mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-26 01:30:14 +00:00
commit
f2599a5d8c
@ -23,6 +23,97 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then
|
|||||||
|
|
||||||
# move SDL2 libs into folder for deployment
|
# move SDL2 libs into folder for deployment
|
||||||
dylibbundler -b -x "${REV_NAME}/citra" -cd -d "${REV_NAME}/libs" -p "@executable_path/libs/"
|
dylibbundler -b -x "${REV_NAME}/citra" -cd -d "${REV_NAME}/libs" -p "@executable_path/libs/"
|
||||||
|
|
||||||
|
# Make the changes to make the citra-qt app standalone (i.e. not dependent on the current brew installation).
|
||||||
|
# To do this, the absolute references to each and every QT framework must be re-written to point to the local frameworks
|
||||||
|
# (in the Contents/Frameworks folder).
|
||||||
|
# The "install_name_tool" is used to do so.
|
||||||
|
|
||||||
|
# Coreutils is a hack to coerce Homebrew to point to the absolute Cellar path (symlink dereferenced). i.e:
|
||||||
|
# ls -l /usr/local/opt/qt5:: /usr/local/opt/qt5 -> ../Cellar/qt5/5.6.1-1
|
||||||
|
# grealpath ../Cellar/qt5/5.6.1-1:: /usr/local/Cellar/qt5/5.6.1-1
|
||||||
|
brew install coreutils
|
||||||
|
|
||||||
|
REV_NAME_ALT=$REV_NAME/
|
||||||
|
# grealpath is located in coreutils, there is no "realpath" for OS X :(
|
||||||
|
QT_BREWS_PATH=$(grealpath "$(brew --prefix qt5)")
|
||||||
|
BREW_PATH=$(brew --prefix)
|
||||||
|
QT_VERSION_NUM=5
|
||||||
|
|
||||||
|
$BREW_PATH/opt/qt5/bin/macdeployqt "${REV_NAME_ALT}citra-qt.app" \
|
||||||
|
-executable="${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt"
|
||||||
|
|
||||||
|
# These are the files that macdeployqt packed into Contents/Frameworks/ - we don't want those, so we replace them.
|
||||||
|
declare -a macos_libs=("QtCore" "QtWidgets" "QtGui" "QtOpenGL" "QtPrintSupport")
|
||||||
|
|
||||||
|
for macos_lib in "${macos_libs[@]}"
|
||||||
|
do
|
||||||
|
SC_FRAMEWORK_PART=$macos_lib.framework/Versions/$QT_VERSION_NUM/$macos_lib
|
||||||
|
# Replace macdeployqt versions of the Frameworks with our own (from /usr/local/opt/qt5/lib/)
|
||||||
|
cp "$BREW_PATH/opt/qt5/lib/$SC_FRAMEWORK_PART" "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$SC_FRAMEWORK_PART"
|
||||||
|
|
||||||
|
# Replace references within the embedded Framework files with "internal" versions.
|
||||||
|
for macos_lib2 in "${macos_libs[@]}"
|
||||||
|
do
|
||||||
|
# Since brew references both the non-symlinked and symlink paths of QT5, it needs to be duplicated.
|
||||||
|
# /usr/local/Cellar/qt5/5.6.1-1/lib and /usr/local/opt/qt5/lib both resolve to the same files.
|
||||||
|
# So the two lines below are effectively duplicates when resolved as a path, but as strings, they aren't.
|
||||||
|
RM_FRAMEWORK_PART=$macos_lib2.framework/Versions/$QT_VERSION_NUM/$macos_lib2
|
||||||
|
install_name_tool -change \
|
||||||
|
$QT_BREWS_PATH/lib/$RM_FRAMEWORK_PART \
|
||||||
|
@executable_path/../Frameworks/$RM_FRAMEWORK_PART \
|
||||||
|
"${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$SC_FRAMEWORK_PART"
|
||||||
|
install_name_tool -change \
|
||||||
|
"$BREW_PATH/opt/qt5/lib/$RM_FRAMEWORK_PART" \
|
||||||
|
@executable_path/../Frameworks/$RM_FRAMEWORK_PART \
|
||||||
|
"${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$SC_FRAMEWORK_PART"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# Handles `This application failed to start because it could not find or load the Qt platform plugin "cocoa"`
|
||||||
|
# Which manifests itself as:
|
||||||
|
# "Exception Type: EXC_CRASH (SIGABRT) | Exception Codes: 0x0000000000000000, 0x0000000000000000 | Exception Note: EXC_CORPSE_NOTIFY"
|
||||||
|
# There may be more dylibs needed to be fixed...
|
||||||
|
declare -a macos_plugins=("Plugins/platforms/libqcocoa.dylib")
|
||||||
|
|
||||||
|
for macos_lib in "${macos_plugins[@]}"
|
||||||
|
do
|
||||||
|
install_name_tool -id @executable_path/../$macos_lib "${REV_NAME_ALT}citra-qt.app/Contents/$macos_lib"
|
||||||
|
for macos_lib2 in "${macos_libs[@]}"
|
||||||
|
do
|
||||||
|
RM_FRAMEWORK_PART=$macos_lib2.framework/Versions/$QT_VERSION_NUM/$macos_lib2
|
||||||
|
install_name_tool -change \
|
||||||
|
$QT_BREWS_PATH/lib/$RM_FRAMEWORK_PART \
|
||||||
|
@executable_path/../Frameworks/$RM_FRAMEWORK_PART \
|
||||||
|
"${REV_NAME_ALT}citra-qt.app/Contents/$macos_lib"
|
||||||
|
install_name_tool -change \
|
||||||
|
"$BREW_PATH/opt/qt5/lib/$RM_FRAMEWORK_PART" \
|
||||||
|
@executable_path/../Frameworks/$RM_FRAMEWORK_PART \
|
||||||
|
"${REV_NAME_ALT}citra-qt.app/Contents/$macos_lib"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
for macos_lib in "${macos_libs[@]}"
|
||||||
|
do
|
||||||
|
# Debugging info for Travis-CI
|
||||||
|
otool -L "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$macos_lib.framework/Versions/$QT_VERSION_NUM/$macos_lib"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Make the citra-qt.app application launch a debugging terminal.
|
||||||
|
# Store away the actual binary
|
||||||
|
mv ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt-bin
|
||||||
|
|
||||||
|
cat > ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt <<EOL
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
cd "\`dirname "\$0"\`"
|
||||||
|
chmod +x citra-qt-bin
|
||||||
|
open citra-qt-bin --args "\$@"
|
||||||
|
EOL
|
||||||
|
# Content that will serve as the launching script for citra (within the .app folder)
|
||||||
|
|
||||||
|
# Make the launching script executable
|
||||||
|
chmod +x ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Copy documentation
|
# Copy documentation
|
||||||
|
@ -66,11 +66,6 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
|
|||||||
if (NOT MSVC)
|
if (NOT MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -Wno-attributes")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -Wno-attributes")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.1")
|
|
||||||
endif()
|
|
||||||
else()
|
else()
|
||||||
# Silence "deprecation" warnings
|
# Silence "deprecation" warnings
|
||||||
add_definitions(/D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE /D_SCL_SECURE_NO_WARNINGS)
|
add_definitions(/D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE /D_SCL_SECURE_NO_WARNINGS)
|
||||||
|
9
externals/cmake-modules/FindSDL2.cmake
vendored
9
externals/cmake-modules/FindSDL2.cmake
vendored
@ -3,6 +3,7 @@
|
|||||||
# SDL2_LIBRARY, the name of the library to link against
|
# SDL2_LIBRARY, the name of the library to link against
|
||||||
# SDL2_FOUND, if false, do not try to link to SDL2
|
# SDL2_FOUND, if false, do not try to link to SDL2
|
||||||
# SDL2_INCLUDE_DIR, where to find SDL.h
|
# SDL2_INCLUDE_DIR, where to find SDL.h
|
||||||
|
# SDL2_DLL_DIR, where to find SDL2.dll if it exists
|
||||||
#
|
#
|
||||||
# This module responds to the the flag:
|
# This module responds to the the flag:
|
||||||
# SDL2_BUILDING_LIBRARY
|
# SDL2_BUILDING_LIBRARY
|
||||||
@ -149,6 +150,14 @@ FIND_LIBRARY(SDL2_LIBRARY_TEMP
|
|||||||
)
|
)
|
||||||
|
|
||||||
IF(SDL2_LIBRARY_TEMP)
|
IF(SDL2_LIBRARY_TEMP)
|
||||||
|
if(MSVC)
|
||||||
|
get_filename_component(SDL2_DLL_DIR_TEMP ${SDL2_LIBRARY_TEMP} DIRECTORY)
|
||||||
|
if(EXISTS ${SDL2_DLL_DIR_TEMP}/SDL2.dll)
|
||||||
|
set(SDL2_DLL_DIR ${SDL2_DLL_DIR_TEMP})
|
||||||
|
unset(SDL2_DLL_DIR_TEMP)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
|
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
|
||||||
HINTS
|
HINTS
|
||||||
$ENV{SDL2DIR}
|
$ENV{SDL2DIR}
|
||||||
|
@ -23,6 +23,7 @@ set(SRCS
|
|||||||
configure_dialog.cpp
|
configure_dialog.cpp
|
||||||
configure_general.cpp
|
configure_general.cpp
|
||||||
configure_system.cpp
|
configure_system.cpp
|
||||||
|
configure_input.cpp
|
||||||
game_list.cpp
|
game_list.cpp
|
||||||
hotkeys.cpp
|
hotkeys.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
@ -54,6 +55,7 @@ set(HEADERS
|
|||||||
configure_dialog.h
|
configure_dialog.h
|
||||||
configure_general.h
|
configure_general.h
|
||||||
configure_system.h
|
configure_system.h
|
||||||
|
configure_input.h
|
||||||
game_list.h
|
game_list.h
|
||||||
game_list_p.h
|
game_list_p.h
|
||||||
hotkeys.h
|
hotkeys.h
|
||||||
@ -72,6 +74,7 @@ set(UIS
|
|||||||
configure_debug.ui
|
configure_debug.ui
|
||||||
configure_general.ui
|
configure_general.ui
|
||||||
configure_system.ui
|
configure_system.ui
|
||||||
|
configure_input.ui
|
||||||
hotkeys.ui
|
hotkeys.ui
|
||||||
main.ui
|
main.ui
|
||||||
)
|
)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>English</string>
|
<string>English</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string></string>
|
<string></string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
|
@ -3,14 +3,11 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
#include "citra_qt/config.h"
|
#include "citra_qt/config.h"
|
||||||
#include "citra_qt/ui_settings.h"
|
#include "citra_qt/ui_settings.h"
|
||||||
|
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "core/settings.h"
|
|
||||||
|
|
||||||
Config::Config() {
|
Config::Config() {
|
||||||
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
|
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
|
||||||
@ -21,7 +18,7 @@ Config::Config() {
|
|||||||
Reload();
|
Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = {
|
const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> Config::defaults = {
|
||||||
// directly mapped keys
|
// directly mapped keys
|
||||||
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X,
|
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X,
|
||||||
Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2,
|
Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2,
|
||||||
@ -109,7 +106,7 @@ void Config::ReadValues() {
|
|||||||
UISettings::values.shortcuts.emplace_back(
|
UISettings::values.shortcuts.emplace_back(
|
||||||
UISettings::Shortcut(group + "/" + hotkey,
|
UISettings::Shortcut(group + "/" + hotkey,
|
||||||
UISettings::ContextualShortcut(qt_config->value("KeySeq").toString(),
|
UISettings::ContextualShortcut(qt_config->value("KeySeq").toString(),
|
||||||
qt_config->value("Context").toInt())));
|
qt_config->value("Context").toInt())));
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +188,7 @@ void Config::SaveValues() {
|
|||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
||||||
qt_config->beginGroup("Shortcuts");
|
qt_config->beginGroup("Shortcuts");
|
||||||
for (auto shortcut : UISettings::values.shortcuts ) {
|
for (auto shortcut : UISettings::values.shortcuts) {
|
||||||
qt_config->setValue(shortcut.first + "/KeySeq", shortcut.second.first);
|
qt_config->setValue(shortcut.first + "/KeySeq", shortcut.second.first);
|
||||||
qt_config->setValue(shortcut.first + "/Context", shortcut.second.second);
|
qt_config->setValue(shortcut.first + "/Context", shortcut.second.second);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
// Copyright 2014 Citra Emulator Project
|
// Copyright 2014 Citra Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include "core/settings.h"
|
||||||
|
|
||||||
class QSettings;
|
class QSettings;
|
||||||
|
|
||||||
@ -20,4 +23,5 @@ public:
|
|||||||
|
|
||||||
void Reload();
|
void Reload();
|
||||||
void Save();
|
void Save();
|
||||||
|
static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults;
|
||||||
};
|
};
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<string>System</string>
|
<string>System</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="inputTab">
|
<widget class="ConfigureInput" name="inputTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Input</string>
|
<string>Input</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
@ -80,6 +80,12 @@
|
|||||||
<header>configure_debug.h</header>
|
<header>configure_debug.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>ConfigureInput</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>configure_input.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -30,6 +30,7 @@ void ConfigureDialog::setConfiguration() {
|
|||||||
void ConfigureDialog::applyConfiguration() {
|
void ConfigureDialog::applyConfiguration() {
|
||||||
ui->generalTab->applyConfiguration();
|
ui->generalTab->applyConfiguration();
|
||||||
ui->systemTab->applyConfiguration();
|
ui->systemTab->applyConfiguration();
|
||||||
|
ui->inputTab->applyConfiguration();
|
||||||
ui->audioTab->applyConfiguration();
|
ui->audioTab->applyConfiguration();
|
||||||
ui->debugTab->applyConfiguration();
|
ui->debugTab->applyConfiguration();
|
||||||
}
|
}
|
||||||
|
149
src/citra_qt/configure_input.cpp
Normal file
149
src/citra_qt/configure_input.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// Copyright 2016 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "citra_qt/configure_input.h"
|
||||||
|
|
||||||
|
ConfigureInput::ConfigureInput(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
// Initialize mapping of input enum to UI button.
|
||||||
|
input_mapping = {
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::A, ui->buttonA) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::B, ui->buttonB) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::X, ui->buttonX) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::Y, ui->buttonY) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::L, ui->buttonL) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::R, ui->buttonR) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::ZL, ui->buttonZL) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::ZR, ui->buttonZR) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::START, ui->buttonStart) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::SELECT, ui->buttonSelect) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::HOME, ui->buttonHome) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::DUP, ui->buttonDpadUp) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::DDOWN, ui->buttonDpadDown) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::DLEFT, ui->buttonDpadLeft) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::DRIGHT, ui->buttonDpadRight) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::CUP, ui->buttonCStickUp) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::CDOWN, ui->buttonCStickDown) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::CLEFT, ui->buttonCStickLeft) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::CRIGHT, ui->buttonCStickRight) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::CIRCLE_UP, ui->buttonCircleUp) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::CIRCLE_DOWN, ui->buttonCircleDown) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::CIRCLE_LEFT, ui->buttonCircleLeft) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::CIRCLE_RIGHT, ui->buttonCircleRight) },
|
||||||
|
{ std::make_pair(Settings::NativeInput::Values::CIRCLE_MODIFIER, ui->buttonCircleMod) },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attach handle click method to each button click.
|
||||||
|
for (const auto& entry : input_mapping) {
|
||||||
|
connect(entry.second, SIGNAL(released()), this, SLOT(handleClick()));
|
||||||
|
}
|
||||||
|
connect(ui->buttonRestoreDefaults, SIGNAL(released()), this, SLOT(restoreDefaults()));
|
||||||
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
|
timer = new QTimer(this);
|
||||||
|
timer->setSingleShot(true);
|
||||||
|
connect(timer, &QTimer::timeout, this, [&]() { key_pressed = Qt::Key_Escape; setKey(); });
|
||||||
|
this->setConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInput::handleClick() {
|
||||||
|
QPushButton* sender = qobject_cast<QPushButton*>(QObject::sender());
|
||||||
|
previous_mapping = sender->text();
|
||||||
|
sender->setText(tr("[waiting]"));
|
||||||
|
sender->setFocus();
|
||||||
|
grabKeyboard();
|
||||||
|
grabMouse();
|
||||||
|
changing_button = sender;
|
||||||
|
timer->start(5000); //Cancel after 5 seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInput::applyConfiguration() {
|
||||||
|
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||||
|
int value = getKeyValue(input_mapping[Settings::NativeInput::Values(i)]->text());
|
||||||
|
Settings::values.input_mappings[Settings::NativeInput::All[i]] = value;
|
||||||
|
}
|
||||||
|
Settings::Apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInput::setConfiguration() {
|
||||||
|
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||||
|
QString keyValue = getKeyName(Settings::values.input_mappings[i]);
|
||||||
|
input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInput::keyPressEvent(QKeyEvent* event) {
|
||||||
|
if (!changing_button)
|
||||||
|
return;
|
||||||
|
if (!event || event->key() == Qt::Key_unknown)
|
||||||
|
return;
|
||||||
|
key_pressed = event->key();
|
||||||
|
timer->stop();
|
||||||
|
setKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInput::setKey() {
|
||||||
|
const QString key_value = getKeyName(key_pressed);
|
||||||
|
if (key_pressed == Qt::Key_Escape)
|
||||||
|
changing_button->setText(previous_mapping);
|
||||||
|
else
|
||||||
|
changing_button->setText(key_value);
|
||||||
|
removeDuplicates(key_value);
|
||||||
|
key_pressed = Qt::Key_unknown;
|
||||||
|
releaseKeyboard();
|
||||||
|
releaseMouse();
|
||||||
|
changing_button = nullptr;
|
||||||
|
previous_mapping = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConfigureInput::getKeyName(int key_code) const {
|
||||||
|
if (key_code == Qt::Key_Shift)
|
||||||
|
return tr("Shift");
|
||||||
|
if (key_code == Qt::Key_Control)
|
||||||
|
return tr("Ctrl");
|
||||||
|
if (key_code == Qt::Key_Alt)
|
||||||
|
return tr("Alt");
|
||||||
|
if (key_code == Qt::Key_Meta)
|
||||||
|
return "";
|
||||||
|
if (key_code == -1)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return QKeySequence(key_code).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::Key ConfigureInput::getKeyValue(const QString& text) const {
|
||||||
|
if (text == "Shift")
|
||||||
|
return Qt::Key_Shift;
|
||||||
|
if (text == "Ctrl")
|
||||||
|
return Qt::Key_Control;
|
||||||
|
if (text == "Alt")
|
||||||
|
return Qt::Key_Alt;
|
||||||
|
if (text == "Meta")
|
||||||
|
return Qt::Key_unknown;
|
||||||
|
if (text == "")
|
||||||
|
return Qt::Key_unknown;
|
||||||
|
|
||||||
|
return Qt::Key(QKeySequence(text)[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInput::removeDuplicates(const QString& newValue) {
|
||||||
|
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||||
|
if (changing_button != input_mapping[Settings::NativeInput::Values(i)]) {
|
||||||
|
const QString oldValue = input_mapping[Settings::NativeInput::Values(i)]->text();
|
||||||
|
if (newValue == oldValue)
|
||||||
|
input_mapping[Settings::NativeInput::Values(i)]->setText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInput::restoreDefaults() {
|
||||||
|
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||||
|
const QString keyValue = getKeyName(Config::defaults[i].toInt());
|
||||||
|
input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue);
|
||||||
|
}
|
||||||
|
}
|
63
src/citra_qt/configure_input.h
Normal file
63
src/citra_qt/configure_input.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2016 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
#include "citra_qt/config.h"
|
||||||
|
#include "core/settings.h"
|
||||||
|
#include "ui_configure_input.h"
|
||||||
|
|
||||||
|
class QPushButton;
|
||||||
|
class QString;
|
||||||
|
class QTimer;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ConfigureInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigureInput : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ConfigureInput(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
/// Save all button configurations to settings file
|
||||||
|
void applyConfiguration();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Ui::ConfigureInput> ui;
|
||||||
|
std::map<Settings::NativeInput::Values, QPushButton*> input_mapping;
|
||||||
|
int key_pressed;
|
||||||
|
QPushButton* changing_button = nullptr; ///< button currently waiting for key press.
|
||||||
|
QString previous_mapping;
|
||||||
|
QTimer* timer;
|
||||||
|
|
||||||
|
/// Load configuration settings into button text
|
||||||
|
void setConfiguration();
|
||||||
|
|
||||||
|
/// Check all inputs for duplicate keys. Clears out any other button with the same value as this button's new value.
|
||||||
|
void removeDuplicates(const QString& newValue);
|
||||||
|
|
||||||
|
/// Handle key press event for input tab when a button is 'waiting'.
|
||||||
|
void keyPressEvent(QKeyEvent* event) override;
|
||||||
|
|
||||||
|
/// Convert key ASCII value to its' letter/name
|
||||||
|
QString getKeyName(int key_code) const;
|
||||||
|
|
||||||
|
/// Convert letter/name of key to its ASCII value.
|
||||||
|
Qt::Key getKeyValue(const QString& text) const;
|
||||||
|
|
||||||
|
/// Set button text to name of key pressed.
|
||||||
|
void setKey();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
/// Event handler for all button released() event.
|
||||||
|
void handleClick();
|
||||||
|
|
||||||
|
/// Restore all buttons to their default values.
|
||||||
|
void restoreDefaults();
|
||||||
|
};
|
593
src/citra_qt/configure_input.ui
Normal file
593
src/citra_qt/configure_input.ui
Normal file
@ -0,0 +1,593 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ConfigureInput</class>
|
||||||
|
<widget class="QWidget" name="ConfigureInput">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>370</width>
|
||||||
|
<height>534</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>ConfigureInput</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_7">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QGroupBox" name="faceButtons">
|
||||||
|
<property name="title">
|
||||||
|
<string>Face Buttons</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>A:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonA">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>B:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonB">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>X:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonX">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Y:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonY">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QGroupBox" name="faceButtons_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>Directional Pad</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_34">
|
||||||
|
<property name="text">
|
||||||
|
<string>Up:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonDpadUp">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_35">
|
||||||
|
<property name="text">
|
||||||
|
<string>Down:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonDpadDown">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_32">
|
||||||
|
<property name="text">
|
||||||
|
<string>Left:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonDpadLeft">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_11">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_33">
|
||||||
|
<property name="text">
|
||||||
|
<string>Right:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonDpadRight">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QGroupBox" name="faceButtons_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>Shoulder Buttons</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_17">
|
||||||
|
<property name="text">
|
||||||
|
<string>L:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonL">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_19">
|
||||||
|
<property name="text">
|
||||||
|
<string>R:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonR">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_15">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_20">
|
||||||
|
<property name="text">
|
||||||
|
<string>ZL:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonZL">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_18">
|
||||||
|
<property name="text">
|
||||||
|
<string>ZR:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonZR">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
<zorder></zorder>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QGroupBox" name="faceButtons_4">
|
||||||
|
<property name="title">
|
||||||
|
<string>Circle Pad</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_17">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_21">
|
||||||
|
<property name="text">
|
||||||
|
<string>Left:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCircleLeft">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_18">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_23">
|
||||||
|
<property name="text">
|
||||||
|
<string>Right:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCircleRight">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_24">
|
||||||
|
<property name="text">
|
||||||
|
<string>Up:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCircleUp">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_20">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_22">
|
||||||
|
<property name="text">
|
||||||
|
<string>Down:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCircleDown">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QGroupBox" name="faceButtons_5">
|
||||||
|
<property name="title">
|
||||||
|
<string>C-Stick</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_21">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_25">
|
||||||
|
<property name="text">
|
||||||
|
<string>Left:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCStickLeft">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_22">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_27">
|
||||||
|
<property name="text">
|
||||||
|
<string>Right:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCStickRight">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_23">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_28">
|
||||||
|
<property name="text">
|
||||||
|
<string>Up:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCStickUp">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_24">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_26">
|
||||||
|
<property name="text">
|
||||||
|
<string>Down:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCStickDown">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QGroupBox" name="faceButtons_6">
|
||||||
|
<property name="title">
|
||||||
|
<string>Misc.</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_6">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_25">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_29">
|
||||||
|
<property name="text">
|
||||||
|
<string>Start:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonStart">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_26">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_30">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonSelect">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_27">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_31">
|
||||||
|
<property name="text">
|
||||||
|
<string>Home:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonHome">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_28">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_34">
|
||||||
|
<property name="text">
|
||||||
|
<string>Circle Mod:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCircleMod">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonRestoreDefaults">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="sizeIncrement">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="baseSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::LeftToRight</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Restore Defaults</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -513,6 +513,7 @@ void GMainWindow::OnConfigure() {
|
|||||||
if (result == QDialog::Accepted)
|
if (result == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
configureDialog.applyConfiguration();
|
configureDialog.applyConfiguration();
|
||||||
|
render_window->ReloadSetKeymaps();
|
||||||
config->Save();
|
config->Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,6 @@ static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsi
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
|
std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
|
||||||
|
|
||||||
new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
|
new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
|
||||||
new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
|
new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
|
||||||
|
|
||||||
@ -92,9 +91,9 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) {
|
EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) {
|
||||||
|
// When hiding the widget, the function receives a size of 0
|
||||||
ASSERT(width > 0);
|
if (width == 0) width = 1;
|
||||||
ASSERT(height > 0);
|
if (height == 0) height = 1;
|
||||||
|
|
||||||
EmuWindow::FramebufferLayout res = { width, height, {}, {} };
|
EmuWindow::FramebufferLayout res = { width, height, {}, {} };
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
// We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding
|
// We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding
|
||||||
// ARM instruction, and using the existing ARM simulator.
|
// ARM instruction, and using the existing ARM simulator.
|
||||||
|
|
||||||
@ -293,15 +295,22 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||||||
| (BIT(tinstr, 4) << 18); // enable bit
|
| (BIT(tinstr, 4) << 18); // enable bit
|
||||||
}
|
}
|
||||||
} else if ((tinstr & 0x0F00) == 0x0a00) {
|
} else if ((tinstr & 0x0F00) == 0x0a00) {
|
||||||
static const u32 subset[3] = {
|
static const u32 subset[4] = {
|
||||||
0xE6BF0F30, // REV
|
0xE6BF0F30, // REV
|
||||||
0xE6BF0FB0, // REV16
|
0xE6BF0FB0, // REV16
|
||||||
|
0, // undefined
|
||||||
0xE6FF0FB0, // REVSH
|
0xE6FF0FB0, // REVSH
|
||||||
};
|
};
|
||||||
|
|
||||||
*ainstr = subset[BITS(tinstr, 6, 7)] // base
|
size_t subset_index = BITS(tinstr, 6, 7);
|
||||||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
|
||||||
| BITS(tinstr, 3, 5); // Rm
|
if (subset_index == 2) {
|
||||||
|
valid = ThumbDecodeStatus::UNDEFINED;
|
||||||
|
} else {
|
||||||
|
*ainstr = subset[subset_index] // base
|
||||||
|
| (BITS(tinstr, 0, 2) << 12) // Rd
|
||||||
|
| BITS(tinstr, 3, 5); // Rm
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
static const u32 subset[4] = {
|
static const u32 subset[4] = {
|
||||||
0xE92D0000, // STMDB sp!,{rlist}
|
0xE92D0000, // STMDB sp!,{rlist}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
extern int g_clock_rate_arm11;
|
extern int g_clock_rate_arm11;
|
||||||
|
|
||||||
inline s64 msToCycles(int ms) {
|
inline s64 msToCycles(int ms) {
|
||||||
return g_clock_rate_arm11 / 1000 * ms;
|
return (s64)g_clock_rate_arm11 / 1000 * ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 msToCycles(float ms) {
|
inline s64 msToCycles(float ms) {
|
||||||
|
@ -37,6 +37,8 @@ static u32 cpu_percent; ///< CPU time available to the running application
|
|||||||
// APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode
|
// APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode
|
||||||
static u8 unknown_ns_state_field;
|
static u8 unknown_ns_state_field;
|
||||||
|
|
||||||
|
static ScreencapPostPermission screen_capture_post_permission;
|
||||||
|
|
||||||
/// Parameter data to be returned in the next call to Glance/ReceiveParameter
|
/// Parameter data to be returned in the next call to Glance/ReceiveParameter
|
||||||
static MessageParameter next_parameter;
|
static MessageParameter next_parameter;
|
||||||
|
|
||||||
@ -70,6 +72,13 @@ void Initialize(Service::Interface* self) {
|
|||||||
void GetSharedFont(Service::Interface* self) {
|
void GetSharedFont(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
|
|
||||||
|
if (!shared_font_mem) {
|
||||||
|
LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds");
|
||||||
|
cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
|
||||||
|
cmd_buff[1] = -1; // TODO: Find the right error code
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The shared font has to be relocated to the new address before being passed to the application.
|
// The shared font has to be relocated to the new address before being passed to the application.
|
||||||
VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
|
VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
|
||||||
// The shared font dumped by 3dsutils (https://github.com/citra-emu/3dsutils) uses this address as base,
|
// The shared font dumped by 3dsutils (https://github.com/citra-emu/3dsutils) uses this address as base,
|
||||||
@ -382,23 +391,23 @@ void StartLibraryApplet(Service::Interface* self) {
|
|||||||
cmd_buff[1] = applet->Start(parameter).raw;
|
cmd_buff[1] = applet->Start(parameter).raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNSStateField(Service::Interface* self) {
|
void SetScreenCapPostPermission(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
|
|
||||||
unknown_ns_state_field = cmd_buff[1];
|
screen_capture_post_permission = static_cast<ScreencapPostPermission>(cmd_buff[1] & 0xF);
|
||||||
|
|
||||||
cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0);
|
cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0);
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||||
LOG_WARNING(Service_APT, "(STUBBED) unknown_ns_state_field=%u", unknown_ns_state_field);
|
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetNSStateField(Service::Interface* self) {
|
void GetScreenCapPostPermission(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
|
|
||||||
cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0);
|
cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0);
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||||
cmd_buff[8] = unknown_ns_state_field;
|
cmd_buff[2] = static_cast<u32>(screen_capture_post_permission);
|
||||||
LOG_WARNING(Service_APT, "(STUBBED) unknown_ns_state_field=%u", unknown_ns_state_field);
|
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetAppletInfo(Service::Interface* self) {
|
void GetAppletInfo(Service::Interface* self) {
|
||||||
@ -493,6 +502,7 @@ void Init() {
|
|||||||
|
|
||||||
cpu_percent = 0;
|
cpu_percent = 0;
|
||||||
unknown_ns_state_field = 0;
|
unknown_ns_state_field = 0;
|
||||||
|
screen_capture_post_permission = ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
|
||||||
|
|
||||||
// TODO(bunnei): Check if these are created in Initialize or on APT process startup.
|
// TODO(bunnei): Check if these are created in Initialize or on APT process startup.
|
||||||
notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification");
|
notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification");
|
||||||
|
@ -94,6 +94,13 @@ enum class StartupArgumentType : u32 {
|
|||||||
OtherMedia = 2,
|
OtherMedia = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ScreencapPostPermission : u32 {
|
||||||
|
CleanThePermission = 0, //TODO(JamePeng): verify what "zero" means
|
||||||
|
NoExplicitSetting = 1,
|
||||||
|
EnableScreenshotPostingToMiiverse = 2,
|
||||||
|
DisableScreenshotPostingToMiiverse = 3
|
||||||
|
};
|
||||||
|
|
||||||
/// Send a parameter to the currently-running application, which will read it via ReceiveParameter
|
/// Send a parameter to the currently-running application, which will read it via ReceiveParameter
|
||||||
void SendParameter(const MessageParameter& parameter);
|
void SendParameter(const MessageParameter& parameter);
|
||||||
|
|
||||||
@ -383,25 +390,24 @@ void StartLibraryApplet(Service::Interface* self);
|
|||||||
void GetStartupArgument(Service::Interface* self);
|
void GetStartupArgument(Service::Interface* self);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APT::SetNSStateField service function
|
* APT::SetScreenCapPostPermission service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 1 : u8 NS state field
|
* 0 : Header Code[0x00550040]
|
||||||
|
* 1 : u8 The screenshot posting permission
|
||||||
* Outputs:
|
* Outputs:
|
||||||
* 1 : Result of function, 0 on success, otherwise error code
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
* Note:
|
|
||||||
* This writes the input u8 to a NS state field.
|
|
||||||
*/
|
*/
|
||||||
void SetNSStateField(Service::Interface* self);
|
void SetScreenCapPostPermission(Service::Interface* self);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APT::GetNSStateField service function
|
* APT::GetScreenCapPostPermission service function
|
||||||
|
* Inputs:
|
||||||
|
* 0 : Header Code[0x00560000]
|
||||||
* Outputs:
|
* Outputs:
|
||||||
* 1 : Result of function, 0 on success, otherwise error code
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
* 8 : u8 NS state field
|
* 2 : u8 The screenshot posting permission
|
||||||
* Note:
|
|
||||||
* This returns a u8 NS state field(which can be set by cmd 0x00550040), at cmdreply+8.
|
|
||||||
*/
|
*/
|
||||||
void GetNSStateField(Service::Interface* self);
|
void GetScreenCapPostPermission(Service::Interface* self);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APT::CheckNew3DSApp service function
|
* APT::CheckNew3DSApp service function
|
||||||
|
@ -33,8 +33,8 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||||
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||||
{0x00550040, SetNSStateField, "SetNSStateField?"},
|
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||||
{0x00560000, GetNSStateField, "GetNSStateField?"},
|
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
||||||
};
|
};
|
||||||
|
@ -92,8 +92,8 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||||
{0x00520104, nullptr, "Wrap1"},
|
{0x00520104, nullptr, "Wrap1"},
|
||||||
{0x00530104, nullptr, "Unwrap1"},
|
{0x00530104, nullptr, "Unwrap1"},
|
||||||
{0x00550040, SetNSStateField, "SetNSStateField?" },
|
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||||
{0x00560000, GetNSStateField, "GetNSStateField?" },
|
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||||
{0x00580002, nullptr, "GetProgramID"},
|
{0x00580002, nullptr, "GetProgramID"},
|
||||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
||||||
|
@ -92,8 +92,8 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||||
{0x00520104, nullptr, "Wrap1"},
|
{0x00520104, nullptr, "Wrap1"},
|
||||||
{0x00530104, nullptr, "Unwrap1"},
|
{0x00530104, nullptr, "Unwrap1"},
|
||||||
{0x00550040, SetNSStateField, "SetNSStateField?"},
|
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||||
{0x00560000, GetNSStateField, "GetNSStateField?"},
|
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||||
{0x00580002, nullptr, "GetProgramID"},
|
{0x00580002, nullptr, "GetProgramID"},
|
||||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
||||||
|
@ -2,8 +2,11 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/shared_page.h"
|
#include "core/hle/shared_page.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -12,6 +15,57 @@ namespace SharedPage {
|
|||||||
|
|
||||||
SharedPageDef shared_page;
|
SharedPageDef shared_page;
|
||||||
|
|
||||||
|
static int update_time_event;
|
||||||
|
|
||||||
|
/// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond.
|
||||||
|
static u64 GetSystemTime() {
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
// 3DS system does't allow user to set a time before Jan 1 2000,
|
||||||
|
// so we use it as an auxiliary epoch to calculate the console time.
|
||||||
|
std::tm epoch_tm;
|
||||||
|
epoch_tm.tm_sec = 0;
|
||||||
|
epoch_tm.tm_min = 0;
|
||||||
|
epoch_tm.tm_hour = 0;
|
||||||
|
epoch_tm.tm_mday = 1;
|
||||||
|
epoch_tm.tm_mon = 0;
|
||||||
|
epoch_tm.tm_year = 100;
|
||||||
|
epoch_tm.tm_isdst = 0;
|
||||||
|
auto epoch = std::chrono::system_clock::from_time_t(std::mktime(&epoch_tm));
|
||||||
|
|
||||||
|
// 3DS console time uses Jan 1 1900 as internal epoch,
|
||||||
|
// so we use the milliseconds between 1900 and 2000 as base console time
|
||||||
|
u64 console_time = 3155673600000ULL;
|
||||||
|
|
||||||
|
// Only when system time is after 2000, we set it as 3DS system time
|
||||||
|
if (now > epoch) {
|
||||||
|
console_time += std::chrono::duration_cast<std::chrono::milliseconds>(now - epoch).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the system time is in daylight saving, we give an additional hour to console time
|
||||||
|
std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
|
||||||
|
std::tm* now_tm = std::localtime(&now_time_t);
|
||||||
|
if (now_tm && now_tm->tm_isdst > 0)
|
||||||
|
console_time += 60 * 60 * 1000;
|
||||||
|
|
||||||
|
return console_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UpdateTimeCallback(u64 userdata, int cycles_late) {
|
||||||
|
DateTime& date_time = shared_page.date_time_counter % 2 ?
|
||||||
|
shared_page.date_time_0 : shared_page.date_time_1;
|
||||||
|
|
||||||
|
date_time.date_time = GetSystemTime();
|
||||||
|
date_time.update_tick = CoreTiming::GetTicks();
|
||||||
|
date_time.tick_to_second_coefficient = g_clock_rate_arm11;
|
||||||
|
date_time.tick_offset = 0;
|
||||||
|
|
||||||
|
++shared_page.date_time_counter;
|
||||||
|
|
||||||
|
// system time is updated hourly
|
||||||
|
CoreTiming::ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late, update_time_event);
|
||||||
|
}
|
||||||
|
|
||||||
void Init() {
|
void Init() {
|
||||||
std::memset(&shared_page, 0, sizeof(shared_page));
|
std::memset(&shared_page, 0, sizeof(shared_page));
|
||||||
|
|
||||||
@ -19,6 +73,9 @@ void Init() {
|
|||||||
|
|
||||||
// Some games wait until this value becomes 0x1, before asking running_hw
|
// Some games wait until this value becomes 0x1, before asking running_hw
|
||||||
shared_page.unknown_value = 0x1;
|
shared_page.unknown_value = 0x1;
|
||||||
|
|
||||||
|
update_time_event = CoreTiming::RegisterEvent("SharedPage::UpdateTimeCallback", UpdateTimeCallback);
|
||||||
|
CoreTiming::ScheduleEvent(0, update_time_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -25,13 +25,14 @@ namespace SharedPage {
|
|||||||
struct DateTime {
|
struct DateTime {
|
||||||
u64_le date_time; // 0
|
u64_le date_time; // 0
|
||||||
u64_le update_tick; // 8
|
u64_le update_tick; // 8
|
||||||
INSERT_PADDING_BYTES(0x20 - 0x10); // 10
|
u64_le tick_to_second_coefficient; // 10
|
||||||
|
u64_le tick_offset; // 18
|
||||||
};
|
};
|
||||||
static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong");
|
static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong");
|
||||||
|
|
||||||
struct SharedPageDef {
|
struct SharedPageDef {
|
||||||
// Most of these names are taken from the 3dbrew page linked above.
|
// Most of these names are taken from the 3dbrew page linked above.
|
||||||
u32_le date_time_selector; // 0
|
u32_le date_time_counter; // 0
|
||||||
u8 running_hw; // 4
|
u8 running_hw; // 4
|
||||||
/// "Microcontroller hardware info"
|
/// "Microcontroller hardware info"
|
||||||
u8 mcu_hw_info; // 5
|
u8 mcu_hw_info; // 5
|
||||||
|
Loading…
Reference in New Issue
Block a user