early-access version 3581
This commit is contained in:
parent
5f158ebb5e
commit
ba2ffe4391
12 changed files with 100 additions and 71 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3580.
|
This is the source code for early-access 3581.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -188,8 +188,6 @@ void AudioRenderer::ThreadFunc() {
|
||||||
max_time = std::min(command_buffer.time_limit, max_time);
|
max_time = std::min(command_buffer.time_limit, max_time);
|
||||||
command_list_processor.SetProcessTimeMax(max_time);
|
command_list_processor.SetProcessTimeMax(max_time);
|
||||||
|
|
||||||
streams[index]->WaitFreeSpace();
|
|
||||||
|
|
||||||
// Process the command list
|
// Process the command list
|
||||||
{
|
{
|
||||||
MICROPROFILE_SCOPE(Audio_Renderer);
|
MICROPROFILE_SCOPE(Audio_Renderer);
|
||||||
|
|
|
@ -15,9 +15,14 @@ MICROPROFILE_DEFINE(Audio_RenderSystemManager, "Audio", "Render System Manager",
|
||||||
MP_RGB(60, 19, 97));
|
MP_RGB(60, 19, 97));
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer {
|
namespace AudioCore::AudioRenderer {
|
||||||
|
constexpr std::chrono::nanoseconds RENDER_TIME{5'000'000UL};
|
||||||
|
|
||||||
SystemManager::SystemManager(Core::System& core_)
|
SystemManager::SystemManager(Core::System& core_)
|
||||||
: core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()} {}
|
: core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()},
|
||||||
|
thread_event{Core::Timing::CreateEvent(
|
||||||
|
"AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
|
||||||
|
return ThreadFunc2(time);
|
||||||
|
})} {}
|
||||||
|
|
||||||
SystemManager::~SystemManager() {
|
SystemManager::~SystemManager() {
|
||||||
Stop();
|
Stop();
|
||||||
|
@ -27,7 +32,9 @@ bool SystemManager::InitializeUnsafe() {
|
||||||
if (!active) {
|
if (!active) {
|
||||||
if (adsp.Start()) {
|
if (adsp.Start()) {
|
||||||
active = true;
|
active = true;
|
||||||
thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); });
|
thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(stop_token); });
|
||||||
|
core.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), RENDER_TIME,
|
||||||
|
thread_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,9 +45,13 @@ void SystemManager::Stop() {
|
||||||
if (!active) {
|
if (!active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
core.CoreTiming().UnscheduleEvent(thread_event, {});
|
||||||
active = false;
|
active = false;
|
||||||
update.store(true);
|
{
|
||||||
update.notify_all();
|
std::scoped_lock l{cv_mutex};
|
||||||
|
do_update = false;
|
||||||
|
}
|
||||||
|
thread.request_stop();
|
||||||
thread.join();
|
thread.join();
|
||||||
adsp.Stop();
|
adsp.Stop();
|
||||||
}
|
}
|
||||||
|
@ -85,12 +96,12 @@ bool SystemManager::Remove(System& system_) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemManager::ThreadFunc() {
|
void SystemManager::ThreadFunc(std::stop_token stop_token) {
|
||||||
static constexpr char name[]{"AudioRenderSystemManager"};
|
static constexpr char name[]{"AudioRenderSystemManager"};
|
||||||
MicroProfileOnThreadCreate(name);
|
MicroProfileOnThreadCreate(name);
|
||||||
Common::SetCurrentThreadName(name);
|
Common::SetCurrentThreadName(name);
|
||||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
|
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
|
||||||
while (active) {
|
while (active && !stop_token.stop_requested()) {
|
||||||
{
|
{
|
||||||
std::scoped_lock l{mutex1};
|
std::scoped_lock l{mutex1};
|
||||||
|
|
||||||
|
@ -103,7 +114,20 @@ void SystemManager::ThreadFunc() {
|
||||||
|
|
||||||
adsp.Signal();
|
adsp.Signal();
|
||||||
adsp.Wait();
|
adsp.Wait();
|
||||||
|
|
||||||
|
std::unique_lock l{cv_mutex};
|
||||||
|
Common::CondvarWait(update_cv, l, stop_token, [this]() { return do_update; });
|
||||||
|
do_update = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::chrono::nanoseconds> SystemManager::ThreadFunc2(s64 time) {
|
||||||
|
{
|
||||||
|
std::scoped_lock l{cv_mutex};
|
||||||
|
do_update = true;
|
||||||
|
}
|
||||||
|
update_cv.notify_all();
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace AudioCore::AudioRenderer
|
} // namespace AudioCore::AudioRenderer
|
||||||
|
|
|
@ -66,13 +66,12 @@ private:
|
||||||
/**
|
/**
|
||||||
* Main thread responsible for command generation.
|
* Main thread responsible for command generation.
|
||||||
*/
|
*/
|
||||||
void ThreadFunc();
|
void ThreadFunc(std::stop_token stop_token);
|
||||||
|
|
||||||
enum class StreamState {
|
/**
|
||||||
Filling,
|
* Signalling core timing thread to run ThreadFunc.
|
||||||
Steady,
|
*/
|
||||||
Draining,
|
std::optional<std::chrono::nanoseconds> ThreadFunc2(s64 time);
|
||||||
};
|
|
||||||
|
|
||||||
/// Core system
|
/// Core system
|
||||||
Core::System& core;
|
Core::System& core;
|
||||||
|
@ -90,8 +89,12 @@ private:
|
||||||
ADSP::ADSP& adsp;
|
ADSP::ADSP& adsp;
|
||||||
/// AudioRenderer mailbox for communication
|
/// AudioRenderer mailbox for communication
|
||||||
ADSP::AudioRenderer_Mailbox* mailbox{};
|
ADSP::AudioRenderer_Mailbox* mailbox{};
|
||||||
|
/// Core timing event to signal main thread
|
||||||
|
std::shared_ptr<Core::Timing::EventType> thread_event;
|
||||||
/// Atomic for main thread to wait on
|
/// Atomic for main thread to wait on
|
||||||
std::atomic<bool> update{};
|
std::mutex cv_mutex{};
|
||||||
|
bool do_update{};
|
||||||
|
std::condition_variable_any update_cv{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AudioCore::AudioRenderer
|
} // namespace AudioCore::AudioRenderer
|
||||||
|
|
|
@ -268,10 +268,4 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
|
||||||
return std::min<u64>(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3;
|
return std::min<u64>(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SinkStream::WaitFreeSpace() {
|
|
||||||
std::unique_lock lk{release_mutex};
|
|
||||||
release_cv.wait(
|
|
||||||
lk, [this]() { return queued_buffers < max_queue_size || system.IsShuttingDown(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace AudioCore::Sink
|
} // namespace AudioCore::Sink
|
||||||
|
|
|
@ -207,11 +207,6 @@ public:
|
||||||
*/
|
*/
|
||||||
u64 GetExpectedPlayedSampleCount();
|
u64 GetExpectedPlayedSampleCount();
|
||||||
|
|
||||||
/**
|
|
||||||
* Waits for free space in the sample ring buffer
|
|
||||||
*/
|
|
||||||
void WaitFreeSpace();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Core system
|
/// Core system
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
|
@ -339,9 +339,7 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
|
||||||
if (ctx.profile.support_vertex_instance_id) {
|
if (ctx.profile.support_vertex_instance_id) {
|
||||||
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_id));
|
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_id));
|
||||||
} else {
|
} else {
|
||||||
const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)};
|
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_index));
|
||||||
const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
|
|
||||||
return ctx.OpBitcast(ctx.F32[1], ctx.OpISub(ctx.U32[1], index, base));
|
|
||||||
}
|
}
|
||||||
case IR::Attribute::BaseInstance:
|
case IR::Attribute::BaseInstance:
|
||||||
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance));
|
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance));
|
||||||
|
@ -386,9 +384,7 @@ Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id) {
|
||||||
if (ctx.profile.support_vertex_instance_id) {
|
if (ctx.profile.support_vertex_instance_id) {
|
||||||
return ctx.OpLoad(ctx.U32[1], ctx.vertex_id);
|
return ctx.OpLoad(ctx.U32[1], ctx.vertex_id);
|
||||||
} else {
|
} else {
|
||||||
const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)};
|
return ctx.OpLoad(ctx.U32[1], ctx.vertex_index);
|
||||||
const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
|
|
||||||
return ctx.OpISub(ctx.U32[1], index, base);
|
|
||||||
}
|
}
|
||||||
case IR::Attribute::BaseInstance:
|
case IR::Attribute::BaseInstance:
|
||||||
return ctx.OpLoad(ctx.U32[1], ctx.base_instance);
|
return ctx.OpLoad(ctx.U32[1], ctx.base_instance);
|
||||||
|
|
|
@ -102,12 +102,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||||
}
|
}
|
||||||
IR::F32 value{v.ir.CompositeExtract(sample, element)};
|
IR::F32 value{v.ir.CompositeExtract(sample, element)};
|
||||||
if (element < 2) {
|
if (element < 2) {
|
||||||
IR::U32 casted_value;
|
IR::U32 casted_value = v.ir.ConvertFToU(32, value);
|
||||||
if (element == 0) {
|
|
||||||
casted_value = v.ir.ConvertFToU(32, value);
|
|
||||||
} else {
|
|
||||||
casted_value = v.ir.ConvertFToS(16, value);
|
|
||||||
}
|
|
||||||
v.X(dest_reg, v.ir.ShiftLeftLogical(casted_value, v.ir.Imm32(8)));
|
v.X(dest_reg, v.ir.ShiftLeftLogical(casted_value, v.ir.Imm32(8)));
|
||||||
} else {
|
} else {
|
||||||
v.F(dest_reg, value);
|
v.F(dest_reg, value);
|
||||||
|
|
|
@ -48,7 +48,9 @@ ConfigureHotkeys::ConfigureHotkeys(Core::HID::HIDCore& hid_core, QWidget* parent
|
||||||
|
|
||||||
connect(poll_timer.get(), &QTimer::timeout, [this] {
|
connect(poll_timer.get(), &QTimer::timeout, [this] {
|
||||||
const auto buttons = controller->GetNpadButtons();
|
const auto buttons = controller->GetNpadButtons();
|
||||||
if (buttons.raw != Core::HID::NpadButton::None) {
|
const auto home_pressed = controller->GetHomeButtons().home != 0;
|
||||||
|
const auto capture_pressed = controller->GetCaptureButtons().capture != 0;
|
||||||
|
if (home_pressed || capture_pressed) {
|
||||||
SetPollingResult(buttons.raw, false);
|
SetPollingResult(buttons.raw, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -154,8 +156,10 @@ void ConfigureHotkeys::ConfigureController(QModelIndex index) {
|
||||||
model->setData(index, previous_key);
|
model->setData(index, previous_key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto home_pressed = this->controller->GetHomeButtons().home != 0;
|
||||||
const QString button_string = tr("Home+%1").arg(GetButtonName(button));
|
const auto capture_pressed = this->controller->GetCaptureButtons().capture != 0;
|
||||||
|
const QString button_string =
|
||||||
|
GetButtonCombinationName(button, home_pressed, capture_pressed);
|
||||||
|
|
||||||
const auto [key_sequence_used, used_action] = IsUsedControllerKey(button_string);
|
const auto [key_sequence_used, used_action] = IsUsedControllerKey(button_string);
|
||||||
|
|
||||||
|
@ -174,72 +178,83 @@ void ConfigureHotkeys::ConfigureController(QModelIndex index) {
|
||||||
poll_timer->start(200); // Check for new inputs every 200ms
|
poll_timer->start(200); // Check for new inputs every 200ms
|
||||||
// We need to disable configuration to be able to read npad buttons
|
// We need to disable configuration to be able to read npad buttons
|
||||||
controller->DisableConfiguration();
|
controller->DisableConfiguration();
|
||||||
controller->DisableSystemButtons();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureHotkeys::SetPollingResult(Core::HID::NpadButton button, const bool cancel) {
|
void ConfigureHotkeys::SetPollingResult(Core::HID::NpadButton button, const bool cancel) {
|
||||||
timeout_timer->stop();
|
timeout_timer->stop();
|
||||||
poll_timer->stop();
|
poll_timer->stop();
|
||||||
|
(*input_setter)(button, cancel);
|
||||||
// Re-Enable configuration
|
// Re-Enable configuration
|
||||||
controller->EnableConfiguration();
|
controller->EnableConfiguration();
|
||||||
controller->EnableSystemButtons();
|
|
||||||
|
|
||||||
(*input_setter)(button, cancel);
|
|
||||||
|
|
||||||
input_setter = std::nullopt;
|
input_setter = std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ConfigureHotkeys::GetButtonName(Core::HID::NpadButton button) const {
|
QString ConfigureHotkeys::GetButtonCombinationName(Core::HID::NpadButton button,
|
||||||
|
const bool home = false,
|
||||||
|
const bool capture = false) const {
|
||||||
Core::HID::NpadButtonState state{button};
|
Core::HID::NpadButtonState state{button};
|
||||||
|
QString button_combination;
|
||||||
|
if (home) {
|
||||||
|
button_combination.append(QStringLiteral("Home+"));
|
||||||
|
}
|
||||||
|
if (capture) {
|
||||||
|
button_combination.append(QStringLiteral("Screenshot+"));
|
||||||
|
}
|
||||||
if (state.a) {
|
if (state.a) {
|
||||||
return QStringLiteral("A");
|
button_combination.append(QStringLiteral("A+"));
|
||||||
}
|
}
|
||||||
if (state.b) {
|
if (state.b) {
|
||||||
return QStringLiteral("B");
|
button_combination.append(QStringLiteral("B+"));
|
||||||
}
|
}
|
||||||
if (state.x) {
|
if (state.x) {
|
||||||
return QStringLiteral("X");
|
button_combination.append(QStringLiteral("X+"));
|
||||||
}
|
}
|
||||||
if (state.y) {
|
if (state.y) {
|
||||||
return QStringLiteral("Y");
|
button_combination.append(QStringLiteral("Y+"));
|
||||||
}
|
}
|
||||||
if (state.l || state.right_sl || state.left_sl) {
|
if (state.l || state.right_sl || state.left_sl) {
|
||||||
return QStringLiteral("L");
|
button_combination.append(QStringLiteral("L+"));
|
||||||
}
|
}
|
||||||
if (state.r || state.right_sr || state.left_sr) {
|
if (state.r || state.right_sr || state.left_sr) {
|
||||||
return QStringLiteral("R");
|
button_combination.append(QStringLiteral("R+"));
|
||||||
}
|
}
|
||||||
if (state.zl) {
|
if (state.zl) {
|
||||||
return QStringLiteral("ZL");
|
button_combination.append(QStringLiteral("ZL+"));
|
||||||
}
|
}
|
||||||
if (state.zr) {
|
if (state.zr) {
|
||||||
return QStringLiteral("ZR");
|
button_combination.append(QStringLiteral("ZR+"));
|
||||||
}
|
}
|
||||||
if (state.left) {
|
if (state.left) {
|
||||||
return QStringLiteral("Dpad_Left");
|
button_combination.append(QStringLiteral("Dpad_Left+"));
|
||||||
}
|
}
|
||||||
if (state.right) {
|
if (state.right) {
|
||||||
return QStringLiteral("Dpad_Right");
|
button_combination.append(QStringLiteral("Dpad_Right+"));
|
||||||
}
|
}
|
||||||
if (state.up) {
|
if (state.up) {
|
||||||
return QStringLiteral("Dpad_Up");
|
button_combination.append(QStringLiteral("Dpad_Up+"));
|
||||||
}
|
}
|
||||||
if (state.down) {
|
if (state.down) {
|
||||||
return QStringLiteral("Dpad_Down");
|
button_combination.append(QStringLiteral("Dpad_Down+"));
|
||||||
}
|
}
|
||||||
if (state.stick_l) {
|
if (state.stick_l) {
|
||||||
return QStringLiteral("Left_Stick");
|
button_combination.append(QStringLiteral("Left_Stick+"));
|
||||||
}
|
}
|
||||||
if (state.stick_r) {
|
if (state.stick_r) {
|
||||||
return QStringLiteral("Right_Stick");
|
button_combination.append(QStringLiteral("Right_Stick+"));
|
||||||
}
|
}
|
||||||
if (state.minus) {
|
if (state.minus) {
|
||||||
return QStringLiteral("Minus");
|
button_combination.append(QStringLiteral("Minus+"));
|
||||||
}
|
}
|
||||||
if (state.plus) {
|
if (state.plus) {
|
||||||
return QStringLiteral("Plus");
|
button_combination.append(QStringLiteral("Plus+"));
|
||||||
}
|
}
|
||||||
|
if (button_combination.isEmpty()) {
|
||||||
return tr("Invalid");
|
return tr("Invalid");
|
||||||
|
} else {
|
||||||
|
button_combination.chop(1);
|
||||||
|
return button_combination;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, QString> ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) const {
|
std::pair<bool, QString> ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) const {
|
||||||
|
|
|
@ -59,7 +59,7 @@ private:
|
||||||
QStandardItemModel* model;
|
QStandardItemModel* model;
|
||||||
|
|
||||||
void SetPollingResult(Core::HID::NpadButton button, bool cancel);
|
void SetPollingResult(Core::HID::NpadButton button, bool cancel);
|
||||||
QString GetButtonName(Core::HID::NpadButton button) const;
|
QString GetButtonCombinationName(Core::HID::NpadButton button, bool home, bool capture) const;
|
||||||
Core::HID::EmulatedController* controller;
|
Core::HID::EmulatedController* controller;
|
||||||
std::unique_ptr<QTimer> timeout_timer;
|
std::unique_ptr<QTimer> timeout_timer;
|
||||||
std::unique_ptr<QTimer> poll_timer;
|
std::unique_ptr<QTimer> poll_timer;
|
||||||
|
|
|
@ -1164,7 +1164,8 @@ void GMainWindow::InitializeRecentFileMenuActions() {
|
||||||
UpdateRecentFiles();
|
UpdateRecentFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name) {
|
void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name,
|
||||||
|
const bool tas_allowed) {
|
||||||
static const QString main_window = QStringLiteral("Main Window");
|
static const QString main_window = QStringLiteral("Main Window");
|
||||||
action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name));
|
action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name));
|
||||||
action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name));
|
action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name));
|
||||||
|
@ -1176,7 +1177,14 @@ void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name
|
||||||
const auto* controller_hotkey =
|
const auto* controller_hotkey =
|
||||||
hotkey_registry.GetControllerHotkey(main_window, action_name, controller);
|
hotkey_registry.GetControllerHotkey(main_window, action_name, controller);
|
||||||
connect(
|
connect(
|
||||||
controller_hotkey, &ControllerShortcut::Activated, this, [action] { action->trigger(); },
|
controller_hotkey, &ControllerShortcut::Activated, this,
|
||||||
|
[action, tas_allowed, this] {
|
||||||
|
auto [tas_status, current_tas_frame, total_tas_frames] =
|
||||||
|
input_subsystem->GetTas()->GetStatus();
|
||||||
|
if (tas_allowed || tas_status == InputCommon::TasInput::TasState::Stopped) {
|
||||||
|
action->trigger();
|
||||||
|
}
|
||||||
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1193,9 +1201,9 @@ void GMainWindow::InitializeHotkeys() {
|
||||||
LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar"));
|
LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar"));
|
||||||
LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen"));
|
LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen"));
|
||||||
LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot"));
|
LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot"));
|
||||||
LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"));
|
LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"), true);
|
||||||
LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"));
|
LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true);
|
||||||
LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"));
|
LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true);
|
||||||
|
|
||||||
static const QString main_window = QStringLiteral("Main Window");
|
static const QString main_window = QStringLiteral("Main Window");
|
||||||
const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) {
|
const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) {
|
||||||
|
|
|
@ -214,7 +214,8 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Updates an action's shortcut and text to reflect an updated hotkey from the hotkey registry.
|
/// Updates an action's shortcut and text to reflect an updated hotkey from the hotkey registry.
|
||||||
void LinkActionShortcut(QAction* action, const QString& action_name);
|
void LinkActionShortcut(QAction* action, const QString& action_name,
|
||||||
|
const bool tas_allowed = false);
|
||||||
|
|
||||||
void RegisterMetaTypes();
|
void RegisterMetaTypes();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue