mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 23:30:13 +00:00
commit
f2599a5d8c
@ -23,6 +23,97 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then
|
||||
|
||||
# move SDL2 libs into folder for deployment
|
||||
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
|
||||
|
||||
# Copy documentation
|
||||
|
@ -66,11 +66,6 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
|
||||
if (NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -Wno-attributes")
|
||||
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()
|
||||
# Silence "deprecation" 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_FOUND, if false, do not try to link to SDL2
|
||||
# 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:
|
||||
# SDL2_BUILDING_LIBRARY
|
||||
@ -149,6 +150,14 @@ FIND_LIBRARY(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
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
|
@ -23,6 +23,7 @@ set(SRCS
|
||||
configure_dialog.cpp
|
||||
configure_general.cpp
|
||||
configure_system.cpp
|
||||
configure_input.cpp
|
||||
game_list.cpp
|
||||
hotkeys.cpp
|
||||
main.cpp
|
||||
@ -54,6 +55,7 @@ set(HEADERS
|
||||
configure_dialog.h
|
||||
configure_general.h
|
||||
configure_system.h
|
||||
configure_input.h
|
||||
game_list.h
|
||||
game_list_p.h
|
||||
hotkeys.h
|
||||
@ -72,6 +74,7 @@ set(UIS
|
||||
configure_debug.ui
|
||||
configure_general.ui
|
||||
configure_system.ui
|
||||
configure_input.ui
|
||||
hotkeys.ui
|
||||
main.ui
|
||||
)
|
||||
|
@ -5,7 +5,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleIconFile</key>
|
||||
|
@ -3,14 +3,11 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "citra_qt/config.h"
|
||||
#include "citra_qt/ui_settings.h"
|
||||
|
||||
#include "common/file_util.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
Config::Config() {
|
||||
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
|
||||
@ -21,7 +18,7 @@ Config::Config() {
|
||||
Reload();
|
||||
}
|
||||
|
||||
static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = {
|
||||
const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> Config::defaults = {
|
||||
// directly mapped keys
|
||||
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X,
|
||||
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::Shortcut(group + "/" + hotkey,
|
||||
UISettings::ContextualShortcut(qt_config->value("KeySeq").toString(),
|
||||
qt_config->value("Context").toInt())));
|
||||
qt_config->value("Context").toInt())));
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
||||
@ -191,7 +188,7 @@ void Config::SaveValues() {
|
||||
qt_config->endGroup();
|
||||
|
||||
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 + "/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
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <QVariant>
|
||||
|
||||
#include "core/settings.h"
|
||||
|
||||
class QSettings;
|
||||
|
||||
@ -20,4 +23,5 @@ public:
|
||||
|
||||
void Reload();
|
||||
void Save();
|
||||
static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults;
|
||||
};
|
||||
|
@ -29,7 +29,7 @@
|
||||
<string>System</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="inputTab">
|
||||
<widget class="ConfigureInput" name="inputTab">
|
||||
<attribute name="title">
|
||||
<string>Input</string>
|
||||
</attribute>
|
||||
@ -80,6 +80,12 @@
|
||||
<header>configure_debug.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConfigureInput</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>configure_input.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
|
@ -30,6 +30,7 @@ void ConfigureDialog::setConfiguration() {
|
||||
void ConfigureDialog::applyConfiguration() {
|
||||
ui->generalTab->applyConfiguration();
|
||||
ui->systemTab->applyConfiguration();
|
||||
ui->inputTab->applyConfiguration();
|
||||
ui->audioTab->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)
|
||||
{
|
||||
configureDialog.applyConfiguration();
|
||||
render_window->ReloadSetKeymaps();
|
||||
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) {
|
||||
|
||||
new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
|
||||
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) {
|
||||
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
// When hiding the widget, the function receives a size of 0
|
||||
if (width == 0) width = 1;
|
||||
if (height == 0) height = 1;
|
||||
|
||||
EmuWindow::FramebufferLayout res = { width, height, {}, {} };
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
// We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding
|
||||
// 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
|
||||
}
|
||||
} else if ((tinstr & 0x0F00) == 0x0a00) {
|
||||
static const u32 subset[3] = {
|
||||
static const u32 subset[4] = {
|
||||
0xE6BF0F30, // REV
|
||||
0xE6BF0FB0, // REV16
|
||||
0, // undefined
|
||||
0xE6FF0FB0, // REVSH
|
||||
};
|
||||
|
||||
*ainstr = subset[BITS(tinstr, 6, 7)] // base
|
||||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
||||
| BITS(tinstr, 3, 5); // Rm
|
||||
size_t subset_index = BITS(tinstr, 6, 7);
|
||||
|
||||
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 {
|
||||
static const u32 subset[4] = {
|
||||
0xE92D0000, // STMDB sp!,{rlist}
|
||||
|
@ -26,7 +26,7 @@
|
||||
extern int g_clock_rate_arm11;
|
||||
|
||||
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) {
|
||||
|
@ -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
|
||||
static u8 unknown_ns_state_field;
|
||||
|
||||
static ScreencapPostPermission screen_capture_post_permission;
|
||||
|
||||
/// Parameter data to be returned in the next call to Glance/ReceiveParameter
|
||||
static MessageParameter next_parameter;
|
||||
|
||||
@ -70,6 +72,13 @@ void Initialize(Service::Interface* self) {
|
||||
void GetSharedFont(Service::Interface* self) {
|
||||
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.
|
||||
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,
|
||||
@ -382,23 +391,23 @@ void StartLibraryApplet(Service::Interface* self) {
|
||||
cmd_buff[1] = applet->Start(parameter).raw;
|
||||
}
|
||||
|
||||
void SetNSStateField(Service::Interface* self) {
|
||||
void SetScreenCapPostPermission(Service::Interface* self) {
|
||||
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[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();
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[8] = unknown_ns_state_field;
|
||||
LOG_WARNING(Service_APT, "(STUBBED) unknown_ns_state_field=%u", unknown_ns_state_field);
|
||||
cmd_buff[2] = static_cast<u32>(screen_capture_post_permission);
|
||||
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission);
|
||||
}
|
||||
|
||||
void GetAppletInfo(Service::Interface* self) {
|
||||
@ -493,6 +502,7 @@ void Init() {
|
||||
|
||||
cpu_percent = 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.
|
||||
notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification");
|
||||
|
@ -94,6 +94,13 @@ enum class StartupArgumentType : u32 {
|
||||
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
|
||||
void SendParameter(const MessageParameter& parameter);
|
||||
|
||||
@ -383,25 +390,24 @@ void StartLibraryApplet(Service::Interface* self);
|
||||
void GetStartupArgument(Service::Interface* self);
|
||||
|
||||
/**
|
||||
* APT::SetNSStateField service function
|
||||
* APT::SetScreenCapPostPermission service function
|
||||
* Inputs:
|
||||
* 1 : u8 NS state field
|
||||
* 0 : Header Code[0x00550040]
|
||||
* 1 : u8 The screenshot posting permission
|
||||
* Outputs:
|
||||
* 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:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 8 : u8 NS state field
|
||||
* Note:
|
||||
* This returns a u8 NS state field(which can be set by cmd 0x00550040), at cmdreply+8.
|
||||
* 2 : u8 The screenshot posting permission
|
||||
*/
|
||||
void GetNSStateField(Service::Interface* self);
|
||||
void GetScreenCapPostPermission(Service::Interface* self);
|
||||
|
||||
/**
|
||||
* APT::CheckNew3DSApp service function
|
||||
|
@ -33,8 +33,8 @@ const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||
{0x00550040, SetNSStateField, "SetNSStateField?"},
|
||||
{0x00560000, GetNSStateField, "GetNSStateField?"},
|
||||
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
||||
};
|
||||
|
@ -92,8 +92,8 @@ const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||
{0x00520104, nullptr, "Wrap1"},
|
||||
{0x00530104, nullptr, "Unwrap1"},
|
||||
{0x00550040, SetNSStateField, "SetNSStateField?" },
|
||||
{0x00560000, GetNSStateField, "GetNSStateField?" },
|
||||
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x00580002, nullptr, "GetProgramID"},
|
||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
||||
|
@ -92,8 +92,8 @@ const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||
{0x00520104, nullptr, "Wrap1"},
|
||||
{0x00530104, nullptr, "Unwrap1"},
|
||||
{0x00550040, SetNSStateField, "SetNSStateField?"},
|
||||
{0x00560000, GetNSStateField, "GetNSStateField?"},
|
||||
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x00580002, nullptr, "GetProgramID"},
|
||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
||||
|
@ -2,8 +2,11 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/shared_page.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -12,6 +15,57 @@ namespace SharedPage {
|
||||
|
||||
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() {
|
||||
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
|
||||
shared_page.unknown_value = 0x1;
|
||||
|
||||
update_time_event = CoreTiming::RegisterEvent("SharedPage::UpdateTimeCallback", UpdateTimeCallback);
|
||||
CoreTiming::ScheduleEvent(0, update_time_event);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -25,13 +25,14 @@ namespace SharedPage {
|
||||
struct DateTime {
|
||||
u64_le date_time; // 0
|
||||
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");
|
||||
|
||||
struct SharedPageDef {
|
||||
// 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
|
||||
/// "Microcontroller hardware info"
|
||||
u8 mcu_hw_info; // 5
|
||||
|
Loading…
Reference in New Issue
Block a user