This commit is contained in:
Andy Klimczak 2025-10-03 17:20:39 -04:00 committed by GitHub
commit bd7540893f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 121 additions and 14 deletions

View file

@ -803,8 +803,8 @@ object NativeLibrary {
const val DPAD = 780
const val BUTTON_DEBUG = 781
const val BUTTON_GPIO14 = 782
const val BUTTON_TURBO = 783
const val BUTTON_SWAP = 800
const val BUTTON_TURBO = 801
}
/**

View file

@ -20,6 +20,11 @@ class HotkeyUtility(
var HotkeyIsPressed = false
fun handleHotkey(bindedButton: Int): Boolean {
if (bindedButton == NativeLibrary.ButtonType.BUTTON_TURBO) {
TurboHelper.toggleTurbo(true)
HotkeyIsPressed = true
return true
}
if(hotkeyButtons.contains(bindedButton)) {
when (bindedButton) {
Hotkey.SWAP_SCREEN.button -> screenAdjustmentUtil.swapScreen()

View file

@ -121,6 +121,7 @@ class Settings {
const val KEY_BUTTON_SELECT = "button_select"
const val KEY_BUTTON_START = "button_start"
const val KEY_BUTTON_HOME = "button_home"
const val KEY_BUTTON_TURBO = "button_turbo"
const val KEY_BUTTON_UP = "button_up"
const val KEY_BUTTON_DOWN = "button_down"
const val KEY_BUTTON_LEFT = "button_left"
@ -150,7 +151,8 @@ class Settings {
KEY_BUTTON_Y,
KEY_BUTTON_SELECT,
KEY_BUTTON_START,
KEY_BUTTON_HOME
KEY_BUTTON_HOME,
KEY_BUTTON_TURBO
)
val buttonTitles = listOf(
R.string.button_a,
@ -159,7 +161,8 @@ class Settings {
R.string.button_y,
R.string.button_select,
R.string.button_start,
R.string.button_home
R.string.button_home,
R.string.button_turbo
)
val circlePadKeys = listOf(
KEY_CIRCLEPAD_AXIS_VERTICAL,
@ -245,4 +248,4 @@ class Settings {
)
}
}
}
}

View file

@ -123,6 +123,7 @@ class InputBindingSetting(
Settings.KEY_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_SELECT
Settings.KEY_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_START
Settings.KEY_BUTTON_HOME -> NativeLibrary.ButtonType.BUTTON_HOME
Settings.KEY_BUTTON_TURBO -> NativeLibrary.ButtonType.BUTTON_TURBO
Settings.KEY_BUTTON_UP -> NativeLibrary.ButtonType.DPAD_UP
Settings.KEY_BUTTON_DOWN -> NativeLibrary.ButtonType.DPAD_DOWN
Settings.KEY_BUTTON_LEFT -> NativeLibrary.ButtonType.DPAD_LEFT

View file

@ -66,8 +66,9 @@ static const std::array<int, Settings::NativeButton::NumButtons> default_buttons
InputManager::N3DS_TRIGGER_L, InputManager::N3DS_TRIGGER_R,
InputManager::N3DS_BUTTON_START, InputManager::N3DS_BUTTON_SELECT,
InputManager::N3DS_BUTTON_DEBUG, InputManager::N3DS_BUTTON_GPIO14,
InputManager::N3DS_BUTTON_ZL, InputManager::N3DS_BUTTON_ZR,
InputManager::N3DS_BUTTON_HOME,
InputManager::N3DS_BUTTON_TURBO, InputManager::N3DS_BUTTON_ZL,
InputManager::N3DS_BUTTON_ZR, InputManager::N3DS_BUTTON_HOME,
InputManager::N3DS_BUTTON_POWER,
};
static const std::array<int, Settings::NativeAnalog::NumAnalogs> default_analogs{{

View file

@ -40,6 +40,7 @@ button_start=
button_select=
button_debug=
button_gpio14=
button_turbo=
button_zl=
button_zr=
button_home=

View file

@ -39,7 +39,8 @@ enum ButtonType {
N3DS_TRIGGER_L = 773,
N3DS_TRIGGER_R = 774,
N3DS_BUTTON_DEBUG = 781,
N3DS_BUTTON_GPIO14 = 782
N3DS_BUTTON_GPIO14 = 782,
N3DS_BUTTON_TURBO = 783
};
class ButtonList;

View file

@ -494,6 +494,9 @@ void GMainWindow::InitializeWidgets() {
});
InputCommon::Init();
turbo_poll_timer.setInterval(10);
connect(&turbo_poll_timer, &QTimer::timeout, this, &GMainWindow::PollTurboButton);
UpdateTurboButtonBinding(true);
multiplayer_state = new MultiplayerState(system, this, game_list->GetModel(),
ui->action_Leave_Room, ui->action_Show_Room);
multiplayer_state->setVisible(false);
@ -878,6 +881,8 @@ void GMainWindow::InitializeHotkeys() {
const auto fullscreen_hotkey = hotkey_registry.GetKeySequence(main_window, fullscreen);
add_secondary_window_hotkey(action_secondary_fullscreen, fullscreen_hotkey,
SLOT(ToggleSecondaryFullscreen()));
UpdateTurboButtonBinding(true);
}
void GMainWindow::SetDefaultUIGeometry() {
@ -1561,6 +1566,7 @@ void GMainWindow::ShutdownGame() {
UpdateSaveStates();
emulation_running = false;
RefreshTurboPollingState();
game_title.clear();
UpdateWindowTitle();
@ -2446,6 +2452,7 @@ void GMainWindow::OnStartGame() {
UpdateSaveStates();
UpdateStatusButtons();
UpdateTurboButtonBinding();
}
void GMainWindow::OnRestartGame() {
@ -2654,6 +2661,54 @@ void GMainWindow::ReloadTurbo() {
UpdateStatusBar();
}
void GMainWindow::UpdateTurboButtonBinding(bool force) {
const auto& binding =
Settings::values.current_input_profile.buttons[Settings::NativeButton::Turbo];
if (!force && binding == turbo_button_binding) {
RefreshTurboPollingState();
return;
}
turbo_button_binding = binding;
if (!turbo_button_binding.empty()) {
turbo_button_device = Input::CreateDevice<Input::ButtonDevice>(turbo_button_binding);
if (!turbo_button_device) {
LOG_WARNING(Frontend, "Failed to create turbo controller device for binding {}",
turbo_button_binding);
}
} else {
turbo_button_device.reset();
}
RefreshTurboPollingState();
}
void GMainWindow::RefreshTurboPollingState() {
if (emulation_running && turbo_button_device) {
turbo_button_was_pressed = turbo_button_device->GetStatus();
if (!turbo_poll_timer.isActive()) {
turbo_poll_timer.start();
}
} else {
turbo_poll_timer.stop();
turbo_button_was_pressed = false;
}
}
void GMainWindow::PollTurboButton() {
if (!emulation_running || !turbo_button_device) {
return;
}
const bool pressed = turbo_button_device->GetStatus();
if (pressed && !turbo_button_was_pressed) {
SetTurboEnabled(!IsTurboEnabled());
}
turbo_button_was_pressed = pressed;
}
// TODO: This should probably take in something more descriptive than a bool. -OS
void GMainWindow::AdjustSpeedLimit(bool increase) {
const int SPEED_LIMIT_STEP = 5;
@ -2804,6 +2859,8 @@ void GMainWindow::OnConfigure() {
Settings::values.touch_from_button_maps = old_touch_from_button_maps;
Settings::LoadProfile(old_input_profile_index);
}
UpdateTurboButtonBinding(true);
}
void GMainWindow::OnLoadAmiibo() {

View file

@ -6,6 +6,7 @@
#include <array>
#include <memory>
#include <string>
#include <vector>
#ifdef __unix__
#include <QDBusObjectPath>
@ -23,6 +24,7 @@
#include "citra_qt/hotkeys.h"
#include "citra_qt/user_data_migration.h"
#include "core/core.h"
#include "core/frontend/input.h"
#include "core/savestate.h"
#include "video_core/rasterizer_interface.h"
@ -266,6 +268,9 @@ private slots:
bool IsTurboEnabled();
void SetTurboEnabled(bool);
void ReloadTurbo();
void UpdateTurboButtonBinding(bool force = false);
void RefreshTurboPollingState();
void PollTurboButton();
void AdjustSpeedLimit(bool increase);
void UpdateSecondaryWindowVisibility();
void ToggleScreenLayout();
@ -376,6 +381,10 @@ private:
bool auto_paused = false;
bool auto_muted = false;
QTimer mouse_hide_timer;
QTimer turbo_poll_timer;
std::unique_ptr<Input::ButtonDevice> turbo_button_device;
std::string turbo_button_binding;
bool turbo_button_was_pressed = false;
// Movie
bool movie_record_on_start = false;

View file

@ -29,7 +29,7 @@ QtConfig::~QtConfig() {
const std::array<int, Settings::NativeButton::NumButtons> QtConfig::default_buttons = {
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G,
Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N,
Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B, Qt::Key_V,
Qt::Key_O, Qt::Key_P, Qt::Key_unknown, Qt::Key_1, Qt::Key_2, Qt::Key_B, Qt::Key_V,
};
const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{

View file

@ -170,8 +170,8 @@ ConfigureInput::ConfigureInput(Core::System& _system, QWidget* parent)
ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight,
ui->buttonL, ui->buttonR, ui->buttonStart, ui->buttonSelect,
ui->buttonDebug, ui->buttonGpio14, ui->buttonZL, ui->buttonZR,
ui->buttonHome, ui->buttonPower,
ui->buttonDebug, ui->buttonGpio14, ui->buttonTurbo, ui->buttonZL,
ui->buttonZR, ui->buttonHome, ui->buttonPower,
};
analog_map_buttons = {{

View file

@ -470,6 +470,24 @@
</item>
</layout>
</item>
<item row="3" column="1">
<layout class="QVBoxLayout" name="verticalLayout_32">
<item>
<widget class="QLabel" name="label_40">
<property name="text">
<string>Toggle Turbo Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonTurbo">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
@ -1093,6 +1111,7 @@
<tabstop>buttonHome</tabstop>
<tabstop>buttonCircleMod</tabstop>
<tabstop>buttonDebug</tabstop>
<tabstop>buttonTurbo</tabstop>
<tabstop>buttonGpio14</tabstop>
<tabstop>buttonMotionTouch</tabstop>
<tabstop>buttonAutoMap</tabstop>

View file

@ -48,9 +48,11 @@ bool SdlConfig::LoadINI(const std::string& default_contents, bool retry) {
}
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons = {
SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T, SDL_SCANCODE_G,
SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_M, SDL_SCANCODE_N,
SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B,
SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X,
SDL_SCANCODE_T, SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H,
SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_M, SDL_SCANCODE_N,
SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_1,
SDL_SCANCODE_2, SDL_SCANCODE_B, SDL_SCANCODE_V,
};
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs{{

View file

@ -40,6 +40,7 @@ button_start=
button_select=
button_debug=
button_gpio14=
button_turbo=
button_zl=
button_zr=
button_home=

View file

@ -133,6 +133,7 @@ enum Values {
Select,
Debug,
Gpio14,
Turbo,
ZL,
ZR,
@ -170,6 +171,7 @@ static const std::array<const char*, NumButtons> mapping = {{
"button_select",
"button_debug",
"button_gpio14",
"button_turbo",
"button_zl",
"button_zr",
"button_home",

View file

@ -208,6 +208,7 @@ void Module::UpdatePadCallback(std::uintptr_t user_data, s64 cycles_late) {
state.select.Assign(buttons[Select - BUTTON_HID_BEGIN]->GetStatus());
state.debug.Assign(buttons[Debug - BUTTON_HID_BEGIN]->GetStatus());
state.gpio14.Assign(buttons[Gpio14 - BUTTON_HID_BEGIN]->GetStatus());
state.turbo.Assign(buttons[Turbo - BUTTON_HID_BEGIN]->GetStatus());
// Get current circle pad position and update circle pad direction
float circle_pad_x_f, circle_pad_y_f;

View file

@ -52,6 +52,7 @@ struct PadState {
BitField<11, 1, u32> y;
BitField<12, 1, u32> debug;
BitField<13, 1, u32> gpio14;
BitField<14, 1, u32> turbo;
BitField<28, 1, u32> circle_right;
BitField<29, 1, u32> circle_left;

View file

@ -59,7 +59,8 @@ struct ControllerState {
BitField<11, 1, u16> y;
BitField<12, 1, u16> debug;
BitField<13, 1, u16> gpio14;
// Bits 14-15 are currently unused
BitField<14, 1, u16> turbo;
// Bit 15 is currently unused
};
s16_le circle_pad_x;
s16_le circle_pad_y;
@ -261,6 +262,7 @@ void Movie::Play(Service::HID::PadState& pad_state, s16& circle_pad_x, s16& circ
pad_state.y.Assign(s.pad_and_circle.y);
pad_state.debug.Assign(s.pad_and_circle.debug);
pad_state.gpio14.Assign(s.pad_and_circle.gpio14);
pad_state.turbo.Assign(s.pad_and_circle.turbo);
circle_pad_x = s.pad_and_circle.circle_pad_x;
circle_pad_y = s.pad_and_circle.circle_pad_y;
@ -385,6 +387,7 @@ void Movie::Record(const Service::HID::PadState& pad_state, const s16& circle_pa
s.pad_and_circle.y.Assign(static_cast<u16>(pad_state.y));
s.pad_and_circle.debug.Assign(static_cast<u16>(pad_state.debug));
s.pad_and_circle.gpio14.Assign(static_cast<u16>(pad_state.gpio14));
s.pad_and_circle.turbo.Assign(static_cast<u16>(pad_state.turbo));
s.pad_and_circle.circle_pad_x = circle_pad_x;
s.pad_and_circle.circle_pad_y = circle_pad_y;