mirror of
https://github.com/azahar-emu/azahar.git
synced 2026-06-08 03:33:44 -04:00
Merge branch 'azahar-emu:master' into patch-1
This commit is contained in:
commit
2143eb6f2f
317 changed files with 33244 additions and 15585 deletions
133
.ci/libretro-ci.yml
Normal file
133
.ci/libretro-ci.yml
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
.core-defs:
|
||||
variables:
|
||||
JNI_PATH: .
|
||||
CORENAME: azahar
|
||||
API_LEVEL: 21
|
||||
BASE_CORE_ARGS: -DENABLE_LIBRETRO=ON -DENABLE_TESTS=OFF
|
||||
CORE_ARGS: ${BASE_CORE_ARGS}
|
||||
EXTRA_PATH: bin/Release
|
||||
|
||||
variables:
|
||||
STATIC_RETROARCH_BRANCH: master
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
|
||||
# Inclusion templates, required for the build to work
|
||||
include:
|
||||
################################## DESKTOPS ############################## ##
|
||||
# Windows 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/windows-cmake-mingw.yml'
|
||||
|
||||
# Linux 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/linux-cmake.yml'
|
||||
|
||||
# MacOS x86_64
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/osx-cmake-x86.yml'
|
||||
|
||||
# MacOS ARM64
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/osx-cmake-arm64.yml'
|
||||
|
||||
################################## CELLULAR ############################## ##
|
||||
# Android
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/android-cmake.yml'
|
||||
|
||||
# iOS
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/ios-cmake.yml'
|
||||
|
||||
# tvOS
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/tvos-cmake.yml'
|
||||
|
||||
################################## CONSOLES ############################## ##
|
||||
|
||||
# Stages for building
|
||||
stages:
|
||||
- build-prepare
|
||||
- build-shared
|
||||
- build-static
|
||||
|
||||
##############################################################################
|
||||
#################################### STAGES ##################################
|
||||
##############################################################################
|
||||
#
|
||||
################################### DESKTOPS #################################
|
||||
# Windows 64-bit
|
||||
libretro-build-windows-x64:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-windows-cmake-x86_64
|
||||
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-mxe-win-cross-cores:mingw12
|
||||
variables:
|
||||
CORE_ARGS: ${BASE_CORE_ARGS} -DENABLE_LTO=OFF -G Ninja
|
||||
|
||||
# Linux 64-bit
|
||||
libretro-build-linux-x64:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-linux-cmake-x86_64
|
||||
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-amd64-ubuntu:backports
|
||||
variables:
|
||||
CORE_ARGS: ${BASE_CORE_ARGS} -DENABLE_LTO=OFF
|
||||
CC: /usr/bin/gcc-12
|
||||
CXX: /usr/bin/g++-12
|
||||
|
||||
# MacOS x86_64
|
||||
libretro-build-osx-x64:
|
||||
tags:
|
||||
- mac-apple-silicon
|
||||
variables:
|
||||
CORE_ARGS: ${BASE_CORE_ARGS} -DCMAKE_OSX_ARCHITECTURES=x86_64
|
||||
MACOSX_DEPLOYMENT_TARGET: "11.0"
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-osx-cmake-x86_64
|
||||
|
||||
# MacOS ARM64
|
||||
libretro-build-osx-arm64:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-osx-cmake-arm64
|
||||
variables:
|
||||
MACOSX_DEPLOYMENT_TARGET: "11.0"
|
||||
|
||||
################################### CELLULAR #################################
|
||||
# Android ARMv8a
|
||||
android-arm64-v8a:
|
||||
extends:
|
||||
- .libretro-android-cmake-arm64-v8a
|
||||
- .core-defs
|
||||
variables:
|
||||
ANDROID_NDK_VERSION: 26.2.11394342
|
||||
NDK_ROOT: /android-sdk-linux/ndk/$ANDROID_NDK_VERSION
|
||||
LIBNAME: ${CORENAME}_libretro.so
|
||||
artifacts:
|
||||
paths:
|
||||
- $LIBNAME
|
||||
|
||||
# iOS arm64
|
||||
libretro-build-ios-arm64:
|
||||
extends:
|
||||
- .libretro-ios-cmake-arm64
|
||||
- .core-defs
|
||||
variables:
|
||||
CORE_ARGS: ${BASE_CORE_ARGS} -DCITRA_USE_PRECOMPILED_HEADERS=OFF -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64 -DENABLE_OPT=OFF
|
||||
IOS_MINVER: "14.0"
|
||||
EXTRA_PATH: bin/RelWithDebInfo
|
||||
|
||||
# tvOS arm64
|
||||
libretro-build-tvos-arm64:
|
||||
extends:
|
||||
- .libretro-tvos-cmake-arm64
|
||||
- .core-defs
|
||||
variables:
|
||||
CORE_ARGS: ${BASE_CORE_ARGS} -DCITRA_USE_PRECOMPILED_HEADERS=OFF -DIOS=ON -DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvos -DCMAKE_OSX_ARCHITECTURES=arm64 -DENABLE_OPT=OFF
|
||||
MINVER: "14.0"
|
||||
EXTRA_PATH: bin/RelWithDebInfo
|
||||
|
||||
################################### CONSOLES #################################
|
||||
|
||||
13
.ci/libretro-pack.sh
Executable file
13
.ci/libretro-pack.sh
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
# Determine the full revision name.
|
||||
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
|
||||
GITREV="`git show -s --format='%h'`"
|
||||
|
||||
REV_NAME="azahar-libretro-$OS-$TARGET-$GITDATE-$GITREV"
|
||||
if [ "$GITHUB_REF_TYPE" = "tag" ]; then
|
||||
REV_NAME="azahar-libretro-$OS-$TARGET-$GITHUB_REF_NAME"
|
||||
fi
|
||||
|
||||
# Create .zip
|
||||
zip -j -9 $REV_NAME.zip $BUILD_DIR/$EXTRA_PATH/azahar_libretro.*
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
if [[ "$TARGET" == "appimage"* ]]; then
|
||||
if [[ "$TARGET" == "appimage"* ]] || [[ "$TARGET" == "clang"* ]]; then
|
||||
# Compile the AppImage we distribute with Clang.
|
||||
export EXTRA_CMAKE_FLAGS=(-DCMAKE_CXX_COMPILER=clang++
|
||||
-DCMAKE_C_COMPILER=clang
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ REV_NAME="azahar-$OS-$TARGET-$GITDATE-$GITREV"
|
|||
# Determine the name of the release being built.
|
||||
if [ "$GITHUB_REF_TYPE" = "tag" ]; then
|
||||
RELEASE_NAME=azahar-$GITHUB_REF_NAME
|
||||
REV_NAME="azahar-$GITHUB_REF_NAME-$OS-$TARGET"
|
||||
REV_NAME="azahar-$OS-$TARGET-$GITHUB_REF_NAME"
|
||||
else
|
||||
RELEASE_NAME=azahar-head
|
||||
fi
|
||||
|
|
|
|||
41
.github/workflows/build.yml
vendored
41
.github/workflows/build.yml
vendored
|
|
@ -23,12 +23,12 @@ jobs:
|
|||
name: source
|
||||
path: artifacts/
|
||||
|
||||
linux:
|
||||
linux-x86_64:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: ["appimage", "appimage-wayland", "fresh"]
|
||||
target: ["appimage", "appimage-wayland", "gcc-nopch"]
|
||||
container:
|
||||
image: opensauce04/azahar-build-environment:latest
|
||||
options: -u 1001
|
||||
|
|
@ -49,9 +49,9 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ runner.os }}-${{ matrix.target }}-${{ github.sha }}
|
||||
key: ${{ github.job }}-${{ matrix.target }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.target }}-
|
||||
${{ github.job }}-${{ matrix.target }}-
|
||||
- name: Build
|
||||
if: ${{ env.SHOULD_RUN == 'true' }}
|
||||
run: ./.ci/linux.sh
|
||||
|
|
@ -68,11 +68,40 @@ jobs:
|
|||
if: ${{ contains(matrix.target, 'appimage') && env.SHOULD_RUN == 'true' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.OS }}-${{ env.TARGET }}
|
||||
name: ${{ github.job }}-${{ matrix.target }}
|
||||
path: artifacts/
|
||||
|
||||
linux-arm64:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: ["clang", "gcc-nopch"]
|
||||
container:
|
||||
image: opensauce04/azahar-build-environment:latest
|
||||
options: -u 1001
|
||||
env:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_COMPILERCHECK: content
|
||||
CCACHE_SLOPPINESS: time_macros
|
||||
OS: linux
|
||||
TARGET: ${{ matrix.target }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ github.job }}-${{ matrix.target }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ github.job }}-${{ matrix.target }}-
|
||||
- name: Build
|
||||
run: ./.ci/linux.sh
|
||||
|
||||
macos:
|
||||
runs-on: ${{ (matrix.target == 'x86_64' && 'macos-15-intel') || 'macos-26' }}
|
||||
runs-on: ${{ (matrix.target == 'x86_64' && 'macos-26-intel') || 'macos-26' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
|
|||
178
.github/workflows/libretro.yml
vendored
Normal file
178
.github/workflows/libretro.yml
vendored
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
name: citra-libretro
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "*" ]
|
||||
tags: [ "*" ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CORE_ARGS: -DENABLE_LIBRETRO=ON
|
||||
|
||||
jobs:
|
||||
android:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
OS: android
|
||||
TARGET: arm64-v8a
|
||||
API_LEVEL: 21
|
||||
ANDROID_NDK_VERSION: 26.2.11394342
|
||||
ANDROID_ABI: arm64-v8a
|
||||
BUILD_DIR: build/android-arm64-v8a
|
||||
EXTRA_PATH: bin/Release
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set tag name
|
||||
run: |
|
||||
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
|
||||
echo "GIT_TAG_NAME=$GITHUB_REF_NAME" >> $GITHUB_ENV
|
||||
fi
|
||||
echo $GIT_TAG_NAME
|
||||
- name: Update Android SDK CMake version
|
||||
run: |
|
||||
echo "y" | ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "ndk;$ANDROID_NDK_VERSION"
|
||||
echo "y" | ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "cmake;3.30.3"
|
||||
- name: Build
|
||||
run: |
|
||||
export NDK_ROOT=${ANDROID_SDK_ROOT}/ndk/$ANDROID_NDK_VERSION
|
||||
${ANDROID_SDK_ROOT}/cmake/3.30.3/bin/cmake $CORE_ARGS -DANDROID_PLATFORM=android-$API_LEVEL -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_static -DANDROID_ABI=$ANDROID_ABI . -B $BUILD_DIR
|
||||
${ANDROID_SDK_ROOT}/cmake/3.30.3/bin/cmake --build $BUILD_DIR --target azahar_libretro --config Release -j $(nproc)
|
||||
- name: Pack
|
||||
run: ./.ci/libretro-pack.sh
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.OS }}-${{ env.TARGET }}
|
||||
path: ./*.zip
|
||||
linux:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
OS: linux
|
||||
TARGET: x86_64
|
||||
BUILD_DIR: build/linux-x86_64
|
||||
EXTRA_PATH: bin/Release
|
||||
EXTRA_CORE_ARGS: -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 -DENABLE_LTO=OFF
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
run: |
|
||||
cmake $CORE_ARGS $EXTRA_CORE_ARGS . -B $BUILD_DIR
|
||||
cmake --build $BUILD_DIR --target azahar_libretro --config Release -j $(nproc)
|
||||
- name: Pack
|
||||
run: ./.ci/libretro-pack.sh
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.OS }}-${{ env.TARGET }}
|
||||
path: ./*.zip
|
||||
windows:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
OS: windows
|
||||
TARGET: x86_64
|
||||
BUILD_DIR: build/windows-x86_64
|
||||
EXTRA_CORE_ARGS: -DENABLE_LTO=OFF -G Ninja
|
||||
CMAKE: x86_64-w64-mingw32.static-cmake
|
||||
IMAGE: git.libretro.com:5050/libretro-infrastructure/libretro-build-mxe-win-cross-cores:mingw12
|
||||
EXTRA_PATH: bin/Release
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build in cross-container
|
||||
run: |
|
||||
docker pull $IMAGE
|
||||
docker run --rm --user root \
|
||||
-v "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}" \
|
||||
-w "${GITHUB_WORKSPACE}" \
|
||||
$IMAGE \
|
||||
bash -lc "\
|
||||
${CMAKE} $CORE_ARGS $EXTRA_CORE_ARGS . -B $BUILD_DIR && \
|
||||
${CMAKE} --build $BUILD_DIR --target azahar_libretro --config Release -j $(nproc)"
|
||||
- name: Pack
|
||||
run: ./.ci/libretro-pack.sh
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.OS }}-${{ env.TARGET }}
|
||||
path: ./*.zip
|
||||
macos:
|
||||
runs-on: macos-26
|
||||
strategy:
|
||||
matrix:
|
||||
target: ["x86_64", "arm64"]
|
||||
env:
|
||||
OS: macos
|
||||
TARGET: ${{ matrix.target }}
|
||||
MACOSX_DEPLOYMENT_TARGET: 11.0
|
||||
BUILD_DIR: build/osx-${{ matrix.target }}
|
||||
EXTRA_PATH: bin/Release
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install tools
|
||||
run: brew install spirv-tools
|
||||
- name: Build
|
||||
run: |
|
||||
cmake $CORE_ARGS -DCMAKE_OSX_ARCHITECTURES=$TARGET . -B $BUILD_DIR
|
||||
cmake --build $BUILD_DIR --target azahar_libretro --config Release
|
||||
- name: Pack
|
||||
run: ./.ci/libretro-pack.sh
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.OS }}-${{ env.TARGET }}
|
||||
path: ./*.zip
|
||||
ios:
|
||||
runs-on: macos-26
|
||||
env:
|
||||
OS: ios
|
||||
TARGET: arm64
|
||||
BUILD_DIR: build/ios-arm64
|
||||
EXTRA_PATH: bin/Release
|
||||
EXTRA_CORE_ARGS: -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_C_FLAGS=-DIOS -DCMAKE_CXX_FLAGS=-DIOS -DIOS=ON -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 -DCITRA_USE_PRECOMPILED_HEADERS=OFF -DCMAKE_OSX_ARCHITECTURES=arm64 -DENABLE_OPT=OFF
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
run: |
|
||||
cmake $CORE_ARGS $EXTRA_CORE_ARGS . -B $BUILD_DIR
|
||||
cmake --build $BUILD_DIR --target azahar_libretro --config Release
|
||||
- name: Pack
|
||||
run: ./.ci/libretro-pack.sh
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.OS }}-${{ env.TARGET }}
|
||||
path: ./*.zip
|
||||
tvos:
|
||||
runs-on: macos-26
|
||||
env:
|
||||
OS: tvos
|
||||
TARGET: arm64
|
||||
BUILD_DIR: build/tvos-arm64
|
||||
EXTRA_PATH: bin/Release
|
||||
EXTRA_CORE_ARGS: -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_C_FLAGS=-DIOS -DCMAKE_CXX_FLAGS=-DIOS -DIOS=ON -DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 -DCITRA_USE_PRECOMPILED_HEADERS=OFF -DCMAKE_OSX_SYSROOT=appletvos -DCMAKE_OSX_ARCHITECTURES=arm64 -DENABLE_OPT=OFF
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
run: |
|
||||
cmake $CORE_ARGS $EXTRA_CORE_ARGS . -B $BUILD_DIR
|
||||
cmake --build $BUILD_DIR --target azahar_libretro --config Release
|
||||
- name: Pack
|
||||
run: ./.ci/libretro-pack.sh
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.OS }}-${{ env.TARGET }}
|
||||
path: ./*.zip
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -56,3 +56,7 @@ repo/
|
|||
.ccache/
|
||||
node_modules/
|
||||
VULKAN_SDK/
|
||||
|
||||
# Version info files
|
||||
GIT-COMMIT
|
||||
GIT-TAG
|
||||
|
|
|
|||
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -103,3 +103,6 @@
|
|||
[submodule "externals/xxHash"]
|
||||
path = externals/xxHash
|
||||
url = https://github.com/Cyan4973/xxHash.git
|
||||
[submodule "externals/libretro-common"]
|
||||
path = externals/libretro-common/libretro-common
|
||||
url = https://github.com/libretro/libretro-common.git
|
||||
|
|
|
|||
|
|
@ -17,20 +17,23 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
|||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||
include(DownloadExternals)
|
||||
include(CMakeDependentOption)
|
||||
include(FindPkgConfig)
|
||||
|
||||
project(citra LANGUAGES C CXX ASM)
|
||||
# must be invoked after project() command when using CMAKE_TOOLCHAIN_FILE
|
||||
include(FindPkgConfig)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
enable_language(OBJC OBJCXX)
|
||||
endif()
|
||||
|
||||
option(ENABLE_LIBRETRO "Build as a LibRetro core" OFF)
|
||||
|
||||
# Some submodules like to pick their own default build type if not specified.
|
||||
# Make sure we default to Release build type always, unless the generator has custom types.
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
if (APPLE AND NOT ENABLE_LIBRETRO)
|
||||
# Silence warnings on empty objects, for example when platform-specific code is #ifdef'd out.
|
||||
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
|
|
@ -90,8 +93,18 @@ else()
|
|||
set(DEFAULT_ENABLE_OPENGL ON)
|
||||
endif()
|
||||
|
||||
# Track which options were explicitly set by the user (for libretro conflict detection)
|
||||
set(_LIBRETRO_INCOMPATIBLE_OPTIONS
|
||||
ENABLE_SDL2 ENABLE_QT ENABLE_WEB_SERVICE ENABLE_SCRIPTING
|
||||
ENABLE_OPENAL ENABLE_ROOM ENABLE_ROOM_STANDALONE ENABLE_CUBEB ENABLE_LIBUSB)
|
||||
set(_USER_SET_OPTIONS "")
|
||||
foreach(_opt IN LISTS _LIBRETRO_INCOMPATIBLE_OPTIONS)
|
||||
if(DEFINED ${_opt})
|
||||
list(APPEND _USER_SET_OPTIONS ${_opt})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
option(ENABLE_SDL2 "Enable using SDL2" ON)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_SDL2_FRONTEND "Enable the SDL2 frontend" OFF "ENABLE_SDL2;NOT ANDROID AND NOT IOS" OFF)
|
||||
option(USE_SYSTEM_SDL2 "Use the system SDL2 lib (instead of the bundled one)" OFF)
|
||||
|
||||
# Set bundled qt as dependent options.
|
||||
|
|
@ -130,6 +143,31 @@ option(ENABLE_NATIVE_OPTIMIZATION "Enables processor-specific optimizations via
|
|||
option(CITRA_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
||||
option(CITRA_WARNINGS_AS_ERRORS "Enable warnings as errors" ON)
|
||||
|
||||
# Handle incompatible options for libretro builds
|
||||
if(ENABLE_LIBRETRO)
|
||||
# Check for explicitly-set conflicting options
|
||||
set(_CONFLICTS "")
|
||||
foreach(_opt IN LISTS _LIBRETRO_INCOMPATIBLE_OPTIONS)
|
||||
list(FIND _USER_SET_OPTIONS ${_opt} _idx)
|
||||
if(NOT _idx EQUAL -1 AND ${_opt})
|
||||
list(APPEND _CONFLICTS ${_opt})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(_CONFLICTS)
|
||||
string(REPLACE ";" ", " _CONFLICTS_STR "${_CONFLICTS}")
|
||||
message(FATAL_ERROR
|
||||
"ENABLE_LIBRETRO is incompatible with: ${_CONFLICTS_STR}\n"
|
||||
"These options were explicitly enabled but are not supported for libretro builds.\n"
|
||||
"Remove these options or set them to OFF.")
|
||||
endif()
|
||||
|
||||
# Force disable incompatible options (handles defaulted-on options)
|
||||
foreach(_opt IN LISTS _LIBRETRO_INCOMPATIBLE_OPTIONS)
|
||||
set(${_opt} OFF CACHE BOOL "Disabled for libretro" FORCE)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Pass the following values to C++ land
|
||||
if (ENABLE_QT)
|
||||
add_definitions(-DENABLE_QT)
|
||||
|
|
@ -143,9 +181,6 @@ endif()
|
|||
if (ENABLE_SDL2)
|
||||
add_definitions(-DENABLE_SDL2)
|
||||
endif()
|
||||
if (ENABLE_SDL2_FRONTEND)
|
||||
add_definitions(-DENABLE_SDL2_FRONTEND)
|
||||
endif()
|
||||
|
||||
if(ENABLE_SSE42 AND (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64"))
|
||||
message(STATUS "SSE4.2 enabled for x86_64")
|
||||
|
|
@ -223,7 +258,7 @@ function(check_submodules_present)
|
|||
foreach(module ${gitmodules})
|
||||
string(REGEX REPLACE "path *= *" "" module ${module})
|
||||
if (NOT EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git")
|
||||
message(SEND_ERROR "Git submodule ${module} not found."
|
||||
message(SEND_ERROR "Git submodule ${module} not found.\n"
|
||||
"Please run: git submodule update --init --recursive")
|
||||
endif()
|
||||
endforeach()
|
||||
|
|
@ -300,6 +335,9 @@ set(CMAKE_VISIBILITY_INLINES_HIDDEN NO)
|
|||
# set up output paths for executable binaries
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/$<CONFIG>)
|
||||
|
||||
if (ENABLE_LIBRETRO)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
# System imported libraries
|
||||
# ======================
|
||||
|
|
@ -359,7 +397,7 @@ if (APPLE)
|
|||
find_library(IOSURFACE_LIBRARY IOSurface REQUIRED)
|
||||
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${AVFOUNDATION_LIBRARY} ${IOSURFACE_LIBRARY} ${MOLTENVK_LIBRARY})
|
||||
|
||||
if (ENABLE_VULKAN)
|
||||
if (ENABLE_VULKAN AND NOT ENABLE_LIBRETRO)
|
||||
if (NOT USE_SYSTEM_MOLTENVK)
|
||||
download_moltenvk()
|
||||
endif()
|
||||
|
|
@ -513,8 +551,6 @@ if (NOT ANDROID AND NOT IOS)
|
|||
include(BundleTarget)
|
||||
if (ENABLE_QT)
|
||||
qt_bundle_target(citra_meta)
|
||||
elseif (ENABLE_SDL2_FRONTEND)
|
||||
bundle_target(citra_meta)
|
||||
endif()
|
||||
if (ENABLE_ROOM_STANDALONE)
|
||||
bundle_target(citra_room_standalone)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
macro(generate_build_info)
|
||||
find_package(Git QUIET)
|
||||
|
||||
# Gets a UTC timstamp and sets the provided variable to it
|
||||
function(get_timestamp _var)
|
||||
string(TIMESTAMP timestamp UTC)
|
||||
|
|
@ -6,9 +8,14 @@ macro(generate_build_info)
|
|||
endfunction()
|
||||
get_timestamp(BUILD_DATE)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/externals/cmake-modules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/externals/cmake-modules")
|
||||
|
||||
if (EXISTS "${SRC_DIR}/.git/objects")
|
||||
if (EXISTS "${CMAKE_SOURCE_DIR}/GIT-COMMIT" AND EXISTS "${CMAKE_SOURCE_DIR}/GIT-TAG")
|
||||
file(READ "${CMAKE_SOURCE_DIR}/GIT-COMMIT" GIT_REV_RAW LIMIT 64)
|
||||
string(STRIP "${GIT_REV_RAW}" GIT_REV)
|
||||
string(SUBSTRING "${GIT_REV_RAW}" 0 9 GIT_DESC)
|
||||
set(GIT_BRANCH "HEAD")
|
||||
elseif (EXISTS "${CMAKE_SOURCE_DIR}/.git/objects")
|
||||
# Find the package here with the known path so that the GetGit commands can find it as well
|
||||
find_package(Git QUIET PATHS "${GIT_EXECUTABLE}")
|
||||
|
||||
|
|
@ -17,12 +24,6 @@ macro(generate_build_info)
|
|||
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
||||
git_describe(GIT_DESC --always --long --dirty)
|
||||
git_branch_name(GIT_BRANCH)
|
||||
elseif (EXISTS "${SRC_DIR}/GIT-COMMIT" AND EXISTS "${SRC_DIR}/GIT-TAG")
|
||||
# unified source archive
|
||||
file(READ "${SRC_DIR}/GIT-COMMIT" GIT_REV_RAW LIMIT 64)
|
||||
string(STRIP "${GIT_REV_RAW}" GIT_REV)
|
||||
string(SUBSTRING "${GIT_REV_RAW}" 0 9 GIT_DESC)
|
||||
set(GIT_BRANCH "HEAD")
|
||||
else()
|
||||
# self-packed archive?
|
||||
set(GIT_REV "UNKNOWN")
|
||||
|
|
@ -39,8 +40,8 @@ macro(generate_build_info)
|
|||
if ($ENV{GITHUB_REF_TYPE} STREQUAL "tag")
|
||||
set(GIT_TAG $ENV{GITHUB_REF_NAME})
|
||||
endif()
|
||||
elseif (EXISTS "${SRC_DIR}/GIT-COMMIT" AND EXISTS "${SRC_DIR}/GIT-TAG")
|
||||
file(READ "${SRC_DIR}/GIT-TAG" GIT_TAG)
|
||||
elseif (EXISTS "${CMAKE_SOURCE_DIR}/GIT-COMMIT" AND EXISTS "${CMAKE_SOURCE_DIR}/GIT-TAG")
|
||||
file(READ "${CMAKE_SOURCE_DIR}/GIT-TAG" GIT_TAG)
|
||||
string(STRIP ${GIT_TAG} GIT_TAG)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/CMakeModules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules")
|
||||
|
||||
include(GenerateBuildInfo)
|
||||
generate_build_info()
|
||||
|
||||
# The variable SRC_DIR must be passed into the script (since it uses the current build directory for all values of CMAKE_*_DIR)
|
||||
set(VIDEO_CORE "${SRC_DIR}/src/video_core")
|
||||
set(VIDEO_CORE "${CMAKE_SOURCE_DIR}/src/video_core")
|
||||
set(HASH_FILES
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h"
|
||||
|
|
@ -11,6 +12,10 @@ set(HASH_FILES
|
|||
"${VIDEO_CORE}/renderer_opengl/gl_shader_util.h"
|
||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_util.cpp"
|
||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_util.h"
|
||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_disk_cache.cpp"
|
||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_disk_cache.h"
|
||||
"${VIDEO_CORE}/renderer_vulkan/vk_pipeline_cache.cpp"
|
||||
"${VIDEO_CORE}/renderer_vulkan/vk_pipeline_cache.h"
|
||||
"${VIDEO_CORE}/shader/generator/glsl_fs_shader_gen.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/glsl_fs_shader_gen.h"
|
||||
"${VIDEO_CORE}/shader/generator/glsl_shader_decompiler.cpp"
|
||||
|
|
@ -19,6 +24,7 @@ set(HASH_FILES
|
|||
"${VIDEO_CORE}/shader/generator/glsl_shader_gen.h"
|
||||
"${VIDEO_CORE}/shader/generator/pica_fs_config.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/pica_fs_config.h"
|
||||
"${VIDEO_CORE}/shader/generator/profile.h"
|
||||
"${VIDEO_CORE}/shader/generator/shader_gen.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/shader_gen.h"
|
||||
"${VIDEO_CORE}/shader/generator/shader_uniforms.cpp"
|
||||
|
|
@ -42,4 +48,4 @@ foreach (F IN LISTS HASH_FILES)
|
|||
set(COMBINED "${COMBINED}${TMP}")
|
||||
endforeach()
|
||||
string(MD5 SHADER_CACHE_VERSION "${COMBINED}")
|
||||
configure_file("${SRC_DIR}/src/common/scm_rev.cpp.in" "scm_rev.cpp" @ONLY)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/src/common/scm_rev.cpp.in" "scm_rev.cpp" @ONLY)
|
||||
|
|
|
|||
278
CMakeModules/GenerateSettingKeys.cmake
Normal file
278
CMakeModules/GenerateSettingKeys.cmake
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
## This file should be the *only place* where setting keys exist as strings.
|
||||
# All references to setting strings should be derived from the
|
||||
# `setting_keys.h` and `jni_setting_keys.cpp` files generated here.
|
||||
|
||||
# !!! Changes made here should be mirrored to SettingKeys.kt if used on Android
|
||||
|
||||
# Shared setting keys (multi-platform)
|
||||
foreach(KEY IN ITEMS
|
||||
"use_artic_base_controller"
|
||||
"enable_gamemode"
|
||||
"use_cpu_jit"
|
||||
"cpu_clock_percentage"
|
||||
"is_new_3ds"
|
||||
"lle_applets"
|
||||
"deterministic_async_operations"
|
||||
"enable_required_online_lle_modules"
|
||||
"use_virtual_sd"
|
||||
"use_custom_storage"
|
||||
"compress_cia_installs"
|
||||
"region_value"
|
||||
"init_clock"
|
||||
"init_time"
|
||||
"init_time_offset"
|
||||
"init_ticks_type"
|
||||
"init_ticks_override"
|
||||
"plugin_loader"
|
||||
"allow_plugin_loader"
|
||||
"steps_per_hour"
|
||||
"apply_region_free_patch"
|
||||
"graphics_api"
|
||||
"physical_device"
|
||||
"use_gles"
|
||||
"renderer_debug"
|
||||
"dump_command_buffers"
|
||||
"spirv_shader_gen"
|
||||
"disable_spirv_optimizer"
|
||||
"async_shader_compilation"
|
||||
"async_presentation"
|
||||
"use_hw_shader"
|
||||
"use_disk_shader_cache"
|
||||
"shaders_accurate_mul"
|
||||
"use_vsync"
|
||||
"use_display_refresh_rate_detection"
|
||||
"use_shader_jit"
|
||||
"resolution_factor"
|
||||
"frame_limit"
|
||||
"turbo_limit"
|
||||
"texture_filter"
|
||||
"texture_sampling"
|
||||
"delay_game_render_thread_us"
|
||||
"layout_option"
|
||||
"swap_screen"
|
||||
"upright_screen"
|
||||
"secondary_display_layout"
|
||||
"large_screen_proportion"
|
||||
"screen_gap"
|
||||
"small_screen_position"
|
||||
"custom_top_x"
|
||||
"custom_top_y"
|
||||
"custom_top_width"
|
||||
"custom_top_height"
|
||||
"custom_bottom_x"
|
||||
"custom_bottom_y"
|
||||
"custom_bottom_width"
|
||||
"custom_bottom_height"
|
||||
"custom_second_layer_opacity"
|
||||
"aspect_ratio"
|
||||
"screen_top_stretch"
|
||||
"screen_top_leftright_padding"
|
||||
"screen_top_topbottom_padding"
|
||||
"screen_bottom_stretch"
|
||||
"screen_bottom_leftright_padding"
|
||||
"screen_bottom_topbottom_padding"
|
||||
"portrait_layout_option"
|
||||
"custom_portrait_top_x"
|
||||
"custom_portrait_top_y"
|
||||
"custom_portrait_top_width"
|
||||
"custom_portrait_top_height"
|
||||
"custom_portrait_bottom_x"
|
||||
"custom_portrait_bottom_y"
|
||||
"custom_portrait_bottom_width"
|
||||
"custom_portrait_bottom_height"
|
||||
"bg_red"
|
||||
"bg_green"
|
||||
"bg_blue"
|
||||
"render_3d"
|
||||
"factor_3d"
|
||||
"swap_eyes_3d"
|
||||
"render_3d_which_display"
|
||||
"mono_render_option"
|
||||
"cardboard_screen_size"
|
||||
"cardboard_x_shift"
|
||||
"cardboard_y_shift"
|
||||
"filter_mode"
|
||||
"pp_shader_name"
|
||||
"anaglyph_shader_name"
|
||||
"dump_textures"
|
||||
"custom_textures"
|
||||
"preload_textures"
|
||||
"async_custom_loading"
|
||||
"disable_right_eye_render"
|
||||
"audio_emulation"
|
||||
"enable_audio_stretching"
|
||||
"enable_realtime_audio"
|
||||
"volume"
|
||||
"output_type"
|
||||
"output_device"
|
||||
"input_type"
|
||||
"input_device"
|
||||
"delay_start_for_lle_modules"
|
||||
"use_gdbstub"
|
||||
"gdbstub_port"
|
||||
"instant_debug_log"
|
||||
"enable_rpc_server"
|
||||
"log_filter"
|
||||
"log_regex_filter"
|
||||
"toggle_unique_data_console_type"
|
||||
"use_integer_scaling"
|
||||
"layouts_to_cycle"
|
||||
"camera_inner_flip"
|
||||
"camera_outer_left_flip"
|
||||
"camera_outer_right_flip"
|
||||
"camera_inner_name"
|
||||
"camera_inner_config"
|
||||
"camera_outer_left_name"
|
||||
"camera_outer_left_config"
|
||||
"camera_outer_right_name"
|
||||
"camera_outer_right_config"
|
||||
"video_encoder"
|
||||
"video_encoder_options"
|
||||
"video_bitrate"
|
||||
"audio_encoder"
|
||||
"audio_encoder_options"
|
||||
"audio_bitrate"
|
||||
"last_artic_base_addr"
|
||||
"motion_device"
|
||||
"touch_device"
|
||||
"udp_input_address"
|
||||
"udp_input_port"
|
||||
"udp_pad_index"
|
||||
"record_frame_times"
|
||||
"language" # FIXME: DUPLICATE KEY (libretro equivalent: language_value)
|
||||
"web_api_url"
|
||||
"citra_username"
|
||||
"citra_token"
|
||||
)
|
||||
set(SETTING_KEY_LIST "${SETTING_KEY_LIST}\n\"${KEY}\",")
|
||||
set(SETTING_KEY_DEFINITIONS "${SETTING_KEY_DEFINITIONS}\nDEFINE_KEY(${KEY})")
|
||||
if (ANDROID)
|
||||
string(REPLACE "_" "_1" KEY_JNI_ESCAPED ${KEY})
|
||||
set(JNI_SETTING_KEY_DEFINITIONS "${JNI_SETTING_KEY_DEFINITIONS}
|
||||
JNI_DEFINE_KEY(${KEY}, ${KEY_JNI_ESCAPED})")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Qt exclusive setting keys
|
||||
# Note: A lot of these are very generic because our Qt settings are currently put under groups:
|
||||
# E.g. UILayout\geometry
|
||||
# TODO: We should probably get rid of these groups and use complete keys at some point. -OS
|
||||
# FIXME: Some of these settings don't use the standard snake_case. When we can migrate, address that. -OS
|
||||
if (ENABLE_QT)
|
||||
foreach(KEY IN ITEMS
|
||||
"nickname"
|
||||
"ip"
|
||||
"port"
|
||||
"room_nickname"
|
||||
"room_name"
|
||||
"room_port"
|
||||
"host_type"
|
||||
"max_player"
|
||||
"room_description"
|
||||
"multiplayer_filter_text"
|
||||
"multiplayer_filter_games_owned"
|
||||
"multiplayer_filter_hide_empty"
|
||||
"multiplayer_filter_hide_full"
|
||||
"username_ban_list"
|
||||
"username"
|
||||
"ip_ban_list"
|
||||
"romsPath"
|
||||
"symbolsPath"
|
||||
"movieRecordPath"
|
||||
"moviePlaybackPath"
|
||||
"videoDumpingPath"
|
||||
"gameListRootDir"
|
||||
"gameListDeepScan"
|
||||
"path"
|
||||
"deep_scan"
|
||||
"expanded"
|
||||
"recentFiles"
|
||||
"output_format"
|
||||
"format_options"
|
||||
"theme"
|
||||
"program_id"
|
||||
"geometry"
|
||||
"state"
|
||||
"geometryRenderWindow"
|
||||
"gameListHeaderState"
|
||||
"microProfileDialogGeometry"
|
||||
"name"
|
||||
"bind"
|
||||
"profile"
|
||||
"use_touchpad"
|
||||
"controller_touch_device"
|
||||
"use_touch_from_button"
|
||||
"touch_from_button_map"
|
||||
"touch_from_button_maps" # Why are these two so similar? Basically typo bait
|
||||
"nand_directory"
|
||||
"sdmc_directory"
|
||||
"game_id"
|
||||
"KeySeq"
|
||||
"gamedirs"
|
||||
"libvorbis"
|
||||
"Context"
|
||||
"favorites"
|
||||
)
|
||||
set(SETTING_KEY_LIST "${SETTING_KEY_LIST}\n\"${KEY}\",")
|
||||
set(SETTING_KEY_DEFINITIONS "${SETTING_KEY_DEFINITIONS}\nDEFINE_KEY(${KEY})")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Android exclusive setting keys (standalone app only, not Android libretro)
|
||||
if (ANDROID)
|
||||
foreach(KEY IN ITEMS
|
||||
"expand_to_cutout_area"
|
||||
"performance_overlay_enable"
|
||||
"performance_overlay_show_fps"
|
||||
"performance_overlay_show_frame_time"
|
||||
"performance_overlay_show_speed"
|
||||
"performance_overlay_show_app_ram_usage"
|
||||
"performance_overlay_show_available_ram"
|
||||
"performance_overlay_show_battery_temp"
|
||||
"performance_overlay_background"
|
||||
"use_frame_limit" # FIXME: DUPLICATE KEY (shared equivalent: frame_limit)
|
||||
"android_hide_images"
|
||||
"screen_orientation"
|
||||
"performance_overlay_position"
|
||||
)
|
||||
string(REPLACE "_" "_1" KEY_JNI_ESCAPED ${KEY})
|
||||
set(SETTING_KEY_LIST "${SETTING_KEY_LIST}\n\"${KEY}\",")
|
||||
set(SETTING_KEY_DEFINITIONS "${SETTING_KEY_DEFINITIONS}\nDEFINE_KEY(${KEY})")
|
||||
set(JNI_SETTING_KEY_DEFINITIONS "${JNI_SETTING_KEY_DEFINITIONS}
|
||||
JNI_DEFINE_KEY(${KEY}, ${KEY_JNI_ESCAPED})")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Libretro exclusive setting keys
|
||||
if (ENABLE_LIBRETRO)
|
||||
foreach(KEY IN ITEMS
|
||||
"language_value"
|
||||
"swap_screen_mode"
|
||||
"use_libretro_save_path"
|
||||
"analog_function"
|
||||
"analog_deadzone"
|
||||
"enable_mouse_touchscreen"
|
||||
"enable_touch_touchscreen"
|
||||
"render_touchscreen"
|
||||
"enable_motion"
|
||||
"motion_sensitivity"
|
||||
)
|
||||
string(REPLACE "_" "_1" KEY_JNI_ESCAPED ${KEY})
|
||||
set(SETTING_KEY_LIST "${SETTING_KEY_LIST}\n\"${KEY}\",")
|
||||
set(SETTING_KEY_DEFINITIONS "${SETTING_KEY_DEFINITIONS}\nDEFINE_KEY(${KEY})")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Trim trailing comma and newline from SETTING_KEY_LIST
|
||||
string(LENGTH "${SETTING_KEY_LIST}" SETTING_KEY_LIST_LENGTH)
|
||||
math(EXPR SETTING_KEY_LIST_NEW_LENGTH "${SETTING_KEY_LIST_LENGTH} - 1")
|
||||
string(SUBSTRING "${SETTING_KEY_LIST}" 0 ${SETTING_KEY_LIST_NEW_LENGTH} SETTING_KEY_LIST)
|
||||
|
||||
# Configure files
|
||||
configure_file("common/setting_keys.h.in" "common/setting_keys.h" @ONLY)
|
||||
if (ENABLE_QT)
|
||||
configure_file("citra_qt/setting_qkeys.h.in" "citra_qt/setting_qkeys.h" @ONLY)
|
||||
endif()
|
||||
if (ANDROID AND NOT ENABLE_LIBRETRO)
|
||||
configure_file("android/app/src/main/jni/jni_setting_keys.cpp.in" "android/app/src/main/jni/jni_setting_keys.cpp" @ONLY)
|
||||
endif()
|
||||
1109
dist/languages/ca_ES_valencia.ts
vendored
1109
dist/languages/ca_ES_valencia.ts
vendored
File diff suppressed because it is too large
Load diff
944
dist/languages/da_DK.ts
vendored
944
dist/languages/da_DK.ts
vendored
File diff suppressed because it is too large
Load diff
948
dist/languages/de.ts
vendored
948
dist/languages/de.ts
vendored
File diff suppressed because it is too large
Load diff
1602
dist/languages/el.ts
vendored
1602
dist/languages/el.ts
vendored
File diff suppressed because it is too large
Load diff
981
dist/languages/es_ES.ts
vendored
981
dist/languages/es_ES.ts
vendored
File diff suppressed because it is too large
Load diff
942
dist/languages/fi.ts
vendored
942
dist/languages/fi.ts
vendored
File diff suppressed because it is too large
Load diff
963
dist/languages/fr.ts
vendored
963
dist/languages/fr.ts
vendored
File diff suppressed because it is too large
Load diff
946
dist/languages/hu_HU.ts
vendored
946
dist/languages/hu_HU.ts
vendored
File diff suppressed because it is too large
Load diff
944
dist/languages/id.ts
vendored
944
dist/languages/id.ts
vendored
File diff suppressed because it is too large
Load diff
1010
dist/languages/it.ts
vendored
1010
dist/languages/it.ts
vendored
File diff suppressed because it is too large
Load diff
950
dist/languages/ja_JP.ts
vendored
950
dist/languages/ja_JP.ts
vendored
File diff suppressed because it is too large
Load diff
946
dist/languages/ko_KR.ts
vendored
946
dist/languages/ko_KR.ts
vendored
File diff suppressed because it is too large
Load diff
942
dist/languages/lt_LT.ts
vendored
942
dist/languages/lt_LT.ts
vendored
File diff suppressed because it is too large
Load diff
946
dist/languages/nb.ts
vendored
946
dist/languages/nb.ts
vendored
File diff suppressed because it is too large
Load diff
946
dist/languages/nl.ts
vendored
946
dist/languages/nl.ts
vendored
File diff suppressed because it is too large
Load diff
952
dist/languages/pl_PL.ts
vendored
952
dist/languages/pl_PL.ts
vendored
File diff suppressed because it is too large
Load diff
952
dist/languages/pt_BR.ts
vendored
952
dist/languages/pt_BR.ts
vendored
File diff suppressed because it is too large
Load diff
946
dist/languages/ro_RO.ts
vendored
946
dist/languages/ro_RO.ts
vendored
File diff suppressed because it is too large
Load diff
948
dist/languages/ru_RU.ts
vendored
948
dist/languages/ru_RU.ts
vendored
File diff suppressed because it is too large
Load diff
952
dist/languages/sv.ts
vendored
952
dist/languages/sv.ts
vendored
File diff suppressed because it is too large
Load diff
948
dist/languages/tr_TR.ts
vendored
948
dist/languages/tr_TR.ts
vendored
File diff suppressed because it is too large
Load diff
944
dist/languages/vi_VN.ts
vendored
944
dist/languages/vi_VN.ts
vendored
File diff suppressed because it is too large
Load diff
950
dist/languages/zh_CN.ts
vendored
950
dist/languages/zh_CN.ts
vendored
File diff suppressed because it is too large
Load diff
944
dist/languages/zh_TW.ts
vendored
944
dist/languages/zh_TW.ts
vendored
File diff suppressed because it is too large
Load diff
27
externals/CMakeLists.txt
vendored
27
externals/CMakeLists.txt
vendored
|
|
@ -50,15 +50,17 @@ else()
|
|||
endif()
|
||||
|
||||
# Catch2
|
||||
add_library(catch2 INTERFACE)
|
||||
if(USE_SYSTEM_CATCH2)
|
||||
find_package(Catch2 3.0.0 REQUIRED)
|
||||
else()
|
||||
set(CATCH_INSTALL_DOCS OFF CACHE BOOL "")
|
||||
set(CATCH_INSTALL_EXTRAS OFF CACHE BOOL "")
|
||||
add_subdirectory(catch2)
|
||||
if (ENABLE_TESTS)
|
||||
add_library(catch2 INTERFACE)
|
||||
if(USE_SYSTEM_CATCH2)
|
||||
find_package(Catch2 3.0.0 REQUIRED)
|
||||
else()
|
||||
set(CATCH_INSTALL_DOCS OFF CACHE BOOL "")
|
||||
set(CATCH_INSTALL_EXTRAS OFF CACHE BOOL "")
|
||||
add_subdirectory(catch2)
|
||||
endif()
|
||||
target_link_libraries(catch2 INTERFACE Catch2::Catch2WithMain)
|
||||
endif()
|
||||
target_link_libraries(catch2 INTERFACE Catch2::Catch2WithMain)
|
||||
|
||||
# Crypto++
|
||||
if(USE_SYSTEM_CRYPTOPP)
|
||||
|
|
@ -292,6 +294,15 @@ if (USE_DISCORD_PRESENCE)
|
|||
target_include_directories(discord-rpc INTERFACE ./discord-rpc/include)
|
||||
endif()
|
||||
|
||||
# LibRetro
|
||||
if (ENABLE_LIBRETRO)
|
||||
add_library(libretro INTERFACE)
|
||||
target_include_directories(libretro INTERFACE ./libretro-common/libretro-common/include)
|
||||
if (ANDROID)
|
||||
add_subdirectory(libretro-common EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# JSON
|
||||
add_library(json-headers INTERFACE)
|
||||
if (USE_SYSTEM_JSON)
|
||||
|
|
|
|||
2
externals/boost
vendored
2
externals/boost
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 2c82bd787302398bcae990e3c9ab2b451284f4ca
|
||||
Subproject commit f9b15f673a688982f78a5f63a49a27275b318e5f
|
||||
16
externals/libretro-common/CMakeLists.txt
vendored
Normal file
16
externals/libretro-common/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
add_library(libretro_common STATIC
|
||||
libretro-common/compat/compat_posix_string.c
|
||||
libretro-common/compat/fopen_utf8.c
|
||||
libretro-common/encodings/encoding_utf.c
|
||||
libretro-common/compat/compat_strl.c
|
||||
libretro-common/file/file_path.c
|
||||
libretro-common/streams/file_stream.c
|
||||
libretro-common/streams/file_stream_transforms.c
|
||||
libretro-common/string/stdstring.c
|
||||
libretro-common/time/rtime.c
|
||||
libretro-common/vfs/vfs_implementation.c
|
||||
)
|
||||
target_include_directories(libretro_common PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libretro-common
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libretro-common/include
|
||||
)
|
||||
1
externals/libretro-common/libretro-common
vendored
Submodule
1
externals/libretro-common/libretro-common
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7fc7feeddca391be65c94e6541381467684b814d
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
# Enable modules to include each other's files
|
||||
include_directories(.)
|
||||
|
||||
include(GenerateSettingKeys)
|
||||
|
||||
# CMake seems to only define _DEBUG on Windows
|
||||
set_property(DIRECTORY APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
|
||||
|
|
@ -110,10 +112,14 @@ else()
|
|||
# In case a flag isn't supported on e.g. a certain architecture, don't error.
|
||||
-Wno-unused-command-line-argument
|
||||
# Build fortification options
|
||||
-Wp,-D_GLIBCXX_ASSERTIONS
|
||||
-fstack-protector-strong
|
||||
-fstack-clash-protection
|
||||
)
|
||||
if (NOT ENABLE_LIBRETRO)
|
||||
add_compile_options(
|
||||
-Wp,-D_GLIBCXX_ASSERTIONS
|
||||
-fstack-clash-protection
|
||||
)
|
||||
endif()
|
||||
|
||||
# If we define _FORTIFY_SOURCE when it is already defined, compilation will fail
|
||||
string(FIND "-D_FORTIFY_SOURCE" "${CMAKE_CXX_FLAGS} " FORTIFY_SOURCE_DEFINED)
|
||||
|
|
@ -189,18 +195,18 @@ if (ENABLE_TESTS)
|
|||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (ENABLE_SDL2_FRONTEND)
|
||||
add_subdirectory(citra_sdl)
|
||||
endif()
|
||||
|
||||
if (ENABLE_QT)
|
||||
add_subdirectory(citra_qt)
|
||||
endif()
|
||||
|
||||
if (ENABLE_QT OR ENABLE_SDL2_FRONTEND)
|
||||
if (ENABLE_QT) # Or any other hypothetical future frontends
|
||||
add_subdirectory(citra_meta)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LIBRETRO)
|
||||
add_subdirectory(citra_libretro)
|
||||
endif()
|
||||
|
||||
if (ENABLE_ROOM)
|
||||
add_subdirectory(citra_room)
|
||||
endif()
|
||||
|
|
@ -209,7 +215,7 @@ if (ENABLE_ROOM_STANDALONE)
|
|||
add_subdirectory(citra_room_standalone)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
if (ANDROID AND NOT ENABLE_LIBRETRO)
|
||||
add_subdirectory(android/app/src/main/jni)
|
||||
target_include_directories(citra-android PRIVATE android/app/src/main)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ android {
|
|||
defaultConfig {
|
||||
// The application ID refers to Lime3DS to allow for
|
||||
// the Play Store listing, which was originally set up for Lime3DS, to still be used.
|
||||
applicationId = "io.github.lime3ds.android"
|
||||
applicationId = "org.azahar_emu.azahar"
|
||||
minSdk = 29
|
||||
targetSdk = 35
|
||||
versionCode = autoVersion
|
||||
|
|
@ -173,6 +173,7 @@ android {
|
|||
register("googlePlay") {
|
||||
dimension = "version"
|
||||
versionNameSuffix = "-googleplay"
|
||||
applicationId = "io.github.lime3ds.android"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import androidx.fragment.app.DialogFragment
|
|||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.citra.citra_emu.activities.EmulationActivity
|
||||
import org.citra.citra_emu.model.Game
|
||||
import org.citra.citra_emu.utils.BuildUtil
|
||||
import org.citra.citra_emu.utils.FileUtil
|
||||
import org.citra.citra_emu.utils.Log
|
||||
|
|
@ -132,7 +133,27 @@ object NativeLibrary {
|
|||
* If not set, it auto-detects a location
|
||||
*/
|
||||
external fun setUserDirectory(directory: String)
|
||||
external fun getInstalledGamePaths(): Array<String?>
|
||||
|
||||
data class InstalledGame(
|
||||
val path: String,
|
||||
val mediaType: Game.MediaType
|
||||
)
|
||||
fun getInstalledGamePaths(): Array<InstalledGame> {
|
||||
val games = getInstalledGamePathsImpl()
|
||||
|
||||
return games.mapNotNull { entry ->
|
||||
entry?.let {
|
||||
val sep = it.lastIndexOf('|')
|
||||
if (sep == -1) return@mapNotNull null
|
||||
|
||||
val path = it.substring(0, sep)
|
||||
val mediaType = Game.MediaType.fromInt(it.substring(sep + 1).toInt())
|
||||
|
||||
InstalledGame(path, mediaType!!)
|
||||
}
|
||||
}.toTypedArray()
|
||||
}
|
||||
private external fun getInstalledGamePathsImpl(): Array<String?>
|
||||
|
||||
// Create the config.ini file.
|
||||
external fun createConfigFile()
|
||||
|
|
@ -230,6 +251,13 @@ object NativeLibrary {
|
|||
external fun playTimeManagerGetPlayTime(titleId: Long): Long
|
||||
external fun playTimeManagerGetCurrentTitleId(): Long
|
||||
|
||||
private external fun uninstallTitle(titleId: Long, mediaType: Int): Boolean
|
||||
fun uninstallTitle(titleId: Long, mediaType: Game.MediaType): Boolean {
|
||||
return uninstallTitle(titleId, mediaType.value)
|
||||
}
|
||||
|
||||
external fun nativeFileExists(path: String): Boolean
|
||||
|
||||
private var coreErrorAlertResult = false
|
||||
private val coreErrorAlertLock = Object()
|
||||
|
||||
|
|
@ -691,34 +719,43 @@ object NativeLibrary {
|
|||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun getUserDirectory(uriOverride: Uri? = null): String {
|
||||
fun getNativePath(uri: Uri): String {
|
||||
BuildUtil.assertNotGooglePlay()
|
||||
|
||||
val preferences: SharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
|
||||
|
||||
val dirSep = "/"
|
||||
val udUri = uriOverride ?:
|
||||
preferences.getString("CITRA_DIRECTORY", "")!!.toUri()
|
||||
val udPathSegment = udUri.lastPathSegment!!
|
||||
val udVirtualPath = udPathSegment.substringAfter(":")
|
||||
|
||||
if (udPathSegment.startsWith("primary:")) { // User directory is located in primary storage
|
||||
val uriString = uri.toString()
|
||||
if (!uriString.contains(":")) { // These raw URIs happen when generating the game list. Why?
|
||||
return uriString
|
||||
}
|
||||
|
||||
val pathSegment = uri.lastPathSegment ?: return ""
|
||||
val virtualPath = pathSegment.substringAfter(":")
|
||||
|
||||
if (pathSegment.startsWith("primary:")) { // User directory is located in primary storage
|
||||
val primaryStoragePath = Environment.getExternalStorageDirectory().absolutePath
|
||||
return primaryStoragePath + dirSep + udVirtualPath + dirSep
|
||||
return primaryStoragePath + dirSep + virtualPath
|
||||
} else { // User directory probably located on a removable storage device
|
||||
val storageIdString = udPathSegment.substringBefore(":")
|
||||
val udRemovablePath = RemovableStorageHelper.getRemovableStoragePath(storageIdString)
|
||||
val storageIdString = pathSegment.substringBefore(":")
|
||||
val removablePath = RemovableStorageHelper.getRemovableStoragePath(CitraApplication.appContext, storageIdString)
|
||||
|
||||
if (udRemovablePath == null) {
|
||||
if (removablePath == null) {
|
||||
android.util.Log.e("NativeLibrary",
|
||||
"Unknown mount location for storage device '$storageIdString' (URI: $udUri)"
|
||||
"Unknown mount location for storage device '$storageIdString' (URI: $uri)"
|
||||
)
|
||||
return ""
|
||||
}
|
||||
return udRemovablePath + dirSep + udVirtualPath + dirSep
|
||||
return removablePath + dirSep + virtualPath
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun getUserDirectory(): String {
|
||||
val preferences: SharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
|
||||
val userDirectoryUri = preferences.getString("CITRA_DIRECTORY", "")!!.toUri()
|
||||
return getNativePath(userDirectoryUri)
|
||||
}
|
||||
|
||||
@Keep
|
||||
|
|
|
|||
|
|
@ -267,36 +267,28 @@ class EmulationActivity : AppCompatActivity() {
|
|||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
val button =
|
||||
preferences.getInt(InputBindingSetting.getInputButtonKey(event.keyCode), event.keyCode)
|
||||
val action: Int = when (event.action) {
|
||||
when (event.action) {
|
||||
KeyEvent.ACTION_DOWN -> {
|
||||
hotkeyUtility.handleHotkey(button)
|
||||
|
||||
// On some devices, the back gesture / button press is not intercepted by androidx
|
||||
// and fails to open the emulation menu. So we're stuck running deprecated code to
|
||||
// cover for either a fault on androidx's side or in OEM skins (MIUI at least)
|
||||
|
||||
if (event.keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
// If the hotkey is pressed, we don't want to open the drawer
|
||||
if (!hotkeyUtility.HotkeyIsPressed) {
|
||||
if (!hotkeyUtility.hotkeyIsPressed) {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Normal key events.
|
||||
NativeLibrary.ButtonState.PRESSED
|
||||
return hotkeyUtility.handleKeyPress(event)
|
||||
}
|
||||
|
||||
KeyEvent.ACTION_UP -> {
|
||||
hotkeyUtility.HotkeyIsPressed = false
|
||||
NativeLibrary.ButtonState.RELEASED
|
||||
return hotkeyUtility.handleKeyRelease(event)
|
||||
}
|
||||
else -> {
|
||||
return false;
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
val input = event.device
|
||||
?: // Controller was disconnected
|
||||
return false
|
||||
return NativeLibrary.onGamePadEvent(input.descriptor, button, action)
|
||||
}
|
||||
|
||||
private fun onAmiiboSelected(selectedFile: String) {
|
||||
|
|
|
|||
|
|
@ -54,8 +54,10 @@ import org.citra.citra_emu.databinding.DialogShortcutBinding
|
|||
import org.citra.citra_emu.features.cheats.ui.CheatsFragmentDirections
|
||||
import org.citra.citra_emu.fragments.IndeterminateProgressDialogFragment
|
||||
import org.citra.citra_emu.model.Game
|
||||
import org.citra.citra_emu.utils.BuildUtil
|
||||
import org.citra.citra_emu.utils.FileUtil
|
||||
import org.citra.citra_emu.utils.GameIconUtils
|
||||
import org.citra.citra_emu.utils.Log
|
||||
import org.citra.citra_emu.viewmodel.GamesViewModel
|
||||
|
||||
class GameAdapter(
|
||||
|
|
@ -136,7 +138,7 @@ class GameAdapter(
|
|||
val holder = view.tag as GameViewHolder
|
||||
gameExists(holder)
|
||||
|
||||
if (holder.game.titleId == 0L) {
|
||||
if (!holder.game.valid) {
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.properties)
|
||||
.setMessage(R.string.properties_not_loaded)
|
||||
|
|
@ -153,12 +155,21 @@ class GameAdapter(
|
|||
if (holder.game.isInstalled) {
|
||||
return true
|
||||
}
|
||||
|
||||
val gameExists = DocumentFile.fromSingleUri(
|
||||
CitraApplication.appContext,
|
||||
Uri.parse(holder.game.path)
|
||||
)?.exists() == true
|
||||
val path = holder.game.path
|
||||
val pathUri = path.toUri()
|
||||
var gameExists: Boolean
|
||||
if (BuildUtil.isGooglePlayBuild || FileUtil.isNativePath(path)) {
|
||||
gameExists =
|
||||
DocumentFile.fromSingleUri(
|
||||
CitraApplication.appContext,
|
||||
pathUri
|
||||
)?.exists() == true
|
||||
} else {
|
||||
val nativePath = NativeLibrary.getNativePath(pathUri)
|
||||
gameExists = NativeLibrary.nativeFileExists(nativePath)
|
||||
}
|
||||
return if (!gameExists) {
|
||||
Log.error("[GameAdapter] ROM file does not exist: $path")
|
||||
Toast.makeText(
|
||||
CitraApplication.appContext,
|
||||
R.string.loader_error_file_not_found,
|
||||
|
|
@ -323,14 +334,16 @@ class GameAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
val titleId = game.titleId
|
||||
val dlcTitleId = titleId or 0x8C00000000L
|
||||
val updateTitleId = titleId or 0xE00000000L
|
||||
|
||||
popup.setOnMenuItemClickListener { menuItem ->
|
||||
val uninstallAction: () -> Unit = {
|
||||
when (menuItem.itemId) {
|
||||
R.id.game_context_uninstall -> CitraApplication.documentsTree.deleteDocument(dirs.gameDir)
|
||||
R.id.game_context_uninstall_dlc -> FileUtil.deleteDocument(CitraApplication.documentsTree.folderUriHelper(dirs.dlcDir)
|
||||
.toString())
|
||||
R.id.game_context_uninstall_updates -> FileUtil.deleteDocument(CitraApplication.documentsTree.folderUriHelper(dirs.updatesDir)
|
||||
.toString())
|
||||
R.id.game_context_uninstall -> NativeLibrary.uninstallTitle(titleId, game.mediaType)
|
||||
R.id.game_context_uninstall_dlc -> NativeLibrary.uninstallTitle(dlcTitleId, Game.MediaType.SDMC)
|
||||
R.id.game_context_uninstall_updates -> NativeLibrary.uninstallTitle(updateTitleId, Game.MediaType.SDMC)
|
||||
}
|
||||
ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true)
|
||||
bottomSheetDialog.dismiss()
|
||||
|
|
@ -556,7 +569,9 @@ class GameAdapter(
|
|||
|
||||
private class DiffCallback : DiffUtil.ItemCallback<Game>() {
|
||||
override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||
return oldItem.titleId == newItem.titleId
|
||||
// The title is taken into account to support 3DSX, which all have the titleID 0.
|
||||
// This only works now because we always return the English title, adjust if that changes.
|
||||
return oldItem.titleId == newItem.titleId && oldItem.title == newItem.title
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import org.citra.citra_emu.NativeLibrary
|
|||
import org.citra.citra_emu.R
|
||||
import org.citra.citra_emu.features.settings.model.BooleanSetting
|
||||
import org.citra.citra_emu.features.settings.model.IntSetting
|
||||
import org.citra.citra_emu.features.settings.model.IntListSetting
|
||||
import org.citra.citra_emu.features.settings.model.Settings
|
||||
import org.citra.citra_emu.features.settings.utils.SettingsFile
|
||||
import org.citra.citra_emu.utils.EmulationMenuSettings
|
||||
|
|
@ -31,8 +32,16 @@ class ScreenAdjustmentUtil(
|
|||
BooleanSetting.SWAP_SCREEN.boolean = isEnabled
|
||||
settings.saveSetting(BooleanSetting.SWAP_SCREEN, SettingsFile.FILE_NAME_CONFIG)
|
||||
}
|
||||
|
||||
fun cycleLayouts() {
|
||||
val landscapeValues = context.resources.getIntArray(R.array.landscapeValues)
|
||||
|
||||
val landscapeLayoutsToCycle = IntListSetting.LAYOUTS_TO_CYCLE.list;
|
||||
val landscapeValues =
|
||||
if (landscapeLayoutsToCycle.isNotEmpty())
|
||||
landscapeLayoutsToCycle.toIntArray()
|
||||
else context.resources.getIntArray(
|
||||
R.array.landscapeValues
|
||||
)
|
||||
val portraitValues = context.resources.getIntArray(R.array.portraitValues)
|
||||
|
||||
if (NativeLibrary.isPortraitMode) {
|
||||
|
|
|
|||
|
|
@ -11,5 +11,6 @@ enum class Hotkey(val button: Int) {
|
|||
PAUSE_OR_RESUME(10004),
|
||||
QUICKSAVE(10005),
|
||||
QUICKLOAD(10006),
|
||||
TURBO_LIMIT(10007);
|
||||
TURBO_LIMIT(10007),
|
||||
ENABLE(10008);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,50 +5,140 @@
|
|||
package org.citra.citra_emu.features.hotkeys
|
||||
|
||||
import android.content.Context
|
||||
import android.view.KeyEvent
|
||||
import android.widget.Toast
|
||||
import androidx.preference.PreferenceManager
|
||||
import org.citra.citra_emu.CitraApplication
|
||||
import org.citra.citra_emu.NativeLibrary
|
||||
import org.citra.citra_emu.R
|
||||
import org.citra.citra_emu.utils.EmulationLifecycleUtil
|
||||
import org.citra.citra_emu.utils.TurboHelper
|
||||
import org.citra.citra_emu.display.ScreenAdjustmentUtil
|
||||
import org.citra.citra_emu.features.settings.model.view.InputBindingSetting
|
||||
import org.citra.citra_emu.features.settings.model.Settings
|
||||
|
||||
class HotkeyUtility(
|
||||
private val screenAdjustmentUtil: ScreenAdjustmentUtil,
|
||||
private val context: Context) {
|
||||
private val context: Context
|
||||
) {
|
||||
|
||||
private val hotkeyButtons = Hotkey.entries.map { it.button }
|
||||
var HotkeyIsPressed = false
|
||||
private var hotkeyIsEnabled = false
|
||||
var hotkeyIsPressed = false
|
||||
private val currentlyPressedButtons = mutableSetOf<Int>()
|
||||
|
||||
fun handleKeyPress(keyEvent: KeyEvent): Boolean {
|
||||
var handled = false
|
||||
val buttonSet = InputBindingSetting.getButtonSet(keyEvent)
|
||||
val enableButton =
|
||||
PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
|
||||
.getString(Settings.HOTKEY_ENABLE, "")
|
||||
val thisKeyIsEnableButton = buttonSet.contains(Hotkey.ENABLE.button)
|
||||
val thisKeyIsHotkey =
|
||||
!thisKeyIsEnableButton && Hotkey.entries.any { buttonSet.contains(it.button) }
|
||||
hotkeyIsEnabled = hotkeyIsEnabled || enableButton == "" || thisKeyIsEnableButton
|
||||
|
||||
// Now process all internal buttons associated with this keypress
|
||||
for (button in buttonSet) {
|
||||
currentlyPressedButtons.add(button)
|
||||
//option 1 - this is the enable command, which was already handled
|
||||
if (button == Hotkey.ENABLE.button) {
|
||||
handled = true
|
||||
}
|
||||
// option 2 - this is a different hotkey command
|
||||
else if (hotkeyButtons.contains(button)) {
|
||||
if (hotkeyIsEnabled) {
|
||||
handled = handleHotkey(button) || handled
|
||||
}
|
||||
}
|
||||
// option 3 - this is a normal key
|
||||
else {
|
||||
// if this key press is ALSO associated with a hotkey that will process, skip
|
||||
// the normal key event.
|
||||
if (!thisKeyIsHotkey || !hotkeyIsEnabled) {
|
||||
handled = NativeLibrary.onGamePadEvent(
|
||||
keyEvent.device.descriptor,
|
||||
button,
|
||||
NativeLibrary.ButtonState.PRESSED
|
||||
) || handled
|
||||
}
|
||||
}
|
||||
}
|
||||
return handled
|
||||
}
|
||||
|
||||
fun handleKeyRelease(keyEvent: KeyEvent): Boolean {
|
||||
var handled = false
|
||||
val buttonSet = InputBindingSetting.getButtonSet(keyEvent)
|
||||
val thisKeyIsEnableButton = buttonSet.contains(Hotkey.ENABLE.button)
|
||||
val thisKeyIsHotkey =
|
||||
!thisKeyIsEnableButton && Hotkey.entries.any { buttonSet.contains(it.button) }
|
||||
if (thisKeyIsEnableButton) {
|
||||
handled = true; hotkeyIsEnabled = false
|
||||
}
|
||||
|
||||
for (button in buttonSet) {
|
||||
// this is a hotkey button
|
||||
if (hotkeyButtons.contains(button)) {
|
||||
currentlyPressedButtons.remove(button)
|
||||
if (!currentlyPressedButtons.any { hotkeyButtons.contains(it) }) {
|
||||
// all hotkeys are no longer pressed
|
||||
hotkeyIsPressed = false
|
||||
}
|
||||
} else {
|
||||
// if this key ALSO sends a hotkey command that we already/will handle,
|
||||
// or if we did not register the press of this button, e.g. if this key
|
||||
// was also a hotkey pressed after enable, but released after enable button release, then
|
||||
// skip the normal key event
|
||||
if ((!thisKeyIsHotkey || !hotkeyIsEnabled) && currentlyPressedButtons.contains(
|
||||
button
|
||||
)
|
||||
) {
|
||||
handled = NativeLibrary.onGamePadEvent(
|
||||
keyEvent.device.descriptor,
|
||||
button,
|
||||
NativeLibrary.ButtonState.RELEASED
|
||||
) || handled
|
||||
currentlyPressedButtons.remove(button)
|
||||
}
|
||||
}
|
||||
}
|
||||
return handled
|
||||
}
|
||||
|
||||
fun handleHotkey(bindedButton: Int): Boolean {
|
||||
if(hotkeyButtons.contains(bindedButton)) {
|
||||
when (bindedButton) {
|
||||
Hotkey.SWAP_SCREEN.button -> screenAdjustmentUtil.swapScreen()
|
||||
Hotkey.CYCLE_LAYOUT.button -> screenAdjustmentUtil.cycleLayouts()
|
||||
Hotkey.CLOSE_GAME.button -> EmulationLifecycleUtil.closeGame()
|
||||
Hotkey.PAUSE_OR_RESUME.button -> EmulationLifecycleUtil.pauseOrResume()
|
||||
Hotkey.TURBO_LIMIT.button -> TurboHelper.toggleTurbo(true)
|
||||
Hotkey.QUICKSAVE.button -> {
|
||||
NativeLibrary.saveState(NativeLibrary.QUICKSAVE_SLOT)
|
||||
Toast.makeText(context,
|
||||
context.getString(R.string.saving),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
Hotkey.QUICKLOAD.button -> {
|
||||
val wasLoaded = NativeLibrary.loadStateIfAvailable(NativeLibrary.QUICKSAVE_SLOT)
|
||||
val stringRes = if(wasLoaded) {
|
||||
R.string.loading
|
||||
} else {
|
||||
R.string.quickload_not_found
|
||||
}
|
||||
Toast.makeText(context,
|
||||
context.getString(stringRes),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
else -> {}
|
||||
when (bindedButton) {
|
||||
Hotkey.SWAP_SCREEN.button -> screenAdjustmentUtil.swapScreen()
|
||||
Hotkey.CYCLE_LAYOUT.button -> screenAdjustmentUtil.cycleLayouts()
|
||||
Hotkey.CLOSE_GAME.button -> EmulationLifecycleUtil.closeGame()
|
||||
Hotkey.PAUSE_OR_RESUME.button -> EmulationLifecycleUtil.pauseOrResume()
|
||||
Hotkey.TURBO_LIMIT.button -> TurboHelper.toggleTurbo(true)
|
||||
Hotkey.QUICKSAVE.button -> {
|
||||
NativeLibrary.saveState(NativeLibrary.QUICKSAVE_SLOT)
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.saving),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
HotkeyIsPressed = true
|
||||
return true
|
||||
|
||||
Hotkey.QUICKLOAD.button -> {
|
||||
val wasLoaded = NativeLibrary.loadStateIfAvailable(NativeLibrary.QUICKSAVE_SLOT)
|
||||
val stringRes = if (wasLoaded) {
|
||||
R.string.loading
|
||||
} else {
|
||||
R.string.quickload_not_found
|
||||
}
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(stringRes),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
return false
|
||||
hotkeyIsPressed = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package org.citra.citra_emu.features.settings
|
||||
|
||||
// This list should mirror the list in GenerateSettingKeys.cmake,
|
||||
// specifically the Shared and Android setting keys.
|
||||
@Suppress("KotlinJniMissingFunction", "FunctionName")
|
||||
object SettingKeys {
|
||||
// Shared
|
||||
external fun use_artic_base_controller(): String
|
||||
external fun use_cpu_jit(): String
|
||||
external fun cpu_clock_percentage(): String
|
||||
external fun is_new_3ds(): String
|
||||
external fun lle_applets(): String
|
||||
external fun deterministic_async_operations(): String
|
||||
external fun enable_required_online_lle_modules(): String
|
||||
external fun use_virtual_sd(): String
|
||||
external fun compress_cia_installs(): String
|
||||
external fun region_value(): String
|
||||
external fun init_clock(): String
|
||||
external fun init_time(): String
|
||||
external fun init_ticks_type(): String
|
||||
external fun init_ticks_override(): String
|
||||
external fun plugin_loader(): String
|
||||
external fun allow_plugin_loader(): String
|
||||
external fun steps_per_hour(): String
|
||||
external fun apply_region_free_patch(): String
|
||||
external fun graphics_api(): String
|
||||
external fun use_gles(): String
|
||||
external fun renderer_debug(): String
|
||||
external fun spirv_shader_gen(): String
|
||||
external fun disable_spirv_optimizer(): String
|
||||
external fun async_shader_compilation(): String
|
||||
external fun async_presentation(): String
|
||||
external fun use_hw_shader(): String
|
||||
external fun use_disk_shader_cache(): String
|
||||
external fun shaders_accurate_mul(): String
|
||||
external fun use_vsync(): String
|
||||
external fun use_shader_jit(): String
|
||||
external fun resolution_factor(): String
|
||||
external fun frame_limit(): String
|
||||
external fun turbo_limit(): String
|
||||
external fun texture_filter(): String
|
||||
external fun texture_sampling(): String
|
||||
external fun delay_game_render_thread_us(): String
|
||||
external fun layout_option(): String
|
||||
external fun swap_screen(): String
|
||||
external fun upright_screen(): String
|
||||
external fun secondary_display_layout(): String
|
||||
external fun large_screen_proportion(): String
|
||||
external fun screen_gap(): String
|
||||
external fun small_screen_position(): String
|
||||
external fun custom_top_x(): String
|
||||
external fun custom_top_y(): String
|
||||
external fun custom_top_width(): String
|
||||
external fun custom_top_height(): String
|
||||
external fun custom_bottom_x(): String
|
||||
external fun custom_bottom_y(): String
|
||||
external fun custom_bottom_width(): String
|
||||
external fun custom_bottom_height(): String
|
||||
external fun custom_second_layer_opacity(): String
|
||||
external fun aspect_ratio(): String
|
||||
external fun portrait_layout_option(): String
|
||||
external fun custom_portrait_top_x(): String
|
||||
external fun custom_portrait_top_y(): String
|
||||
external fun custom_portrait_top_width(): String
|
||||
external fun custom_portrait_top_height(): String
|
||||
external fun custom_portrait_bottom_x(): String
|
||||
external fun custom_portrait_bottom_y(): String
|
||||
external fun custom_portrait_bottom_width(): String
|
||||
external fun custom_portrait_bottom_height(): String
|
||||
external fun bg_red(): String
|
||||
external fun bg_green(): String
|
||||
external fun bg_blue(): String
|
||||
external fun render_3d(): String
|
||||
external fun factor_3d(): String
|
||||
external fun swap_eyes_3d(): String
|
||||
external fun render_3d_which_display(): String
|
||||
external fun cardboard_screen_size(): String
|
||||
external fun cardboard_x_shift(): String
|
||||
external fun cardboard_y_shift(): String
|
||||
external fun filter_mode(): String
|
||||
external fun pp_shader_name(): String
|
||||
external fun anaglyph_shader_name(): String
|
||||
external fun dump_textures(): String
|
||||
external fun custom_textures(): String
|
||||
external fun preload_textures(): String
|
||||
external fun async_custom_loading(): String
|
||||
external fun disable_right_eye_render(): String
|
||||
external fun audio_emulation(): String
|
||||
external fun enable_audio_stretching(): String
|
||||
external fun enable_realtime_audio(): String
|
||||
external fun volume(): String
|
||||
external fun output_type(): String
|
||||
external fun output_device(): String
|
||||
external fun input_type(): String
|
||||
external fun input_device(): String
|
||||
external fun delay_start_for_lle_modules(): String
|
||||
external fun use_gdbstub(): String
|
||||
external fun gdbstub_port(): String
|
||||
external fun instant_debug_log(): String
|
||||
external fun enable_rpc_server(): String
|
||||
external fun toggle_unique_data_console_type(): String
|
||||
external fun log_filter(): String
|
||||
external fun log_regex_filter(): String
|
||||
external fun use_integer_scaling(): String
|
||||
external fun layouts_to_cycle(): String
|
||||
external fun camera_inner_flip(): String
|
||||
external fun camera_outer_left_flip(): String
|
||||
external fun camera_outer_right_flip(): String
|
||||
external fun camera_inner_name(): String
|
||||
external fun camera_inner_config(): String
|
||||
external fun camera_outer_left_name(): String
|
||||
external fun camera_outer_left_config(): String
|
||||
external fun camera_outer_right_name(): String
|
||||
external fun camera_outer_right_config(): String
|
||||
external fun last_artic_base_addr(): String
|
||||
external fun motion_device(): String
|
||||
external fun touch_device(): String
|
||||
external fun udp_input_address(): String
|
||||
external fun udp_input_port(): String
|
||||
external fun udp_pad_index(): String
|
||||
external fun record_frame_times(): String
|
||||
|
||||
// Android
|
||||
external fun expand_to_cutout_area(): String
|
||||
external fun performance_overlay_enable(): String
|
||||
external fun performance_overlay_show_fps(): String
|
||||
external fun performance_overlay_show_frame_time(): String
|
||||
external fun performance_overlay_show_speed(): String
|
||||
external fun performance_overlay_show_app_ram_usage(): String
|
||||
external fun performance_overlay_show_available_ram(): String
|
||||
external fun performance_overlay_show_battery_temp(): String
|
||||
external fun performance_overlay_background(): String
|
||||
external fun use_frame_limit(): String
|
||||
external fun android_hide_images(): String
|
||||
external fun screen_orientation(): String
|
||||
external fun performance_overlay_position(): String
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package org.citra.citra_emu.features.settings.model
|
||||
|
||||
interface AbstractListSetting<E> : AbstractSetting {
|
||||
var list: List<E>
|
||||
}
|
||||
|
|
@ -4,56 +4,59 @@
|
|||
|
||||
package org.citra.citra_emu.features.settings.model
|
||||
|
||||
import org.citra.citra_emu.features.settings.SettingKeys
|
||||
|
||||
enum class BooleanSetting(
|
||||
override val key: String,
|
||||
override val section: String,
|
||||
override val defaultValue: Boolean
|
||||
) : AbstractBooleanSetting {
|
||||
EXPAND_TO_CUTOUT_AREA("expand_to_cutout_area", Settings.SECTION_LAYOUT, false),
|
||||
SPIRV_SHADER_GEN("spirv_shader_gen", Settings.SECTION_RENDERER, true),
|
||||
ASYNC_SHADERS("async_shader_compilation", Settings.SECTION_RENDERER, false),
|
||||
DISABLE_SPIRV_OPTIMIZER("disable_spirv_optimizer", Settings.SECTION_RENDERER, true),
|
||||
PLUGIN_LOADER("plugin_loader", Settings.SECTION_SYSTEM, false),
|
||||
ALLOW_PLUGIN_LOADER("allow_plugin_loader", Settings.SECTION_SYSTEM, true),
|
||||
SWAP_SCREEN("swap_screen", Settings.SECTION_LAYOUT, false),
|
||||
INSTANT_DEBUG_LOG("instant_debug_log", Settings.SECTION_DEBUG, false),
|
||||
ENABLE_RPC_SERVER("enable_rpc_server", Settings.SECTION_DEBUG, false),
|
||||
CUSTOM_LAYOUT("custom_layout",Settings.SECTION_LAYOUT,false),
|
||||
SWAP_EYES_3D("swap_eyes_3d",Settings.SECTION_RENDERER,false),
|
||||
PERF_OVERLAY_ENABLE("performance_overlay_enable", Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_FPS("performance_overlay_show_fps", Settings.SECTION_LAYOUT, true),
|
||||
PERF_OVERLAY_SHOW_FRAMETIME("performance_overlay_show_frame_time", Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_SPEED("performance_overlay_show_speed", Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_APP_RAM_USAGE("performance_overlay_show_app_ram_usage", Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_AVAILABLE_RAM("performance_overlay_show_available_ram", Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_BATTERY_TEMP("performance_overlay_show_battery_temp", Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_BACKGROUND("performance_overlay_background", Settings.SECTION_LAYOUT, false),
|
||||
DELAY_START_LLE_MODULES("delay_start_for_lle_modules", Settings.SECTION_DEBUG, true),
|
||||
DETERMINISTIC_ASYNC_OPERATIONS("deterministic_async_operations", Settings.SECTION_DEBUG, false),
|
||||
REQUIRED_ONLINE_LLE_MODULES("enable_required_online_lle_modules", Settings.SECTION_SYSTEM, false),
|
||||
LLE_APPLETS("lle_applets", Settings.SECTION_SYSTEM, false),
|
||||
NEW_3DS("is_new_3ds", Settings.SECTION_SYSTEM, true),
|
||||
LINEAR_FILTERING("filter_mode", Settings.SECTION_RENDERER, true),
|
||||
SHADERS_ACCURATE_MUL("shaders_accurate_mul", Settings.SECTION_RENDERER, false),
|
||||
DISK_SHADER_CACHE("use_disk_shader_cache", Settings.SECTION_RENDERER, true),
|
||||
DUMP_TEXTURES("dump_textures", Settings.SECTION_UTILITY, false),
|
||||
CUSTOM_TEXTURES("custom_textures", Settings.SECTION_UTILITY, false),
|
||||
ASYNC_CUSTOM_LOADING("async_custom_loading", Settings.SECTION_UTILITY, true),
|
||||
PRELOAD_TEXTURES("preload_textures", Settings.SECTION_UTILITY, false),
|
||||
ENABLE_AUDIO_STRETCHING("enable_audio_stretching", Settings.SECTION_AUDIO, true),
|
||||
ENABLE_REALTIME_AUDIO("enable_realtime_audio", Settings.SECTION_AUDIO, false),
|
||||
CPU_JIT("use_cpu_jit", Settings.SECTION_CORE, true),
|
||||
HW_SHADER("use_hw_shader", Settings.SECTION_RENDERER, true),
|
||||
SHADER_JIT("use_shader_jit", Settings.SECTION_RENDERER, true),
|
||||
VSYNC("use_vsync", Settings.SECTION_RENDERER, false),
|
||||
USE_FRAME_LIMIT("use_frame_limit", Settings.SECTION_RENDERER, true),
|
||||
DEBUG_RENDERER("renderer_debug", Settings.SECTION_DEBUG, false),
|
||||
DISABLE_RIGHT_EYE_RENDER("disable_right_eye_render", Settings.SECTION_RENDERER, false),
|
||||
USE_ARTIC_BASE_CONTROLLER("use_artic_base_controller", Settings.SECTION_CONTROLS, false),
|
||||
UPRIGHT_SCREEN("upright_screen", Settings.SECTION_LAYOUT, false),
|
||||
COMPRESS_INSTALLED_CIA_CONTENT("compress_cia_installs", Settings.SECTION_STORAGE, false),
|
||||
ANDROID_HIDE_IMAGES("android_hide_images", Settings.SECTION_CORE, false),
|
||||
APPLY_REGION_FREE_PATCH("apply_region_free_patch", Settings.SECTION_SYSTEM, true);
|
||||
EXPAND_TO_CUTOUT_AREA(SettingKeys.expand_to_cutout_area(), Settings.SECTION_LAYOUT, false),
|
||||
SPIRV_SHADER_GEN(SettingKeys.spirv_shader_gen(), Settings.SECTION_RENDERER, true),
|
||||
ASYNC_SHADERS(SettingKeys.async_shader_compilation(), Settings.SECTION_RENDERER, false),
|
||||
DISABLE_SPIRV_OPTIMIZER(SettingKeys.disable_spirv_optimizer(), Settings.SECTION_RENDERER, true),
|
||||
PLUGIN_LOADER(SettingKeys.plugin_loader(), Settings.SECTION_SYSTEM, false),
|
||||
ALLOW_PLUGIN_LOADER(SettingKeys.allow_plugin_loader(), Settings.SECTION_SYSTEM, true),
|
||||
SWAP_SCREEN(SettingKeys.swap_screen(), Settings.SECTION_LAYOUT, false),
|
||||
INSTANT_DEBUG_LOG(SettingKeys.instant_debug_log(), Settings.SECTION_DEBUG, false),
|
||||
ENABLE_RPC_SERVER(SettingKeys.enable_rpc_server(), Settings.SECTION_DEBUG, false),
|
||||
TOGGLE_UNIQUE_DATA_CONSOLE_TYPE(SettingKeys.toggle_unique_data_console_type(), Settings.SECTION_DEBUG, false),
|
||||
SWAP_EYES_3D(SettingKeys.swap_eyes_3d(),Settings.SECTION_RENDERER, false),
|
||||
PERF_OVERLAY_ENABLE(SettingKeys.performance_overlay_enable(), Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_FPS(SettingKeys.performance_overlay_show_fps(), Settings.SECTION_LAYOUT, true),
|
||||
PERF_OVERLAY_SHOW_FRAMETIME(SettingKeys.performance_overlay_show_frame_time(), Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_SPEED(SettingKeys.performance_overlay_show_speed(), Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_APP_RAM_USAGE(SettingKeys.performance_overlay_show_app_ram_usage(), Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_AVAILABLE_RAM(SettingKeys.performance_overlay_show_available_ram(), Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_SHOW_BATTERY_TEMP(SettingKeys.performance_overlay_show_battery_temp(), Settings.SECTION_LAYOUT, false),
|
||||
PERF_OVERLAY_BACKGROUND(SettingKeys.performance_overlay_background(), Settings.SECTION_LAYOUT, false),
|
||||
DELAY_START_LLE_MODULES(SettingKeys.delay_start_for_lle_modules(), Settings.SECTION_DEBUG, true),
|
||||
DETERMINISTIC_ASYNC_OPERATIONS(SettingKeys.deterministic_async_operations(), Settings.SECTION_DEBUG, false),
|
||||
REQUIRED_ONLINE_LLE_MODULES(SettingKeys.enable_required_online_lle_modules(), Settings.SECTION_SYSTEM, false),
|
||||
LLE_APPLETS(SettingKeys.lle_applets(), Settings.SECTION_SYSTEM, false),
|
||||
NEW_3DS(SettingKeys.is_new_3ds(), Settings.SECTION_SYSTEM, true),
|
||||
LINEAR_FILTERING(SettingKeys.filter_mode(), Settings.SECTION_RENDERER, true),
|
||||
SHADERS_ACCURATE_MUL(SettingKeys.shaders_accurate_mul(), Settings.SECTION_RENDERER, false),
|
||||
DISK_SHADER_CACHE(SettingKeys.use_disk_shader_cache(), Settings.SECTION_RENDERER, true),
|
||||
DUMP_TEXTURES(SettingKeys.dump_textures(), Settings.SECTION_UTILITY, false),
|
||||
CUSTOM_TEXTURES(SettingKeys.custom_textures(), Settings.SECTION_UTILITY, false),
|
||||
ASYNC_CUSTOM_LOADING(SettingKeys.async_custom_loading(), Settings.SECTION_UTILITY, true),
|
||||
PRELOAD_TEXTURES(SettingKeys.preload_textures(), Settings.SECTION_UTILITY, false),
|
||||
ENABLE_AUDIO_STRETCHING(SettingKeys.enable_audio_stretching(), Settings.SECTION_AUDIO, true),
|
||||
ENABLE_REALTIME_AUDIO(SettingKeys.enable_realtime_audio(), Settings.SECTION_AUDIO, false),
|
||||
CPU_JIT(SettingKeys.use_cpu_jit(), Settings.SECTION_CORE, true),
|
||||
HW_SHADER(SettingKeys.use_hw_shader(), Settings.SECTION_RENDERER, true),
|
||||
SHADER_JIT(SettingKeys.use_shader_jit(), Settings.SECTION_RENDERER, true),
|
||||
VSYNC(SettingKeys.use_vsync(), Settings.SECTION_RENDERER, false),
|
||||
USE_FRAME_LIMIT(SettingKeys.use_frame_limit(), Settings.SECTION_RENDERER, true),
|
||||
DEBUG_RENDERER(SettingKeys.renderer_debug(), Settings.SECTION_DEBUG, false),
|
||||
DISABLE_RIGHT_EYE_RENDER(SettingKeys.disable_right_eye_render(), Settings.SECTION_RENDERER, false),
|
||||
USE_ARTIC_BASE_CONTROLLER(SettingKeys.use_artic_base_controller(), Settings.SECTION_CONTROLS, false),
|
||||
UPRIGHT_SCREEN(SettingKeys.upright_screen(), Settings.SECTION_LAYOUT, false),
|
||||
COMPRESS_INSTALLED_CIA_CONTENT(SettingKeys.compress_cia_installs(), Settings.SECTION_STORAGE, false),
|
||||
ANDROID_HIDE_IMAGES(SettingKeys.android_hide_images(), Settings.SECTION_MISC, false),
|
||||
APPLY_REGION_FREE_PATCH(SettingKeys.apply_region_free_patch(), Settings.SECTION_SYSTEM, true),
|
||||
USE_INTEGER_SCALING(SettingKeys.use_integer_scaling(), Settings.SECTION_RENDERER, false);
|
||||
|
||||
override var boolean: Boolean = defaultValue
|
||||
|
||||
|
|
@ -80,6 +83,7 @@ enum class BooleanSetting(
|
|||
REQUIRED_ONLINE_LLE_MODULES,
|
||||
NEW_3DS,
|
||||
LLE_APPLETS,
|
||||
TOGGLE_UNIQUE_DATA_CONSOLE_TYPE,
|
||||
VSYNC,
|
||||
DEBUG_RENDERER,
|
||||
CPU_JIT,
|
||||
|
|
|
|||
|
|
@ -4,17 +4,18 @@
|
|||
|
||||
package org.citra.citra_emu.features.settings.model
|
||||
|
||||
import org.citra.citra_emu.features.settings.SettingKeys
|
||||
|
||||
enum class FloatSetting(
|
||||
override val key: String,
|
||||
override val section: String,
|
||||
override val defaultValue: Float
|
||||
) : AbstractFloatSetting {
|
||||
LARGE_SCREEN_PROPORTION("large_screen_proportion",Settings.SECTION_LAYOUT,2.25f),
|
||||
SECOND_SCREEN_OPACITY("custom_second_layer_opacity", Settings.SECTION_RENDERER, 100f),
|
||||
BACKGROUND_RED("bg_red", Settings.SECTION_RENDERER, 0f),
|
||||
BACKGROUND_BLUE("bg_blue", Settings.SECTION_RENDERER, 0f),
|
||||
BACKGROUND_GREEN("bg_green", Settings.SECTION_RENDERER, 0f),
|
||||
EMPTY_SETTING("", "", 0.0f);
|
||||
LARGE_SCREEN_PROPORTION(SettingKeys.large_screen_proportion(),Settings.SECTION_LAYOUT,2.25f),
|
||||
SECOND_SCREEN_OPACITY(SettingKeys.custom_second_layer_opacity(), Settings.SECTION_RENDERER, 100f),
|
||||
BACKGROUND_RED(SettingKeys.bg_red(), Settings.SECTION_RENDERER, 0f),
|
||||
BACKGROUND_BLUE(SettingKeys.bg_blue(), Settings.SECTION_RENDERER, 0f),
|
||||
BACKGROUND_GREEN(SettingKeys.bg_green(), Settings.SECTION_RENDERER, 0f);
|
||||
|
||||
override var float: Float = defaultValue
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package org.citra.citra_emu.features.settings.model
|
||||
|
||||
enum class IntListSetting(
|
||||
override val key: String,
|
||||
override val section: String,
|
||||
override val defaultValue: List<Int>,
|
||||
val canBeEmpty: Boolean = true
|
||||
) : AbstractListSetting<Int> {
|
||||
|
||||
LAYOUTS_TO_CYCLE("layouts_to_cycle", Settings.SECTION_LAYOUT, listOf(0, 1, 2, 3, 4, 5), canBeEmpty = false);
|
||||
|
||||
private var backingList: List<Int> = defaultValue
|
||||
private var lastValidList : List<Int> = defaultValue
|
||||
|
||||
override var list: List<Int>
|
||||
get() = backingList
|
||||
set(value) {
|
||||
if (!canBeEmpty && value.isEmpty()) {
|
||||
backingList = lastValidList
|
||||
} else {
|
||||
backingList = value
|
||||
lastValidList = value
|
||||
}
|
||||
}
|
||||
|
||||
override val valueAsString: String
|
||||
get() = list.joinToString()
|
||||
|
||||
|
||||
override val isRuntimeEditable: Boolean
|
||||
get() {
|
||||
for (setting in NOT_RUNTIME_EDITABLE) {
|
||||
if (setting == this) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val NOT_RUNTIME_EDITABLE: List<IntListSetting> = emptyList()
|
||||
|
||||
fun from(key: String): IntListSetting? =
|
||||
values().firstOrNull { it.key == key }
|
||||
|
||||
fun clear() = values().forEach { it.list = it.defaultValue }
|
||||
}
|
||||
}
|
||||
|
|
@ -4,57 +4,59 @@
|
|||
|
||||
package org.citra.citra_emu.features.settings.model
|
||||
|
||||
import org.citra.citra_emu.features.settings.SettingKeys
|
||||
|
||||
enum class IntSetting(
|
||||
override val key: String,
|
||||
override val section: String,
|
||||
override val defaultValue: Int
|
||||
) : AbstractIntSetting {
|
||||
FRAME_LIMIT("frame_limit", Settings.SECTION_RENDERER, 100),
|
||||
EMULATED_REGION("region_value", Settings.SECTION_SYSTEM, -1),
|
||||
INIT_CLOCK("init_clock", Settings.SECTION_SYSTEM, 0),
|
||||
CAMERA_INNER_FLIP("camera_inner_flip", Settings.SECTION_CAMERA, 0),
|
||||
CAMERA_OUTER_LEFT_FLIP("camera_outer_left_flip", Settings.SECTION_CAMERA, 0),
|
||||
CAMERA_OUTER_RIGHT_FLIP("camera_outer_right_flip", Settings.SECTION_CAMERA, 0),
|
||||
GRAPHICS_API("graphics_api", Settings.SECTION_RENDERER, 1),
|
||||
RESOLUTION_FACTOR("resolution_factor", Settings.SECTION_RENDERER, 1),
|
||||
STEREOSCOPIC_3D_MODE("render_3d", Settings.SECTION_RENDERER, 2),
|
||||
STEREOSCOPIC_3D_DEPTH("factor_3d", Settings.SECTION_RENDERER, 0),
|
||||
STEPS_PER_HOUR("steps_per_hour", Settings.SECTION_SYSTEM, 0),
|
||||
CARDBOARD_SCREEN_SIZE("cardboard_screen_size", Settings.SECTION_LAYOUT, 85),
|
||||
CARDBOARD_X_SHIFT("cardboard_x_shift", Settings.SECTION_LAYOUT, 0),
|
||||
CARDBOARD_Y_SHIFT("cardboard_y_shift", Settings.SECTION_LAYOUT, 0),
|
||||
SCREEN_LAYOUT("layout_option", Settings.SECTION_LAYOUT, 0),
|
||||
SMALL_SCREEN_POSITION("small_screen_position",Settings.SECTION_LAYOUT,0),
|
||||
LANDSCAPE_TOP_X("custom_top_x",Settings.SECTION_LAYOUT,0),
|
||||
LANDSCAPE_TOP_Y("custom_top_y",Settings.SECTION_LAYOUT,0),
|
||||
LANDSCAPE_TOP_WIDTH("custom_top_width",Settings.SECTION_LAYOUT,800),
|
||||
LANDSCAPE_TOP_HEIGHT("custom_top_height",Settings.SECTION_LAYOUT,480),
|
||||
LANDSCAPE_BOTTOM_X("custom_bottom_x",Settings.SECTION_LAYOUT,80),
|
||||
LANDSCAPE_BOTTOM_Y("custom_bottom_y",Settings.SECTION_LAYOUT,480),
|
||||
LANDSCAPE_BOTTOM_WIDTH("custom_bottom_width",Settings.SECTION_LAYOUT,640),
|
||||
LANDSCAPE_BOTTOM_HEIGHT("custom_bottom_height",Settings.SECTION_LAYOUT,480),
|
||||
SCREEN_GAP("screen_gap",Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_SCREEN_LAYOUT("portrait_layout_option",Settings.SECTION_LAYOUT,0),
|
||||
SECONDARY_DISPLAY_LAYOUT("secondary_display_layout",Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_TOP_X("custom_portrait_top_x",Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_TOP_Y("custom_portrait_top_y",Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_TOP_WIDTH("custom_portrait_top_width",Settings.SECTION_LAYOUT,800),
|
||||
PORTRAIT_TOP_HEIGHT("custom_portrait_top_height",Settings.SECTION_LAYOUT,480),
|
||||
PORTRAIT_BOTTOM_X("custom_portrait_bottom_x",Settings.SECTION_LAYOUT,80),
|
||||
PORTRAIT_BOTTOM_Y("custom_portrait_bottom_y",Settings.SECTION_LAYOUT,480),
|
||||
PORTRAIT_BOTTOM_WIDTH("custom_portrait_bottom_width",Settings.SECTION_LAYOUT,640),
|
||||
PORTRAIT_BOTTOM_HEIGHT("custom_portrait_bottom_height",Settings.SECTION_LAYOUT,480),
|
||||
AUDIO_INPUT_TYPE("input_type", Settings.SECTION_AUDIO, 0),
|
||||
CPU_CLOCK_SPEED("cpu_clock_percentage", Settings.SECTION_CORE, 100),
|
||||
TEXTURE_FILTER("texture_filter", Settings.SECTION_RENDERER, 0),
|
||||
TEXTURE_SAMPLING("texture_sampling", Settings.SECTION_RENDERER, 0),
|
||||
USE_FRAME_LIMIT("use_frame_limit", Settings.SECTION_RENDERER, 1),
|
||||
DELAY_RENDER_THREAD_US("delay_game_render_thread_us", Settings.SECTION_RENDERER, 0),
|
||||
ORIENTATION_OPTION("screen_orientation", Settings.SECTION_LAYOUT, 2),
|
||||
TURBO_LIMIT("turbo_limit", Settings.SECTION_CORE, 200),
|
||||
PERFORMANCE_OVERLAY_POSITION("performance_overlay_position", Settings.SECTION_LAYOUT, 0),
|
||||
RENDER_3D_WHICH_DISPLAY("render_3d_which_display",Settings.SECTION_RENDERER,0),
|
||||
ASPECT_RATIO("aspect_ratio", Settings.SECTION_LAYOUT, 0);
|
||||
FRAME_LIMIT(SettingKeys.frame_limit(), Settings.SECTION_RENDERER, 100),
|
||||
EMULATED_REGION(SettingKeys.region_value(), Settings.SECTION_SYSTEM, -1),
|
||||
INIT_CLOCK(SettingKeys.init_clock(), Settings.SECTION_SYSTEM, 0),
|
||||
CAMERA_INNER_FLIP(SettingKeys.camera_inner_flip(), Settings.SECTION_CAMERA, 0),
|
||||
CAMERA_OUTER_LEFT_FLIP(SettingKeys.camera_outer_left_flip(), Settings.SECTION_CAMERA, 0),
|
||||
CAMERA_OUTER_RIGHT_FLIP(SettingKeys.camera_outer_right_flip(), Settings.SECTION_CAMERA, 0),
|
||||
GRAPHICS_API(SettingKeys.graphics_api(), Settings.SECTION_RENDERER, 1),
|
||||
RESOLUTION_FACTOR(SettingKeys.resolution_factor(), Settings.SECTION_RENDERER, 1),
|
||||
STEREOSCOPIC_3D_MODE(SettingKeys.render_3d(), Settings.SECTION_RENDERER, 2),
|
||||
STEREOSCOPIC_3D_DEPTH(SettingKeys.factor_3d(), Settings.SECTION_RENDERER, 0),
|
||||
STEPS_PER_HOUR(SettingKeys.steps_per_hour(), Settings.SECTION_SYSTEM, 0),
|
||||
CARDBOARD_SCREEN_SIZE(SettingKeys.cardboard_screen_size(), Settings.SECTION_LAYOUT, 85),
|
||||
CARDBOARD_X_SHIFT(SettingKeys.cardboard_x_shift(), Settings.SECTION_LAYOUT, 0),
|
||||
CARDBOARD_Y_SHIFT(SettingKeys.cardboard_y_shift(), Settings.SECTION_LAYOUT, 0),
|
||||
SCREEN_LAYOUT(SettingKeys.layout_option(), Settings.SECTION_LAYOUT, 0),
|
||||
SMALL_SCREEN_POSITION(SettingKeys.small_screen_position(),Settings.SECTION_LAYOUT,0),
|
||||
LANDSCAPE_TOP_X(SettingKeys.custom_top_x(),Settings.SECTION_LAYOUT,0),
|
||||
LANDSCAPE_TOP_Y(SettingKeys.custom_top_y(),Settings.SECTION_LAYOUT,0),
|
||||
LANDSCAPE_TOP_WIDTH(SettingKeys.custom_top_width(),Settings.SECTION_LAYOUT,800),
|
||||
LANDSCAPE_TOP_HEIGHT(SettingKeys.custom_top_height(),Settings.SECTION_LAYOUT,480),
|
||||
LANDSCAPE_BOTTOM_X(SettingKeys.custom_bottom_x(),Settings.SECTION_LAYOUT,80),
|
||||
LANDSCAPE_BOTTOM_Y(SettingKeys.custom_bottom_y(),Settings.SECTION_LAYOUT,480),
|
||||
LANDSCAPE_BOTTOM_WIDTH(SettingKeys.custom_bottom_width(),Settings.SECTION_LAYOUT,640),
|
||||
LANDSCAPE_BOTTOM_HEIGHT(SettingKeys.custom_bottom_height(),Settings.SECTION_LAYOUT,480),
|
||||
SCREEN_GAP(SettingKeys.screen_gap(),Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_SCREEN_LAYOUT(SettingKeys.portrait_layout_option(),Settings.SECTION_LAYOUT,0),
|
||||
SECONDARY_DISPLAY_LAYOUT(SettingKeys.secondary_display_layout(),Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_TOP_X(SettingKeys.custom_portrait_top_x(),Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_TOP_Y(SettingKeys.custom_portrait_top_y(),Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_TOP_WIDTH(SettingKeys.custom_portrait_top_width(),Settings.SECTION_LAYOUT,800),
|
||||
PORTRAIT_TOP_HEIGHT(SettingKeys.custom_portrait_top_height(),Settings.SECTION_LAYOUT,480),
|
||||
PORTRAIT_BOTTOM_X(SettingKeys.custom_portrait_bottom_x(),Settings.SECTION_LAYOUT,80),
|
||||
PORTRAIT_BOTTOM_Y(SettingKeys.custom_portrait_bottom_y(),Settings.SECTION_LAYOUT,480),
|
||||
PORTRAIT_BOTTOM_WIDTH(SettingKeys.custom_portrait_bottom_width(),Settings.SECTION_LAYOUT,640),
|
||||
PORTRAIT_BOTTOM_HEIGHT(SettingKeys.custom_portrait_bottom_height(),Settings.SECTION_LAYOUT,480),
|
||||
AUDIO_INPUT_TYPE(SettingKeys.input_type(), Settings.SECTION_AUDIO, 0),
|
||||
CPU_CLOCK_SPEED(SettingKeys.cpu_clock_percentage(), Settings.SECTION_CORE, 100),
|
||||
TEXTURE_FILTER(SettingKeys.texture_filter(), Settings.SECTION_RENDERER, 0),
|
||||
TEXTURE_SAMPLING(SettingKeys.texture_sampling(), Settings.SECTION_RENDERER, 0),
|
||||
USE_FRAME_LIMIT(SettingKeys.use_frame_limit(), Settings.SECTION_RENDERER, 1),
|
||||
DELAY_RENDER_THREAD_US(SettingKeys.delay_game_render_thread_us(), Settings.SECTION_RENDERER, 0),
|
||||
ORIENTATION_OPTION(SettingKeys.screen_orientation(), Settings.SECTION_LAYOUT, 2),
|
||||
TURBO_LIMIT(SettingKeys.turbo_limit(), Settings.SECTION_CORE, 200),
|
||||
PERFORMANCE_OVERLAY_POSITION(SettingKeys.performance_overlay_position(), Settings.SECTION_LAYOUT, 0),
|
||||
RENDER_3D_WHICH_DISPLAY(SettingKeys.render_3d_which_display(),Settings.SECTION_RENDERER,0),
|
||||
ASPECT_RATIO(SettingKeys.aspect_ratio(), Settings.SECTION_LAYOUT, 0);
|
||||
|
||||
override var int: Int = defaultValue
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package org.citra.citra_emu.features.settings.model
|
||||
|
||||
import org.citra.citra_emu.features.settings.SettingKeys
|
||||
|
||||
enum class ScaledFloatSetting(
|
||||
override val key: String,
|
||||
override val section: String,
|
||||
override val defaultValue: Float,
|
||||
val scale: Int
|
||||
) : AbstractFloatSetting {
|
||||
AUDIO_VOLUME("volume", Settings.SECTION_AUDIO, 1.0f, 100);
|
||||
AUDIO_VOLUME(SettingKeys.volume(), Settings.SECTION_AUDIO, 1.0f, 100);
|
||||
|
||||
override var float: Float = defaultValue
|
||||
get() = field * scale
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ class Settings {
|
|||
const val SECTION_CUSTOM_PORTRAIT = "Custom Portrait Layout"
|
||||
const val SECTION_PERFORMANCE_OVERLAY = "Performance Overlay"
|
||||
const val SECTION_STORAGE = "Storage"
|
||||
const val SECTION_MISC = "Miscellaneous"
|
||||
|
||||
const val KEY_BUTTON_A = "button_a"
|
||||
const val KEY_BUTTON_B = "button_b"
|
||||
|
|
@ -135,6 +136,7 @@ class Settings {
|
|||
const val KEY_CSTICK_AXIS_HORIZONTAL = "cstick_axis_horizontal"
|
||||
const val KEY_DPAD_AXIS_VERTICAL = "dpad_axis_vertical"
|
||||
const val KEY_DPAD_AXIS_HORIZONTAL = "dpad_axis_horizontal"
|
||||
const val HOTKEY_ENABLE = "hotkey_enable"
|
||||
const val HOTKEY_SCREEN_SWAP = "hotkey_screen_swap"
|
||||
const val HOTKEY_CYCLE_LAYOUT = "hotkey_toggle_layout"
|
||||
const val HOTKEY_CLOSE_GAME = "hotkey_close_game"
|
||||
|
|
@ -202,6 +204,7 @@ class Settings {
|
|||
R.string.button_zr
|
||||
)
|
||||
val hotKeys = listOf(
|
||||
HOTKEY_ENABLE,
|
||||
HOTKEY_SCREEN_SWAP,
|
||||
HOTKEY_CYCLE_LAYOUT,
|
||||
HOTKEY_CLOSE_GAME,
|
||||
|
|
@ -211,6 +214,7 @@ class Settings {
|
|||
HOTKEY_TURBO_LIMIT
|
||||
)
|
||||
val hotkeyTitles = listOf(
|
||||
R.string.controller_hotkey_enable_button,
|
||||
R.string.emulation_swap_screens,
|
||||
R.string.emulation_cycle_landscape_layouts,
|
||||
R.string.emulation_close_game,
|
||||
|
|
@ -220,6 +224,7 @@ class Settings {
|
|||
R.string.turbo_limit_hotkey
|
||||
)
|
||||
|
||||
// TODO: Move these in with the other setting keys in GenerateSettingKeys.cmake
|
||||
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
|
||||
const val PREF_MATERIAL_YOU = "MaterialYouTheme"
|
||||
const val PREF_THEME_MODE = "ThemeMode"
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package org.citra.citra_emu.features.settings.model
|
||||
|
||||
import org.citra.citra_emu.features.settings.SettingKeys
|
||||
|
||||
enum class StringSetting(
|
||||
override val key: String,
|
||||
override val section: String,
|
||||
override val defaultValue: String
|
||||
) : AbstractStringSetting {
|
||||
INIT_TIME("init_time", Settings.SECTION_SYSTEM, "946731601"),
|
||||
CAMERA_INNER_NAME("camera_inner_name", Settings.SECTION_CAMERA, "ndk"),
|
||||
CAMERA_INNER_CONFIG("camera_inner_config", Settings.SECTION_CAMERA, "_front"),
|
||||
CAMERA_OUTER_LEFT_NAME("camera_outer_left_name", Settings.SECTION_CAMERA, "ndk"),
|
||||
CAMERA_OUTER_LEFT_CONFIG("camera_outer_left_config", Settings.SECTION_CAMERA, "_back"),
|
||||
CAMERA_OUTER_RIGHT_NAME("camera_outer_right_name", Settings.SECTION_CAMERA, "ndk"),
|
||||
CAMERA_OUTER_RIGHT_CONFIG("camera_outer_right_config", Settings.SECTION_CAMERA, "_back");
|
||||
INIT_TIME(SettingKeys.init_time(), Settings.SECTION_SYSTEM, "946731601"),
|
||||
CAMERA_INNER_NAME(SettingKeys.camera_inner_name(), Settings.SECTION_CAMERA, "ndk"),
|
||||
CAMERA_INNER_CONFIG(SettingKeys.camera_inner_config(), Settings.SECTION_CAMERA, "_front"),
|
||||
CAMERA_OUTER_LEFT_NAME(SettingKeys.camera_outer_left_name(), Settings.SECTION_CAMERA, "ndk"),
|
||||
CAMERA_OUTER_LEFT_CONFIG(SettingKeys.camera_outer_left_config(), Settings.SECTION_CAMERA, "_back"),
|
||||
CAMERA_OUTER_RIGHT_NAME(SettingKeys.camera_outer_right_name(), Settings.SECTION_CAMERA, "ndk"),
|
||||
CAMERA_OUTER_RIGHT_CONFIG(SettingKeys.camera_outer_right_config(), Settings.SECTION_CAMERA, "_back");
|
||||
|
||||
override var string: String = defaultValue
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.content.SharedPreferences
|
|||
import android.view.InputDevice
|
||||
import android.view.InputDevice.MotionRange
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.widget.Toast
|
||||
import androidx.preference.PreferenceManager
|
||||
import org.citra.citra_emu.CitraApplication
|
||||
|
|
@ -128,6 +129,7 @@ class InputBindingSetting(
|
|||
Settings.KEY_BUTTON_DOWN -> NativeLibrary.ButtonType.DPAD_DOWN
|
||||
Settings.KEY_BUTTON_LEFT -> NativeLibrary.ButtonType.DPAD_LEFT
|
||||
Settings.KEY_BUTTON_RIGHT -> NativeLibrary.ButtonType.DPAD_RIGHT
|
||||
Settings.HOTKEY_ENABLE -> Hotkey.ENABLE.button
|
||||
Settings.HOTKEY_SCREEN_SWAP -> Hotkey.SWAP_SCREEN.button
|
||||
Settings.HOTKEY_CYCLE_LAYOUT -> Hotkey.CYCLE_LAYOUT.button
|
||||
Settings.HOTKEY_CLOSE_GAME -> Hotkey.CLOSE_GAME.button
|
||||
|
|
@ -162,36 +164,40 @@ class InputBindingSetting(
|
|||
fun removeOldMapping() {
|
||||
// Try remove all possible keys we wrote for this setting
|
||||
val oldKey = preferences.getString(reverseKey, "")
|
||||
(setting as AbstractStringSetting).string = ""
|
||||
if (oldKey != "") {
|
||||
(setting as AbstractStringSetting).string = ""
|
||||
preferences.edit()
|
||||
.remove(abstractSetting.key) // Used for ui text
|
||||
.remove(oldKey) // Used for button mapping
|
||||
.remove(oldKey + "_GuestOrientation") // Used for axis orientation
|
||||
.remove(oldKey + "_GuestButton") // Used for axis button
|
||||
.remove(oldKey + "_Inverted") // used for axis inversion
|
||||
.apply()
|
||||
.remove(reverseKey)
|
||||
val buttonCodes = try {
|
||||
preferences.getStringSet(oldKey, mutableSetOf<String>())!!.toMutableSet()
|
||||
} catch (e: ClassCastException) {
|
||||
// if this is an int pref, either old button or an axis, so just remove it
|
||||
preferences.edit().remove(oldKey).apply()
|
||||
return;
|
||||
}
|
||||
buttonCodes.remove(buttonCode.toString());
|
||||
preferences.edit().putStringSet(oldKey,buttonCodes).apply()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to write a gamepad button mapping for the setting.
|
||||
*/
|
||||
private fun writeButtonMapping(key: String) {
|
||||
private fun writeButtonMapping(keyEvent: KeyEvent) {
|
||||
val editor = preferences.edit()
|
||||
|
||||
// Remove mapping for another setting using this input
|
||||
val oldButtonCode = preferences.getInt(key, -1)
|
||||
if (oldButtonCode != -1) {
|
||||
val oldKey = getButtonKey(oldButtonCode)
|
||||
editor.remove(oldKey) // Only need to remove UI text setting, others will be overwritten
|
||||
}
|
||||
|
||||
val key = getInputButtonKey(keyEvent)
|
||||
// Pull in all codes associated with this key
|
||||
// Migrate from the old int preference if need be
|
||||
val buttonCodes = InputBindingSetting.getButtonSet(keyEvent)
|
||||
buttonCodes.add(buttonCode)
|
||||
// Cleanup old mapping for this setting
|
||||
removeOldMapping()
|
||||
|
||||
// Write new mapping
|
||||
editor.putInt(key, buttonCode)
|
||||
editor.putStringSet(key, buttonCodes.mapTo(mutableSetOf()) {it.toString()})
|
||||
|
||||
// Write next reverse mapping for future cleanup
|
||||
editor.putString(reverseKey, key)
|
||||
|
|
@ -229,9 +235,8 @@ class InputBindingSetting(
|
|||
}
|
||||
|
||||
val code = translateEventToKeyId(keyEvent)
|
||||
writeButtonMapping(getInputButtonKey(code))
|
||||
val uiString = "${keyEvent.device.name}: Button $code"
|
||||
value = uiString
|
||||
writeButtonMapping(keyEvent)
|
||||
value = "${keyEvent.device.name}: ${getButtonName(code)}"
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -258,8 +263,7 @@ class InputBindingSetting(
|
|||
// use UP (-) to map vertical, but use RIGHT (+) to map horizontal
|
||||
val inverted = if (isHorizontalOrientation()) axisDir == '-' else axisDir == '+'
|
||||
writeAxisMapping(motionRange.axis, button, inverted)
|
||||
val uiString = "${device.name}: Axis ${motionRange.axis}" + axisDir
|
||||
value = uiString
|
||||
value = "Axis ${motionRange.axis}$axisDir"
|
||||
}
|
||||
|
||||
override val type = TYPE_INPUT_BINDING
|
||||
|
|
@ -267,6 +271,241 @@ class InputBindingSetting(
|
|||
companion object {
|
||||
private const val INPUT_MAPPING_PREFIX = "InputMapping"
|
||||
|
||||
private fun toTitleCase(raw: String): String =
|
||||
raw.replace("_", " ").lowercase()
|
||||
.split(" ").joinToString(" ") { it.replaceFirstChar { c -> c.uppercase() } }
|
||||
|
||||
private const val BUTTON_NAME_L3 = "Button L3"
|
||||
private const val BUTTON_NAME_R3 = "Button R3"
|
||||
|
||||
private val buttonNameOverrides = mapOf(
|
||||
KeyEvent.KEYCODE_BUTTON_THUMBL to BUTTON_NAME_L3,
|
||||
KeyEvent.KEYCODE_BUTTON_THUMBR to BUTTON_NAME_R3,
|
||||
LINUX_BTN_DPAD_UP to "Dpad Up",
|
||||
LINUX_BTN_DPAD_DOWN to "Dpad Down",
|
||||
LINUX_BTN_DPAD_LEFT to "Dpad Left",
|
||||
LINUX_BTN_DPAD_RIGHT to "Dpad Right"
|
||||
)
|
||||
|
||||
fun getButtonName(keyCode: Int): String =
|
||||
buttonNameOverrides[keyCode]
|
||||
?: toTitleCase(KeyEvent.keyCodeToString(keyCode).removePrefix("KEYCODE_"))
|
||||
|
||||
private data class DefaultButtonMapping(
|
||||
val settingKey: String,
|
||||
val hostKeyCode: Int,
|
||||
val guestButtonCode: Int
|
||||
)
|
||||
// Auto-map always sets inverted = false. Users needing inverted axes should remap manually.
|
||||
private data class DefaultAxisMapping(
|
||||
val settingKey: String,
|
||||
val hostAxis: Int,
|
||||
val guestButton: Int,
|
||||
val orientation: Int,
|
||||
val inverted: Boolean
|
||||
)
|
||||
|
||||
private val xboxFaceButtonMappings = listOf(
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_A, KeyEvent.KEYCODE_BUTTON_B, NativeLibrary.ButtonType.BUTTON_A),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_B, KeyEvent.KEYCODE_BUTTON_A, NativeLibrary.ButtonType.BUTTON_B),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_X, KeyEvent.KEYCODE_BUTTON_Y, NativeLibrary.ButtonType.BUTTON_X),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_Y, KeyEvent.KEYCODE_BUTTON_X, NativeLibrary.ButtonType.BUTTON_Y)
|
||||
)
|
||||
|
||||
private val nintendoFaceButtonMappings = listOf(
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_A, KeyEvent.KEYCODE_BUTTON_A, NativeLibrary.ButtonType.BUTTON_A),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_B, KeyEvent.KEYCODE_BUTTON_B, NativeLibrary.ButtonType.BUTTON_B),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_X, KeyEvent.KEYCODE_BUTTON_X, NativeLibrary.ButtonType.BUTTON_X),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_Y, KeyEvent.KEYCODE_BUTTON_Y, NativeLibrary.ButtonType.BUTTON_Y)
|
||||
)
|
||||
|
||||
private val commonButtonMappings = listOf(
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_L, KeyEvent.KEYCODE_BUTTON_L1, NativeLibrary.ButtonType.TRIGGER_L),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_R, KeyEvent.KEYCODE_BUTTON_R1, NativeLibrary.ButtonType.TRIGGER_R),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_ZL, KeyEvent.KEYCODE_BUTTON_L2, NativeLibrary.ButtonType.BUTTON_ZL),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_ZR, KeyEvent.KEYCODE_BUTTON_R2, NativeLibrary.ButtonType.BUTTON_ZR),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_SELECT, KeyEvent.KEYCODE_BUTTON_SELECT, NativeLibrary.ButtonType.BUTTON_SELECT),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_START, KeyEvent.KEYCODE_BUTTON_START, NativeLibrary.ButtonType.BUTTON_START)
|
||||
)
|
||||
|
||||
private val dpadButtonMappings = listOf(
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_UP, KeyEvent.KEYCODE_DPAD_UP, NativeLibrary.ButtonType.DPAD_UP),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_DOWN, KeyEvent.KEYCODE_DPAD_DOWN, NativeLibrary.ButtonType.DPAD_DOWN),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_LEFT, KeyEvent.KEYCODE_DPAD_LEFT, NativeLibrary.ButtonType.DPAD_LEFT),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_RIGHT, KeyEvent.KEYCODE_DPAD_RIGHT, NativeLibrary.ButtonType.DPAD_RIGHT)
|
||||
)
|
||||
|
||||
private val stickAxisMappings = listOf(
|
||||
DefaultAxisMapping(Settings.KEY_CIRCLEPAD_AXIS_HORIZONTAL, MotionEvent.AXIS_X, NativeLibrary.ButtonType.STICK_LEFT, 0, false),
|
||||
DefaultAxisMapping(Settings.KEY_CIRCLEPAD_AXIS_VERTICAL, MotionEvent.AXIS_Y, NativeLibrary.ButtonType.STICK_LEFT, 1, false),
|
||||
DefaultAxisMapping(Settings.KEY_CSTICK_AXIS_HORIZONTAL, MotionEvent.AXIS_Z, NativeLibrary.ButtonType.STICK_C, 0, false),
|
||||
DefaultAxisMapping(Settings.KEY_CSTICK_AXIS_VERTICAL, MotionEvent.AXIS_RZ, NativeLibrary.ButtonType.STICK_C, 1, false)
|
||||
)
|
||||
|
||||
private val dpadAxisMappings = listOf(
|
||||
DefaultAxisMapping(Settings.KEY_DPAD_AXIS_HORIZONTAL, MotionEvent.AXIS_HAT_X, NativeLibrary.ButtonType.DPAD, 0, false),
|
||||
DefaultAxisMapping(Settings.KEY_DPAD_AXIS_VERTICAL, MotionEvent.AXIS_HAT_Y, NativeLibrary.ButtonType.DPAD, 1, false)
|
||||
)
|
||||
|
||||
// Nintendo Switch Joy-Con specific mappings.
|
||||
// Joy-Cons connected via Bluetooth on Android have several quirks:
|
||||
// - They register as two separate InputDevices (left and right)
|
||||
// - Android's evdev translation swaps A<->B (BTN_EAST->BUTTON_B, BTN_SOUTH->BUTTON_A)
|
||||
// but does NOT swap X<->Y (BTN_NORTH->BUTTON_X, BTN_WEST->BUTTON_Y)
|
||||
// - D-pad buttons arrive as KEYCODE_UNKNOWN (0) with Linux BTN_DPAD_* scan codes
|
||||
// - Right stick uses AXIS_RX/AXIS_RY instead of AXIS_Z/AXIS_RZ
|
||||
private const val NINTENDO_VENDOR_ID = 0x057e
|
||||
|
||||
// Linux BTN_DPAD_* values (0x220-0x223). Joy-Con D-pad buttons arrive as
|
||||
// KEYCODE_UNKNOWN with these scan codes because Android's input layer doesn't
|
||||
// translate them to KEYCODE_DPAD_*. translateEventToKeyId() falls back to
|
||||
// the scan code in that case.
|
||||
private const val LINUX_BTN_DPAD_UP = 0x220 // 544
|
||||
private const val LINUX_BTN_DPAD_DOWN = 0x221 // 545
|
||||
private const val LINUX_BTN_DPAD_LEFT = 0x222 // 546
|
||||
private const val LINUX_BTN_DPAD_RIGHT = 0x223 // 547
|
||||
|
||||
// Joy-Con face buttons: A/B are swapped by Android's evdev layer, but X/Y are not.
|
||||
// This is different from both the standard Xbox table (full swap) and the
|
||||
// Nintendo table (no swap).
|
||||
private val joyconFaceButtonMappings = listOf(
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_A, KeyEvent.KEYCODE_BUTTON_B, NativeLibrary.ButtonType.BUTTON_A),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_B, KeyEvent.KEYCODE_BUTTON_A, NativeLibrary.ButtonType.BUTTON_B),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_X, KeyEvent.KEYCODE_BUTTON_X, NativeLibrary.ButtonType.BUTTON_X),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_Y, KeyEvent.KEYCODE_BUTTON_Y, NativeLibrary.ButtonType.BUTTON_Y)
|
||||
)
|
||||
|
||||
// Joy-Con D-pad: uses Linux scan codes because Android reports BTN_DPAD_* as KEYCODE_UNKNOWN
|
||||
private val joyconDpadButtonMappings = listOf(
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_UP, LINUX_BTN_DPAD_UP, NativeLibrary.ButtonType.DPAD_UP),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_DOWN, LINUX_BTN_DPAD_DOWN, NativeLibrary.ButtonType.DPAD_DOWN),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_LEFT, LINUX_BTN_DPAD_LEFT, NativeLibrary.ButtonType.DPAD_LEFT),
|
||||
DefaultButtonMapping(Settings.KEY_BUTTON_RIGHT, LINUX_BTN_DPAD_RIGHT, NativeLibrary.ButtonType.DPAD_RIGHT)
|
||||
)
|
||||
|
||||
// Joy-Con sticks: left stick is AXIS_X/Y (standard), right stick is AXIS_RX/RY
|
||||
// (not Z/RZ like most controllers). The horizontal axis is inverted relative to
|
||||
// the standard orientation - verified empirically on paired Joy-Cons via Bluetooth.
|
||||
private val joyconStickAxisMappings = listOf(
|
||||
DefaultAxisMapping(Settings.KEY_CIRCLEPAD_AXIS_HORIZONTAL, MotionEvent.AXIS_X, NativeLibrary.ButtonType.STICK_LEFT, 0, false),
|
||||
DefaultAxisMapping(Settings.KEY_CIRCLEPAD_AXIS_VERTICAL, MotionEvent.AXIS_Y, NativeLibrary.ButtonType.STICK_LEFT, 1, false),
|
||||
DefaultAxisMapping(Settings.KEY_CSTICK_AXIS_HORIZONTAL, MotionEvent.AXIS_RX, NativeLibrary.ButtonType.STICK_C, 0, true),
|
||||
DefaultAxisMapping(Settings.KEY_CSTICK_AXIS_VERTICAL, MotionEvent.AXIS_RY, NativeLibrary.ButtonType.STICK_C, 1, false)
|
||||
)
|
||||
|
||||
/**
|
||||
* Detects whether a device is a Nintendo Switch Joy-Con (as opposed to a
|
||||
* Pro Controller or other Nintendo device) by checking vendor ID + device
|
||||
* capabilities. Joy-Cons lack AXIS_HAT_X/Y and use AXIS_RX/RY for the
|
||||
* right stick, while the Pro Controller has standard HAT axes and Z/RZ.
|
||||
*/
|
||||
fun isJoyCon(device: InputDevice?): Boolean {
|
||||
if (device == null) return false
|
||||
if (device.vendorId != NINTENDO_VENDOR_ID) return false
|
||||
|
||||
// Pro Controllers have HAT_X/HAT_Y (D-pad) and Z/RZ (right stick).
|
||||
// Joy-Cons lack both: no HAT axes, right stick on RX/RY instead of Z/RZ.
|
||||
var hasHatAxes = false
|
||||
var hasStandardRightStick = false
|
||||
for (range in device.motionRanges) {
|
||||
when (range.axis) {
|
||||
MotionEvent.AXIS_HAT_X, MotionEvent.AXIS_HAT_Y -> hasHatAxes = true
|
||||
MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ -> hasStandardRightStick = true
|
||||
}
|
||||
}
|
||||
return !hasHatAxes && !hasStandardRightStick
|
||||
}
|
||||
|
||||
private val allBindingKeys: Set<String> by lazy {
|
||||
(Settings.buttonKeys + Settings.triggerKeys +
|
||||
Settings.circlePadKeys + Settings.cStickKeys + Settings.dPadAxisKeys +
|
||||
Settings.dPadButtonKeys).toSet()
|
||||
}
|
||||
|
||||
fun clearAllBindings() {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
|
||||
val editor = prefs.edit()
|
||||
val allKeys = prefs.all.keys.toList()
|
||||
for (key in allKeys) {
|
||||
if (key.startsWith(INPUT_MAPPING_PREFIX) || key in allBindingKeys) {
|
||||
editor.remove(key)
|
||||
}
|
||||
}
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
private fun applyBindings(
|
||||
buttonMappings: List<DefaultButtonMapping>,
|
||||
axisMappings: List<DefaultAxisMapping>
|
||||
) {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
|
||||
val editor = prefs.edit()
|
||||
buttonMappings.forEach { applyDefaultButtonMapping(editor, it) }
|
||||
axisMappings.forEach { applyDefaultAxisMapping(editor, it) }
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies Joy-Con specific bindings: scan code D-pad, partial face button
|
||||
* swap, and AXIS_RX/RY right stick.
|
||||
*/
|
||||
fun applyJoyConBindings() {
|
||||
applyBindings(
|
||||
joyconFaceButtonMappings + commonButtonMappings + joyconDpadButtonMappings,
|
||||
joyconStickAxisMappings
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies auto-mapped bindings based on detected controller layout and d-pad type.
|
||||
*
|
||||
* @param isNintendoLayout true if the controller uses Nintendo face button layout
|
||||
* (A=east, B=south), false for Xbox layout (A=south, B=east)
|
||||
* @param useAxisDpad true if the d-pad should be mapped as axis (HAT_X/HAT_Y),
|
||||
* false if it should be mapped as individual button keycodes (DPAD_UP/DOWN/LEFT/RIGHT)
|
||||
*/
|
||||
fun applyAutoMapBindings(isNintendoLayout: Boolean, useAxisDpad: Boolean) {
|
||||
val faceButtons = if (isNintendoLayout) nintendoFaceButtonMappings else xboxFaceButtonMappings
|
||||
val buttonMappings = if (useAxisDpad) {
|
||||
faceButtons + commonButtonMappings
|
||||
} else {
|
||||
faceButtons + commonButtonMappings + dpadButtonMappings
|
||||
}
|
||||
val axisMappings = if (useAxisDpad) {
|
||||
stickAxisMappings + dpadAxisMappings
|
||||
} else {
|
||||
stickAxisMappings
|
||||
}
|
||||
applyBindings(buttonMappings, axisMappings)
|
||||
}
|
||||
|
||||
private fun applyDefaultButtonMapping(
|
||||
editor: SharedPreferences.Editor,
|
||||
mapping: DefaultButtonMapping
|
||||
) {
|
||||
val prefKey = getInputButtonKey(mapping.hostKeyCode)
|
||||
editor.putInt(prefKey, mapping.guestButtonCode)
|
||||
editor.putString(mapping.settingKey, getButtonName(mapping.hostKeyCode))
|
||||
editor.putString(
|
||||
"${INPUT_MAPPING_PREFIX}_ReverseMapping_${mapping.settingKey}",
|
||||
prefKey
|
||||
)
|
||||
}
|
||||
|
||||
private fun applyDefaultAxisMapping(
|
||||
editor: SharedPreferences.Editor,
|
||||
mapping: DefaultAxisMapping
|
||||
) {
|
||||
val axisKey = getInputAxisKey(mapping.hostAxis)
|
||||
editor.putInt(getInputAxisOrientationKey(mapping.hostAxis), mapping.orientation)
|
||||
editor.putInt(getInputAxisButtonKey(mapping.hostAxis), mapping.guestButton)
|
||||
editor.putBoolean(getInputAxisInvertedKey(mapping.hostAxis), mapping.inverted)
|
||||
val dir = if (mapping.orientation == 0) '+' else '-'
|
||||
editor.putString(mapping.settingKey, "Axis ${mapping.hostAxis}$dir")
|
||||
val reverseKey = "${INPUT_MAPPING_PREFIX}_ReverseMapping_${mapping.settingKey}_${mapping.orientation}"
|
||||
editor.putString(reverseKey, axisKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings key for the specified Citra button code.
|
||||
*/
|
||||
|
|
@ -289,19 +528,31 @@ class InputBindingSetting(
|
|||
NativeLibrary.ButtonType.DPAD_RIGHT -> Settings.KEY_BUTTON_RIGHT
|
||||
else -> ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the settings key for an gamepad button.
|
||||
*
|
||||
* Get the mutable set of int button values this key should map to given an event
|
||||
*/
|
||||
@Deprecated("Use the new getInputButtonKey(keyEvent) method to handle unknown keys")
|
||||
fun getInputButtonKey(keyCode: Int): String = "${INPUT_MAPPING_PREFIX}_HostAxis_${keyCode}"
|
||||
fun getButtonSet(keyCode: KeyEvent):MutableSet<Int> {
|
||||
val key = getInputButtonKey(keyCode)
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
|
||||
var buttonCodes = try {
|
||||
preferences.getStringSet(key, mutableSetOf<String>())
|
||||
} catch (e: ClassCastException) {
|
||||
val prefInt = preferences.getInt(key, -1);
|
||||
val migratedSet = if (prefInt != -1) {
|
||||
mutableSetOf(prefInt.toString())
|
||||
} else {
|
||||
mutableSetOf<String>()
|
||||
}
|
||||
migratedSet
|
||||
}
|
||||
if (buttonCodes == null) buttonCodes = mutableSetOf<String>()
|
||||
return buttonCodes.mapNotNull { it.toIntOrNull() }.toMutableSet()
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the settings key for an gamepad button.
|
||||
*
|
||||
*/
|
||||
fun getInputButtonKey(event: KeyEvent): String = "${INPUT_MAPPING_PREFIX}_HostAxis_${translateEventToKeyId(event)}"
|
||||
private fun getInputButtonKey(keyId: Int): String = "${INPUT_MAPPING_PREFIX}_HostAxis_${keyId}"
|
||||
|
||||
/** Falls back to the scan code when keyCode is KEYCODE_UNKNOWN. */
|
||||
fun getInputButtonKey(event: KeyEvent): String = getInputButtonKey(translateEventToKeyId(event))
|
||||
|
||||
/**
|
||||
* Helper function to get the settings key for an gamepad axis.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package org.citra.citra_emu.features.settings.model.view
|
||||
import org.citra.citra_emu.features.settings.model.AbstractSetting
|
||||
import org.citra.citra_emu.features.settings.model.IntListSetting
|
||||
class MultiChoiceSetting(
|
||||
setting: AbstractSetting?,
|
||||
titleId: Int,
|
||||
descriptionId: Int,
|
||||
val choicesId: Int,
|
||||
val valuesId: Int,
|
||||
val key: String? = null,
|
||||
val defaultValue: List<Int>? = null,
|
||||
override var isEnabled: Boolean = true
|
||||
) : SettingsItem(setting, titleId, descriptionId) {
|
||||
override val type = TYPE_MULTI_CHOICE
|
||||
|
||||
val selectedValues: List<Int>
|
||||
get() {
|
||||
if (setting == null) {
|
||||
return defaultValue!!
|
||||
}
|
||||
try {
|
||||
val setting = setting as IntListSetting
|
||||
return setting.list
|
||||
}catch (_: ClassCastException) {
|
||||
}
|
||||
return defaultValue!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to the backing list. If that int was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param selection New value of the int.
|
||||
* @return the existing setting with the new value applied.
|
||||
*/
|
||||
fun setSelectedValue(selection: List<Int>): IntListSetting {
|
||||
val intSetting = setting as IntListSetting
|
||||
intSetting.list = selection
|
||||
return intSetting
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package org.citra.citra_emu.features.settings.model.view
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import org.citra.citra_emu.activities.EmulationActivity
|
||||
|
||||
class RunnableSetting(
|
||||
titleId: Int,
|
||||
|
|
@ -12,7 +13,11 @@ class RunnableSetting(
|
|||
val isRuntimeRunnable: Boolean,
|
||||
@DrawableRes val iconId: Int = 0,
|
||||
val runnable: () -> Unit,
|
||||
val value: (() -> String)? = null
|
||||
val value: (() -> String)? = null,
|
||||
val onLongClick: (() -> Boolean)? = null
|
||||
) : SettingsItem(null, titleId, descriptionId) {
|
||||
override val type = TYPE_RUNNABLE
|
||||
|
||||
override val isEditable: Boolean
|
||||
get() = if (EmulationActivity.isRunning()) isRuntimeRunnable else true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ abstract class SettingsItem(
|
|||
) {
|
||||
abstract val type: Int
|
||||
|
||||
val isEditable: Boolean
|
||||
open val isEditable: Boolean
|
||||
get() {
|
||||
if (!EmulationActivity.isRunning()) return true
|
||||
return setting?.isRuntimeEditable ?: false
|
||||
|
|
@ -47,5 +47,6 @@ abstract class SettingsItem(
|
|||
const val TYPE_INPUT_BINDING = 8
|
||||
const val TYPE_STRING_INPUT = 9
|
||||
const val TYPE_FLOAT_INPUT = 10
|
||||
const val TYPE_MULTI_CHOICE = 11
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,12 +41,14 @@ import org.citra.citra_emu.features.settings.model.AbstractIntSetting
|
|||
import org.citra.citra_emu.features.settings.model.AbstractSetting
|
||||
import org.citra.citra_emu.features.settings.model.AbstractStringSetting
|
||||
import org.citra.citra_emu.features.settings.model.FloatSetting
|
||||
import org.citra.citra_emu.features.settings.model.IntListSetting
|
||||
import org.citra.citra_emu.features.settings.model.ScaledFloatSetting
|
||||
import org.citra.citra_emu.features.settings.model.AbstractShortSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.DateTimeSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.InputBindingSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.SettingsItem
|
||||
import org.citra.citra_emu.features.settings.model.view.SingleChoiceSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.MultiChoiceSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.SliderSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.StringInputSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.StringSingleChoiceSetting
|
||||
|
|
@ -55,6 +57,7 @@ import org.citra.citra_emu.features.settings.model.view.SwitchSetting
|
|||
import org.citra.citra_emu.features.settings.ui.viewholder.DateTimeViewHolder
|
||||
import org.citra.citra_emu.features.settings.ui.viewholder.HeaderViewHolder
|
||||
import org.citra.citra_emu.features.settings.ui.viewholder.InputBindingSettingViewHolder
|
||||
import org.citra.citra_emu.features.settings.ui.viewholder.MultiChoiceViewHolder
|
||||
import org.citra.citra_emu.features.settings.ui.viewholder.RunnableViewHolder
|
||||
import org.citra.citra_emu.features.settings.ui.viewholder.SettingViewHolder
|
||||
import org.citra.citra_emu.features.settings.ui.viewholder.SingleChoiceViewHolder
|
||||
|
|
@ -62,6 +65,7 @@ import org.citra.citra_emu.features.settings.ui.viewholder.SliderViewHolder
|
|||
import org.citra.citra_emu.features.settings.ui.viewholder.StringInputViewHolder
|
||||
import org.citra.citra_emu.features.settings.ui.viewholder.SubmenuViewHolder
|
||||
import org.citra.citra_emu.features.settings.ui.viewholder.SwitchSettingViewHolder
|
||||
import org.citra.citra_emu.fragments.AutoMapDialogFragment
|
||||
import org.citra.citra_emu.fragments.MessageDialogFragment
|
||||
import org.citra.citra_emu.fragments.MotionBottomSheetDialogFragment
|
||||
import org.citra.citra_emu.utils.SystemSaveGame
|
||||
|
|
@ -72,7 +76,8 @@ import kotlin.math.roundToInt
|
|||
class SettingsAdapter(
|
||||
private val fragmentView: SettingsFragmentView,
|
||||
public val context: Context
|
||||
) : RecyclerView.Adapter<SettingViewHolder?>(), DialogInterface.OnClickListener {
|
||||
) : RecyclerView.Adapter<SettingViewHolder?>(), DialogInterface.OnClickListener,
|
||||
DialogInterface.OnMultiChoiceClickListener {
|
||||
private var settings: ArrayList<SettingsItem>? = null
|
||||
private var clickedItem: SettingsItem? = null
|
||||
private var clickedPosition: Int
|
||||
|
|
@ -104,6 +109,10 @@ class SettingsAdapter(
|
|||
SingleChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_MULTI_CHOICE -> {
|
||||
MultiChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_SLIDER -> {
|
||||
SliderViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
|
@ -181,21 +190,30 @@ class SettingsAdapter(
|
|||
SettingsItem.TYPE_SLIDER -> {
|
||||
(oldItem as SliderSetting).isEnabled == (newItem as SliderSetting).isEnabled
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_SWITCH -> {
|
||||
(oldItem as SwitchSetting).isEnabled == (newItem as SwitchSetting).isEnabled
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_SINGLE_CHOICE -> {
|
||||
(oldItem as SingleChoiceSetting).isEnabled == (newItem as SingleChoiceSetting).isEnabled
|
||||
}
|
||||
SettingsItem.TYPE_MULTI_CHOICE -> {
|
||||
(oldItem as MultiChoiceSetting).isEnabled == (newItem as MultiChoiceSetting).isEnabled
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_DATETIME_SETTING -> {
|
||||
(oldItem as DateTimeSetting).isEnabled == (newItem as DateTimeSetting).isEnabled
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
|
||||
(oldItem as StringSingleChoiceSetting).isEnabled == (newItem as StringSingleChoiceSetting).isEnabled
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_STRING_INPUT -> {
|
||||
(oldItem as StringInputSetting).isEnabled == (newItem as StringInputSetting).isEnabled
|
||||
}
|
||||
|
||||
else -> {
|
||||
oldItem == newItem
|
||||
}
|
||||
|
|
@ -214,7 +232,7 @@ class SettingsAdapter(
|
|||
|
||||
// If statement is required otherwise the app will crash on activity recreate ex. theme settings
|
||||
if (fragmentView.activityView != null)
|
||||
// Reload the settings list to update the UI
|
||||
// Reload the settings list to update the UI
|
||||
fragmentView.loadSettingsList()
|
||||
}
|
||||
|
||||
|
|
@ -232,6 +250,27 @@ class SettingsAdapter(
|
|||
onSingleChoiceClick(item)
|
||||
}
|
||||
|
||||
private fun onMultiChoiceClick(item: MultiChoiceSetting) {
|
||||
clickedItem = item
|
||||
|
||||
val value: BooleanArray = getSelectionForMultiChoiceValue(item);
|
||||
dialog = MaterialAlertDialogBuilder(context)
|
||||
.setTitle(item.nameId)
|
||||
.setMultiChoiceItems(item.choicesId, value, this)
|
||||
.setOnDismissListener {
|
||||
if (clickedPosition != -1) {
|
||||
notifyItemChanged(clickedPosition)
|
||||
clickedPosition = -1
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
fun onMultiChoiceClick(item: MultiChoiceSetting, position: Int) {
|
||||
clickedPosition = position
|
||||
onMultiChoiceClick(item)
|
||||
}
|
||||
|
||||
private fun onStringSingleChoiceClick(item: StringSingleChoiceSetting) {
|
||||
clickedItem = item
|
||||
dialog = context?.let {
|
||||
|
|
@ -360,14 +399,14 @@ class SettingsAdapter(
|
|||
sliderString = sliderProgress.roundToInt().toString()
|
||||
if (textSliderValue?.text.toString() != sliderString) {
|
||||
textSliderValue?.setText(sliderString)
|
||||
textSliderValue?.setSelection(textSliderValue?.length() ?: 0 )
|
||||
textSliderValue?.setSelection(textSliderValue?.length() ?: 0)
|
||||
}
|
||||
} else {
|
||||
val currentText = textSliderValue?.text.toString()
|
||||
val currentTextValue = currentText.toFloat()
|
||||
if (currentTextValue != sliderProgress) {
|
||||
textSliderValue?.setText(sliderString)
|
||||
textSliderValue?.setSelection(textSliderValue?.length() ?: 0 )
|
||||
textSliderValue?.setSelection(textSliderValue?.length() ?: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -447,6 +486,7 @@ class SettingsAdapter(
|
|||
}
|
||||
it.setSelectedValue(value)
|
||||
}
|
||||
|
||||
is AbstractShortSetting -> {
|
||||
val value = getValueForSingleChoiceSelection(it, which).toShort()
|
||||
if (it.selectedValue.toShort() != value) {
|
||||
|
|
@ -454,6 +494,7 @@ class SettingsAdapter(
|
|||
}
|
||||
it.setSelectedValue(value)
|
||||
}
|
||||
|
||||
else -> throw IllegalStateException("Unrecognized type used for SingleChoiceSetting!")
|
||||
}
|
||||
fragmentView?.putSetting(setting)
|
||||
|
|
@ -499,11 +540,12 @@ class SettingsAdapter(
|
|||
val setting = it.setSelectedValue(value)
|
||||
fragmentView?.putSetting(setting)
|
||||
}
|
||||
|
||||
else -> {
|
||||
val setting = it.setSelectedValue(sliderProgress)
|
||||
fragmentView?.putSetting(setting)
|
||||
}
|
||||
}
|
||||
}
|
||||
fragmentView.loadSettingsList()
|
||||
closeDialog()
|
||||
}
|
||||
|
|
@ -519,7 +561,7 @@ class SettingsAdapter(
|
|||
fragmentView?.putSetting(setting)
|
||||
fragmentView.loadSettingsList()
|
||||
closeDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clickedItem = null
|
||||
|
|
@ -527,6 +569,21 @@ class SettingsAdapter(
|
|||
textInputValue = ""
|
||||
}
|
||||
|
||||
//onclick for multichoice
|
||||
override fun onClick(dialog: DialogInterface?, which: Int, isChecked: Boolean) {
|
||||
val mcsetting = clickedItem as? MultiChoiceSetting
|
||||
mcsetting?.let {
|
||||
val value = getValueForMultiChoiceSelection(it, which)
|
||||
if (it.selectedValues.contains(value) != isChecked) {
|
||||
val setting = it.setSelectedValue((if (isChecked) it.selectedValues + value else it.selectedValues - value).sorted())
|
||||
fragmentView?.putSetting(setting)
|
||||
fragmentView?.onSettingChanged()
|
||||
}
|
||||
fragmentView.loadSettingsList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun onLongClick(setting: AbstractSetting, position: Int): Boolean {
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setMessage(R.string.reset_setting_confirmation)
|
||||
|
|
@ -586,26 +643,42 @@ class SettingsAdapter(
|
|||
).show((fragmentView as SettingsFragment).childFragmentManager, MessageDialogFragment.TAG)
|
||||
}
|
||||
|
||||
fun onClickAutoMap() {
|
||||
val activity = fragmentView.activityView as FragmentActivity
|
||||
AutoMapDialogFragment.newInstance {
|
||||
fragmentView.loadSettingsList()
|
||||
fragmentView.onSettingChanged()
|
||||
}.show(activity.supportFragmentManager, AutoMapDialogFragment.TAG)
|
||||
}
|
||||
|
||||
fun onLongClickAutoMap(): Boolean {
|
||||
showConfirmationDialog(R.string.controller_clear_all, R.string.controller_clear_all_confirm) {
|
||||
InputBindingSetting.clearAllBindings()
|
||||
fragmentView.loadSettingsList()
|
||||
fragmentView.onSettingChanged()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun onClickRegenerateConsoleId() {
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.regenerate_console_id)
|
||||
.setMessage(R.string.regenerate_console_id_description)
|
||||
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
|
||||
SystemSaveGame.regenerateConsoleId()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
showConfirmationDialog(R.string.regenerate_console_id, R.string.regenerate_console_id_description) {
|
||||
SystemSaveGame.regenerateConsoleId()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
fun onClickRegenerateMAC() {
|
||||
showConfirmationDialog(R.string.regenerate_mac_address, R.string.regenerate_mac_address_description) {
|
||||
SystemSaveGame.regenerateMac()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showConfirmationDialog(titleId: Int, messageId: Int, onConfirm: () -> Unit) {
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.regenerate_mac_address)
|
||||
.setMessage(R.string.regenerate_mac_address_description)
|
||||
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
|
||||
SystemSaveGame.regenerateMac()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
.setTitle(titleId)
|
||||
.setMessage(messageId)
|
||||
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> onConfirm() }
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
|
@ -631,6 +704,16 @@ class SettingsAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getValueForMultiChoiceSelection(item: MultiChoiceSetting, which: Int): Int {
|
||||
val valuesId = item.valuesId
|
||||
return if (valuesId > 0) {
|
||||
val valuesArray = context.resources.getIntArray(valuesId)
|
||||
valuesArray[which]
|
||||
} else {
|
||||
which
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectionForSingleChoiceValue(item: SingleChoiceSetting): Int {
|
||||
val value = item.selectedValue
|
||||
val valuesId = item.valuesId
|
||||
|
|
@ -647,4 +730,20 @@ class SettingsAdapter(
|
|||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
private fun getSelectionForMultiChoiceValue(item: MultiChoiceSetting): BooleanArray {
|
||||
val value = item.selectedValues;
|
||||
val valuesId = item.valuesId;
|
||||
if (valuesId > 0) {
|
||||
val valuesArray = context.resources.getIntArray(valuesId);
|
||||
val res = BooleanArray(valuesArray.size){false}
|
||||
for (index in valuesArray.indices) {
|
||||
if (value.contains(valuesArray[index])) {
|
||||
res[index] = true;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return BooleanArray(1){false};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import android.os.Build
|
|||
import android.text.TextUtils
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.serialization.builtins.IntArraySerializer
|
||||
import org.citra.citra_emu.CitraApplication
|
||||
import org.citra.citra_emu.R
|
||||
import org.citra.citra_emu.display.ScreenLayout
|
||||
|
|
@ -27,12 +28,14 @@ import org.citra.citra_emu.features.settings.model.AbstractStringSetting
|
|||
import org.citra.citra_emu.features.settings.model.BooleanSetting
|
||||
import org.citra.citra_emu.features.settings.model.FloatSetting
|
||||
import org.citra.citra_emu.features.settings.model.IntSetting
|
||||
import org.citra.citra_emu.features.settings.model.IntListSetting
|
||||
import org.citra.citra_emu.features.settings.model.ScaledFloatSetting
|
||||
import org.citra.citra_emu.features.settings.model.Settings
|
||||
import org.citra.citra_emu.features.settings.model.StringSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.DateTimeSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.HeaderSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.InputBindingSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.MultiChoiceSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.RunnableSetting
|
||||
import org.citra.citra_emu.features.settings.model.view.SettingsItem
|
||||
import org.citra.citra_emu.features.settings.model.view.SingleChoiceSetting
|
||||
|
|
@ -776,6 +779,16 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
|||
private fun addControlsSettings(sl: ArrayList<SettingsItem>) {
|
||||
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_controls))
|
||||
sl.apply {
|
||||
add(
|
||||
RunnableSetting(
|
||||
R.string.controller_auto_map,
|
||||
R.string.controller_auto_map_description,
|
||||
true,
|
||||
R.drawable.ic_controller,
|
||||
{ settingsAdapter.onClickAutoMap() },
|
||||
onLongClick = { settingsAdapter.onLongClickAutoMap() }
|
||||
)
|
||||
)
|
||||
add(HeaderSetting(R.string.generic_buttons))
|
||||
Settings.buttonKeys.forEachIndexed { i: Int, key: String ->
|
||||
val button = getInputObject(key)
|
||||
|
|
@ -811,7 +824,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
|||
add(InputBindingSetting(button, Settings.triggerTitles[i]))
|
||||
}
|
||||
|
||||
add(HeaderSetting(R.string.controller_hotkeys))
|
||||
add(HeaderSetting(R.string.controller_hotkeys,R.string.controller_hotkeys_description))
|
||||
Settings.hotKeys.forEachIndexed { i: Int, key: String ->
|
||||
val button = getInputObject(key)
|
||||
add(InputBindingSetting(button, Settings.hotkeyTitles[i]))
|
||||
|
|
@ -898,6 +911,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
|||
IntSetting.RESOLUTION_FACTOR.key,
|
||||
IntSetting.RESOLUTION_FACTOR.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SwitchSetting(
|
||||
BooleanSetting.USE_INTEGER_SCALING,
|
||||
R.string.use_integer_scaling,
|
||||
R.string.use_integer_scaling_description,
|
||||
BooleanSetting.USE_INTEGER_SCALING.key,
|
||||
BooleanSetting.USE_INTEGER_SCALING.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SwitchSetting(
|
||||
|
|
@ -1148,6 +1170,17 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
|||
BooleanSetting.UPRIGHT_SCREEN.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
MultiChoiceSetting(
|
||||
IntListSetting.LAYOUTS_TO_CYCLE,
|
||||
R.string.layouts_to_cycle,
|
||||
R.string.layouts_to_cycle_description,
|
||||
R.array.landscapeLayouts,
|
||||
R.array.landscapeLayoutValues,
|
||||
IntListSetting.LAYOUTS_TO_CYCLE.key,
|
||||
IntListSetting.LAYOUTS_TO_CYCLE.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.PORTRAIT_SCREEN_LAYOUT,
|
||||
|
|
@ -1784,6 +1817,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
|||
BooleanSetting.ENABLE_RPC_SERVER.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SwitchSetting(
|
||||
BooleanSetting.TOGGLE_UNIQUE_DATA_CONSOLE_TYPE,
|
||||
R.string.toggle_unique_data_console_type,
|
||||
R.string.toggle_unique_data_console_type_desc,
|
||||
BooleanSetting.TOGGLE_UNIQUE_DATA_CONSOLE_TYPE.key,
|
||||
BooleanSetting.TOGGLE_UNIQUE_DATA_CONSOLE_TYPE.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SwitchSetting(
|
||||
BooleanSetting.DELAY_START_LLE_MODULES,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package org.citra.citra_emu.features.settings.ui.viewholder
|
||||
|
||||
import android.view.View
|
||||
import org.citra.citra_emu.databinding.ListItemSettingBinding
|
||||
import org.citra.citra_emu.features.settings.model.view.SettingsItem
|
||||
import org.citra.citra_emu.features.settings.model.view.MultiChoiceSetting
|
||||
import org.citra.citra_emu.features.settings.ui.SettingsAdapter
|
||||
|
||||
class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||
SettingViewHolder(binding.root, adapter) {
|
||||
private lateinit var setting: SettingsItem
|
||||
|
||||
override fun bind(item: SettingsItem) {
|
||||
setting = item
|
||||
binding.textSettingName.setText(item.nameId)
|
||||
if (item.descriptionId != 0) {
|
||||
binding.textSettingDescription.visibility = View.VISIBLE
|
||||
binding.textSettingDescription.setText(item.descriptionId)
|
||||
} else {
|
||||
binding.textSettingDescription.visibility = View.GONE
|
||||
}
|
||||
binding.textSettingValue.visibility = View.VISIBLE
|
||||
binding.textSettingValue.text = getTextSetting()
|
||||
|
||||
if (setting.isActive) {
|
||||
binding.textSettingName.alpha = 1f
|
||||
binding.textSettingDescription.alpha = 1f
|
||||
binding.textSettingValue.alpha = 1f
|
||||
} else {
|
||||
binding.textSettingName.alpha = 0.5f
|
||||
binding.textSettingDescription.alpha = 0.5f
|
||||
binding.textSettingValue.alpha = 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTextSetting(): String {
|
||||
when (val item = setting) {
|
||||
is MultiChoiceSetting -> {
|
||||
val resMgr = binding.textSettingDescription.context.resources
|
||||
val values = resMgr.getIntArray(item.valuesId)
|
||||
var resList:List<String> = emptyList();
|
||||
values.forEachIndexed { i: Int, value: Int ->
|
||||
if ((setting as MultiChoiceSetting).selectedValues.contains(value)) {
|
||||
resList = resList + resMgr.getStringArray(item.choicesId)[i];
|
||||
}
|
||||
}
|
||||
return resList.joinToString();
|
||||
}
|
||||
|
||||
else -> return ""
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(clicked: View) {
|
||||
if (!setting.isEditable || !setting.isEnabled) {
|
||||
adapter.onClickDisabledSetting(!setting.isEditable)
|
||||
return
|
||||
}
|
||||
|
||||
if (setting is MultiChoiceSetting) {
|
||||
adapter.onMultiChoiceClick(
|
||||
(setting as MultiChoiceSetting),
|
||||
bindingAdapterPosition
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLongClick(clicked: View): Boolean {
|
||||
if (setting.isActive) {
|
||||
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
|
||||
} else {
|
||||
adapter.onClickDisabledSetting(!setting.isEditable)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +67,10 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
|
|||
}
|
||||
|
||||
override fun onLongClick(clicked: View): Boolean {
|
||||
// no-op
|
||||
return true
|
||||
if (!setting.isEditable) {
|
||||
adapter.onClickDisabledSetting(true)
|
||||
return true
|
||||
}
|
||||
return setting.onLongClick?.invoke() ?: true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
|
@ -12,6 +12,7 @@ import org.citra.citra_emu.R
|
|||
import org.citra.citra_emu.features.settings.model.AbstractSetting
|
||||
import org.citra.citra_emu.features.settings.model.BooleanSetting
|
||||
import org.citra.citra_emu.features.settings.model.FloatSetting
|
||||
import org.citra.citra_emu.features.settings.model.IntListSetting
|
||||
import org.citra.citra_emu.features.settings.model.IntSetting
|
||||
import org.citra.citra_emu.features.settings.model.ScaledFloatSetting
|
||||
import org.citra.citra_emu.features.settings.model.SettingSection
|
||||
|
|
@ -255,6 +256,11 @@ object SettingsFile {
|
|||
return stringSetting
|
||||
}
|
||||
|
||||
val intListSetting = IntListSetting.from(key)
|
||||
if (intListSetting != null) {
|
||||
intListSetting.list = value.split(", ").map { it.toInt() }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package org.citra.citra_emu.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.InputDevice
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import org.citra.citra_emu.R
|
||||
import org.citra.citra_emu.databinding.DialogAutoMapBinding
|
||||
import org.citra.citra_emu.features.settings.model.view.InputBindingSetting
|
||||
import org.citra.citra_emu.utils.Log
|
||||
|
||||
/**
|
||||
* Captures a single button press to detect controller layout (Xbox vs Nintendo)
|
||||
* and d-pad type (axis vs button), then applies the appropriate bindings.
|
||||
*/
|
||||
class AutoMapDialogFragment : BottomSheetDialogFragment() {
|
||||
private var _binding: DialogAutoMapBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var onComplete: (() -> Unit)? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = DialogAutoMapBinding.inflate(inflater)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
BottomSheetBehavior.from<View>(view.parent as View).state =
|
||||
BottomSheetBehavior.STATE_EXPANDED
|
||||
|
||||
isCancelable = false
|
||||
view.requestFocus()
|
||||
view.setOnFocusChangeListener { v, hasFocus -> if (!hasFocus) v.requestFocus() }
|
||||
|
||||
binding.textTitle.setText(R.string.controller_auto_map)
|
||||
binding.textMessage.setText(R.string.auto_map_prompt)
|
||||
|
||||
binding.imageFaceButtons.setImageResource(R.drawable.automap_face_buttons)
|
||||
|
||||
dialog?.setOnKeyListener { _, _, event -> onKeyEvent(event) }
|
||||
|
||||
binding.buttonCancel.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
private fun onKeyEvent(event: KeyEvent): Boolean {
|
||||
if (event.action != KeyEvent.ACTION_UP) return false
|
||||
|
||||
val keyCode = event.keyCode
|
||||
val device = event.device
|
||||
|
||||
// Check if this is a Nintendo Switch Joy-Con (not Pro Controller).
|
||||
// Joy-Cons have unique quirks: split devices, non-standard D-pad scan codes,
|
||||
// partial A/B swap but no X/Y swap from Android's evdev layer.
|
||||
val isJoyCon = InputBindingSetting.isJoyCon(device)
|
||||
|
||||
if (isJoyCon) {
|
||||
Log.info("[AutoMap] Detected Joy-Con - using Joy-Con mappings")
|
||||
InputBindingSetting.clearAllBindings()
|
||||
InputBindingSetting.applyJoyConBindings()
|
||||
onComplete?.invoke()
|
||||
dismiss()
|
||||
return true
|
||||
}
|
||||
|
||||
// For non-Joy-Con controllers, determine layout from which keycode arrives
|
||||
// for the east/right position.
|
||||
// The user is pressing the button in the "A" (east/right) position on the 3DS diamond.
|
||||
// Xbox layout: east position sends KEYCODE_BUTTON_B (97)
|
||||
// Nintendo layout: east position sends KEYCODE_BUTTON_A (96)
|
||||
val isNintendoLayout = when (keyCode) {
|
||||
KeyEvent.KEYCODE_BUTTON_A -> true
|
||||
KeyEvent.KEYCODE_BUTTON_B -> false
|
||||
else -> {
|
||||
// Unrecognized button - ignore and wait for a valid press
|
||||
Log.warning("[AutoMap] Ignoring unrecognized keycode $keyCode, waiting for A or B")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
val layoutName = if (isNintendoLayout) "Nintendo" else "Xbox"
|
||||
Log.info("[AutoMap] Detected $layoutName layout (keyCode=$keyCode)")
|
||||
|
||||
val useAxisDpad = detectDpadType(device)
|
||||
|
||||
val dpadName = if (useAxisDpad) "axis" else "button"
|
||||
Log.info("[AutoMap] Detected $dpadName d-pad (device=${device?.name})")
|
||||
|
||||
InputBindingSetting.clearAllBindings()
|
||||
InputBindingSetting.applyAutoMapBindings(isNintendoLayout, useAxisDpad)
|
||||
|
||||
onComplete?.invoke()
|
||||
dismiss()
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "AutoMapDialogFragment"
|
||||
|
||||
fun newInstance(
|
||||
onComplete: () -> Unit
|
||||
): AutoMapDialogFragment {
|
||||
val dialog = AutoMapDialogFragment()
|
||||
dialog.onComplete = onComplete
|
||||
return dialog
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true for axis d-pad (HAT_X/HAT_Y), false for button d-pad (DPAD_UP/DOWN/LEFT/RIGHT).
|
||||
* Prefers axis when both are present. Defaults to axis if detection fails.
|
||||
*/
|
||||
private fun detectDpadType(device: InputDevice?): Boolean {
|
||||
if (device == null) return true
|
||||
|
||||
val hasAxisDpad = device.motionRanges.any {
|
||||
it.axis == MotionEvent.AXIS_HAT_X || it.axis == MotionEvent.AXIS_HAT_Y
|
||||
}
|
||||
|
||||
if (hasAxisDpad) return true
|
||||
|
||||
val dpadKeyCodes = intArrayOf(
|
||||
KeyEvent.KEYCODE_DPAD_UP,
|
||||
KeyEvent.KEYCODE_DPAD_DOWN,
|
||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT
|
||||
)
|
||||
val hasButtonDpad = device.hasKeys(*dpadKeyCodes).any { it }
|
||||
|
||||
return !hasButtonDpad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import android.content.DialogInterface
|
|||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.os.BatteryManager
|
||||
import android.os.Build
|
||||
|
|
@ -132,14 +133,16 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||
var intentGame: Game? = null
|
||||
if (intentUri != null) {
|
||||
intentGame = if (Game.extensions.contains(FileUtil.getExtension(intentUri))) {
|
||||
GameHelper.getGame(intentUri, isInstalled = false, addedToLibrary = false)
|
||||
// isInstalled, addedToLibrary and mediaType do not matter here
|
||||
GameHelper.getGame(intentUri, isInstalled = false, addedToLibrary = false, mediaType = Game.MediaType.GAME_CARD)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else if (oldIntentInfo.first != null) {
|
||||
val gameUri = Uri.parse(oldIntentInfo.first)
|
||||
intentGame = if (Game.extensions.contains(FileUtil.getExtension(gameUri))) {
|
||||
GameHelper.getGame(gameUri, isInstalled = false, addedToLibrary = false)
|
||||
// isInstalled, addedToLibrary and mediaType do not matter here
|
||||
GameHelper.getGame(gameUri, isInstalled = false, addedToLibrary = false, mediaType = Game.MediaType.GAME_CARD)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
@ -175,6 +178,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentEmulationBinding.inflate(inflater)
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_landscape_screen_layout).isVisible =
|
||||
CitraApplication.appContext.resources.configuration.orientation !=
|
||||
Configuration.ORIENTATION_PORTRAIT
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_portrait_screen_layout).isVisible =
|
||||
CitraApplication.appContext.resources.configuration.orientation ==
|
||||
Configuration.ORIENTATION_PORTRAIT
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import org.citra.citra_emu.adapters.HomeSettingAdapter
|
|||
import org.citra.citra_emu.databinding.DialogSoftwareKeyboardBinding
|
||||
import org.citra.citra_emu.databinding.FragmentHomeSettingsBinding
|
||||
import org.citra.citra_emu.features.settings.model.Settings
|
||||
import org.citra.citra_emu.features.settings.model.StringSetting
|
||||
import org.citra.citra_emu.features.settings.SettingKeys
|
||||
import org.citra.citra_emu.features.settings.ui.SettingsActivity
|
||||
import org.citra.citra_emu.features.settings.utils.SettingsFile
|
||||
import org.citra.citra_emu.model.Game
|
||||
|
|
@ -89,7 +89,7 @@ class HomeSettingsFragment : Fragment() {
|
|||
{
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val inputBinding = DialogSoftwareKeyboardBinding.inflate(inflater)
|
||||
var textInputValue: String = preferences.getString("last_artic_base_addr", "")!!
|
||||
var textInputValue: String = preferences.getString(SettingKeys.last_artic_base_addr(), "")!!
|
||||
|
||||
inputBinding.editTextInput.setText(textInputValue)
|
||||
inputBinding.editTextInput.doOnTextChanged { text, _, _, _ ->
|
||||
|
|
@ -103,7 +103,7 @@ class HomeSettingsFragment : Fragment() {
|
|||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
if (textInputValue.isNotEmpty()) {
|
||||
preferences.edit()
|
||||
.putString("last_artic_base_addr", textInputValue)
|
||||
.putString(SettingKeys.last_artic_base_addr(), textInputValue)
|
||||
.apply()
|
||||
val menu = Game(
|
||||
title = getString(R.string.artic_base),
|
||||
|
|
|
|||
|
|
@ -567,7 +567,7 @@ class SetupFragment : Fragment() {
|
|||
}
|
||||
|
||||
if (!BuildUtil.isGooglePlayBuild) {
|
||||
if (NativeLibrary.getUserDirectory(result) == "") {
|
||||
if (NativeLibrary.getNativePath(result) == "") {
|
||||
SelectUserDirectoryDialogFragment.newInstance(
|
||||
mainActivity,
|
||||
R.string.invalid_selection,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import org.citra.citra_emu.R
|
|||
import org.citra.citra_emu.databinding.DialogSoftwareKeyboardBinding
|
||||
import org.citra.citra_emu.databinding.FragmentSystemFilesBinding
|
||||
import org.citra.citra_emu.features.settings.model.Settings
|
||||
import org.citra.citra_emu.features.settings.SettingKeys
|
||||
import org.citra.citra_emu.model.Game
|
||||
import org.citra.citra_emu.utils.SystemSaveGame
|
||||
import org.citra.citra_emu.viewmodel.GamesViewModel
|
||||
|
|
@ -177,7 +178,7 @@ class SystemFilesFragment : Fragment() {
|
|||
binding.buttonSetUpSystemFiles.setOnClickListener {
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val inputBinding = DialogSoftwareKeyboardBinding.inflate(inflater)
|
||||
var textInputValue: String = preferences.getString("last_artic_base_addr", "")!!
|
||||
var textInputValue: String = preferences.getString(SettingKeys.last_artic_base_addr(), "")!!
|
||||
|
||||
val progressDialog = showProgressDialog(
|
||||
getText(R.string.setup_system_files),
|
||||
|
|
@ -274,7 +275,7 @@ class SystemFilesFragment : Fragment() {
|
|||
.setPositiveButton(android.R.string.ok) { diag, _ ->
|
||||
if (textInputValue.isNotEmpty() && !(!buttonO3ds.isChecked && !buttonN3ds.isChecked)) {
|
||||
preferences.edit()
|
||||
.putString("last_artic_base_addr", textInputValue)
|
||||
.putString(SettingKeys.last_artic_base_addr(), textInputValue)
|
||||
.apply()
|
||||
val menu = Game(
|
||||
title = getString(R.string.artic_base),
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@ import org.citra.citra_emu.activities.EmulationActivity
|
|||
@Parcelize
|
||||
@Serializable
|
||||
class Game(
|
||||
val valid: Boolean = false,
|
||||
val title: String = "",
|
||||
val description: String = "",
|
||||
val path: String = "",
|
||||
val titleId: Long = 0L,
|
||||
val mediaType: MediaType = MediaType.GAME_CARD,
|
||||
val company: String = "",
|
||||
val regions: String = "",
|
||||
val isInstalled: Boolean = false,
|
||||
|
|
@ -58,10 +60,23 @@ class Game(
|
|||
result = 31 * result + regions.hashCode()
|
||||
result = 31 * result + path.hashCode()
|
||||
result = 31 * result + titleId.hashCode()
|
||||
result = 31 * result + mediaType.hashCode()
|
||||
result = 31 * result + company.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
enum class MediaType(val value: Int) {
|
||||
NAND(0),
|
||||
SDMC(1),
|
||||
GAME_CARD(2);
|
||||
|
||||
companion object {
|
||||
fun fromInt(value: Int): MediaType? {
|
||||
return MediaType.entries.find { it.value == value }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val allExtensions: Set<String> get() = extensions + badExtensions
|
||||
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
}
|
||||
|
||||
if (!BuildUtil.isGooglePlayBuild) {
|
||||
if (NativeLibrary.getUserDirectory(result) == "") {
|
||||
if (NativeLibrary.getNativePath(result) == "") {
|
||||
SelectUserDirectoryDialogFragment.newInstance(
|
||||
this,
|
||||
R.string.invalid_selection,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
|
@ -12,9 +12,11 @@ import androidx.core.app.NotificationCompat
|
|||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import org.citra.citra_emu.NativeLibrary
|
||||
import org.citra.citra_emu.NativeLibrary.InstallStatus
|
||||
import org.citra.citra_emu.R
|
||||
import org.citra.citra_emu.utils.FileUtil.getFilename
|
||||
import androidx.core.net.toUri
|
||||
|
||||
class CiaInstallWorker(
|
||||
val context: Context,
|
||||
|
|
@ -131,7 +133,7 @@ class CiaInstallWorker(
|
|||
installProgressBuilder.setOngoing(true)
|
||||
setProgressCallback(100, 0)
|
||||
selectedFiles.forEachIndexed { i, file ->
|
||||
val filename = getFilename(Uri.parse(file))
|
||||
val filename = getFilename(file.toUri())
|
||||
installProgressBuilder.setContentText(
|
||||
context.getString(
|
||||
R.string.cia_install_notification_installing,
|
||||
|
|
@ -140,7 +142,13 @@ class CiaInstallWorker(
|
|||
selectedFiles.size
|
||||
)
|
||||
)
|
||||
val res = installCIA(file)
|
||||
var fileFinal: String
|
||||
if (BuildUtil.isGooglePlayBuild) {
|
||||
fileFinal = file
|
||||
} else {
|
||||
fileFinal = "!" + NativeLibrary.getNativePath(file.toUri())
|
||||
}
|
||||
val res = installCIA(fileFinal)
|
||||
notifyInstallStatus(filename, res)
|
||||
}
|
||||
notificationManager.cancel(PROGRESS_NOTIFICATION_ID)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ object DiskShaderCacheProgress {
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun loadProgress(stage: LoadCallbackStage, progress: Int, max: Int) {
|
||||
fun loadProgress(stage: LoadCallbackStage, progress: Int, max: Int, obj: String) {
|
||||
val emulationActivity = NativeLibrary.sEmulationActivity.get()
|
||||
if (emulationActivity == null) {
|
||||
Log.error("[DiskShaderCacheProgress] EmulationActivity not present")
|
||||
|
|
@ -40,7 +40,7 @@ object DiskShaderCacheProgress {
|
|||
)
|
||||
|
||||
LoadCallbackStage.Build -> emulationViewModel.updateProgress(
|
||||
emulationActivity.getString(R.string.building_shaders),
|
||||
emulationActivity.getString(R.string.building_shaders, obj ),
|
||||
progress,
|
||||
max
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import androidx.core.net.toUri
|
|||
import androidx.documentfile.provider.DocumentFile
|
||||
import org.citra.citra_emu.CitraApplication
|
||||
import org.citra.citra_emu.model.CheapDocument
|
||||
import org.citra.citra_emu.utils.BuildUtil
|
||||
import java.io.IOException
|
||||
import java.net.URLDecoder
|
||||
import java.nio.file.Paths
|
||||
import java.util.StringTokenizer
|
||||
|
|
@ -77,8 +79,9 @@ class DocumentsTree {
|
|||
|
||||
@Synchronized
|
||||
fun getFilename(filepath: String): String {
|
||||
val node = resolvePath(filepath) ?: return ""
|
||||
return node.name
|
||||
val components = filepath.split(DELIMITER).filter { it.isNotEmpty() }
|
||||
val filename = components.last()
|
||||
return filename
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
|
@ -260,6 +263,17 @@ class DocumentsTree {
|
|||
|
||||
@Synchronized
|
||||
private fun resolvePath(filepath: String): DocumentsNode? {
|
||||
if (!BuildUtil.isGooglePlayBuild) {
|
||||
var isLegalPath = false
|
||||
kotlinDirectoryAccessWhitelist.forEach {
|
||||
if (filepath.startsWith(it)) {
|
||||
isLegalPath = true
|
||||
}
|
||||
}
|
||||
if (!isLegalPath) {
|
||||
throw IOException("Attempted to resolve forbidden path: " + filepath)
|
||||
}
|
||||
}
|
||||
root ?: return null
|
||||
val tokens = StringTokenizer(filepath, DELIMITER, false)
|
||||
var iterator = root
|
||||
|
|
@ -351,5 +365,10 @@ class DocumentsTree {
|
|||
|
||||
companion object {
|
||||
const val DELIMITER = "/"
|
||||
val kotlinDirectoryAccessWhitelist = arrayOf(
|
||||
"/config/",
|
||||
"/log/",
|
||||
"/gpu_drivers/",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ object GameHelper {
|
|||
|
||||
addGamesRecursive(games, FileUtil.listFiles(gamesUri), 3)
|
||||
NativeLibrary.getInstalledGamePaths().forEach {
|
||||
games.add(getGame(Uri.parse(it), isInstalled = true, addedToLibrary = true))
|
||||
games.add(getGame(Uri.parse(it.path), isInstalled = true, addedToLibrary = true, it.mediaType))
|
||||
}
|
||||
|
||||
// Cache list of games found on disk
|
||||
|
|
@ -62,27 +62,41 @@ object GameHelper {
|
|||
addGamesRecursive(games, FileUtil.listFiles(it.uri), depth - 1)
|
||||
} else {
|
||||
if (Game.allExtensions.contains(FileUtil.getExtension(it.uri))) {
|
||||
games.add(getGame(it.uri, isInstalled = false, addedToLibrary = true))
|
||||
games.add(getGame(it.uri, isInstalled = false, addedToLibrary = true, Game.MediaType.GAME_CARD))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getGame(uri: Uri, isInstalled: Boolean, addedToLibrary: Boolean): Game {
|
||||
fun getGame(uri: Uri, isInstalled: Boolean, addedToLibrary: Boolean, mediaType: Game.MediaType): Game {
|
||||
val filePath = uri.toString()
|
||||
var gameInfo: GameInfo? = GameInfo(filePath)
|
||||
var nativePath: String? = null
|
||||
var gameInfo: GameInfo?
|
||||
if (BuildUtil.isGooglePlayBuild || FileUtil.isNativePath(filePath)) {
|
||||
gameInfo = GameInfo(filePath)
|
||||
} else {
|
||||
nativePath = "!" + NativeLibrary.getNativePath(uri);
|
||||
gameInfo = GameInfo(nativePath)
|
||||
}
|
||||
|
||||
if (gameInfo?.isValid() == false) {
|
||||
val valid = gameInfo.isValid()
|
||||
if (!valid) {
|
||||
gameInfo = null
|
||||
}
|
||||
|
||||
val isEncrypted = gameInfo?.isEncrypted() == true
|
||||
|
||||
val newGame = Game(
|
||||
valid,
|
||||
(gameInfo?.getTitle() ?: FileUtil.getFilename(uri)).replace("[\\t\\n\\r]+".toRegex(), " "),
|
||||
filePath.replace("\n", " "),
|
||||
filePath,
|
||||
if (BuildUtil.isGooglePlayBuild || FileUtil.isNativePath(filePath)) {
|
||||
filePath
|
||||
} else {
|
||||
nativePath!!
|
||||
},
|
||||
gameInfo?.getTitleID() ?: 0,
|
||||
mediaType,
|
||||
gameInfo?.getCompany() ?: "",
|
||||
if (isEncrypted) { CitraApplication.appContext.getString(R.string.unsupported_encrypted) } else { gameInfo?.getRegions() ?: "" },
|
||||
isInstalled,
|
||||
|
|
|
|||
|
|
@ -4,28 +4,43 @@
|
|||
|
||||
package org.citra.citra_emu.utils
|
||||
|
||||
import org.citra.citra_emu.utils.BuildUtil
|
||||
import java.io.File
|
||||
import android.content.Context
|
||||
import android.os.storage.StorageManager
|
||||
|
||||
object RemovableStorageHelper {
|
||||
// This really shouldn't be necessary, but the Android API seemingly
|
||||
// doesn't have a way of doing this?
|
||||
fun getRemovableStoragePath(idString: String): String? {
|
||||
BuildUtil.assertNotGooglePlay()
|
||||
|
||||
// On certain Android flavours the external storage mount location can
|
||||
// vary, so add extra cases here if we discover them.
|
||||
val possibleMountPaths = listOf("/mnt/media_rw/$idString", "/storage/$idString")
|
||||
private val pathCache = mutableMapOf<String, String?>()
|
||||
private var scanned = false
|
||||
|
||||
for (mountPath in possibleMountPaths) {
|
||||
val pathFile = File(mountPath);
|
||||
if (pathFile.exists()) {
|
||||
// TODO: Cache which mount location is being used for the remainder of the
|
||||
// session, as it should never change. -OS
|
||||
return pathFile.absolutePath
|
||||
}
|
||||
private fun scanVolumes(context: Context) {
|
||||
if (scanned) {
|
||||
return
|
||||
}
|
||||
|
||||
return null
|
||||
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
|
||||
|
||||
for (volume in storageManager.storageVolumes) {
|
||||
if (!volume.isRemovable) {
|
||||
continue
|
||||
}
|
||||
|
||||
val uuid = volume.uuid ?: continue
|
||||
val dir = volume.directory ?: continue
|
||||
|
||||
pathCache[uuid.uppercase()] = dir.absolutePath
|
||||
}
|
||||
|
||||
scanned = true
|
||||
}
|
||||
|
||||
fun getRemovableStoragePath(context: Context, idString: String): String? {
|
||||
BuildUtil.assertNotGooglePlay()
|
||||
val key = idString.uppercase()
|
||||
|
||||
if (!scanned) {
|
||||
scanVolumes(context)
|
||||
}
|
||||
|
||||
return pathCache[key]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ add_library(citra-android SHARED
|
|||
game_info.cpp
|
||||
id_cache.cpp
|
||||
id_cache.h
|
||||
jni_setting_keys.cpp
|
||||
native.cpp
|
||||
ndk_motion.cpp
|
||||
ndk_motion.h
|
||||
|
|
|
|||
|
|
@ -4,13 +4,16 @@
|
|||
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <INIReader.h>
|
||||
#include <boost/hana/string.hpp>
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/param_package.h"
|
||||
#include "common/setting_keys.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/cfg/cfg.h"
|
||||
|
|
@ -25,11 +28,11 @@
|
|||
|
||||
Config::Config() {
|
||||
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
|
||||
sdl2_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "config.ini";
|
||||
android_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "config.ini";
|
||||
std::string ini_buffer;
|
||||
FileUtil::ReadFileToString(true, sdl2_config_loc, ini_buffer);
|
||||
FileUtil::ReadFileToString(true, android_config_loc, ini_buffer);
|
||||
if (!ini_buffer.empty()) {
|
||||
sdl2_config = std::make_unique<INIReader>(ini_buffer.c_str(), ini_buffer.size());
|
||||
android_config = std::make_unique<INIReader>(ini_buffer.c_str(), ini_buffer.size());
|
||||
}
|
||||
|
||||
Reload();
|
||||
|
|
@ -38,15 +41,15 @@ Config::Config() {
|
|||
Config::~Config() = default;
|
||||
|
||||
bool Config::LoadINI(const std::string& default_contents, bool retry) {
|
||||
const std::string& location = this->sdl2_config_loc;
|
||||
if (sdl2_config == nullptr || sdl2_config->ParseError() < 0) {
|
||||
const std::string& location = this->android_config_loc;
|
||||
if (android_config == nullptr || android_config->ParseError() < 0) {
|
||||
if (retry) {
|
||||
LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location);
|
||||
FileUtil::CreateFullPath(location);
|
||||
FileUtil::WriteStringToFile(true, location, default_contents);
|
||||
std::string ini_buffer;
|
||||
FileUtil::ReadFileToString(true, location, ini_buffer);
|
||||
sdl2_config =
|
||||
android_config =
|
||||
std::make_unique<INIReader>(ini_buffer.c_str(), ini_buffer.size()); // Reopen file
|
||||
|
||||
return LoadINI(default_contents, false);
|
||||
|
|
@ -77,7 +80,8 @@ static const std::array<int, Settings::NativeAnalog::NumAnalogs> default_analogs
|
|||
|
||||
template <>
|
||||
void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
|
||||
std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
|
||||
std::string setting_value =
|
||||
android_config->Get(group, setting.GetLabel(), setting.GetDefault());
|
||||
if (setting_value.empty()) {
|
||||
setting_value = setting.GetDefault();
|
||||
}
|
||||
|
|
@ -86,15 +90,15 @@ void Config::ReadSetting(const std::string& group, Settings::Setting<std::string
|
|||
|
||||
template <>
|
||||
void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
|
||||
setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
||||
setting = android_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
||||
}
|
||||
|
||||
template <typename Type, bool ranged>
|
||||
void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
|
||||
if constexpr (std::is_floating_point_v<Type>) {
|
||||
setting = sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault());
|
||||
setting = android_config->GetReal(group, setting.GetLabel(), setting.GetDefault());
|
||||
} else {
|
||||
setting = static_cast<Type>(sdl2_config->GetInteger(
|
||||
setting = static_cast<Type>(android_config->GetInteger(
|
||||
group, setting.GetLabel(), static_cast<long>(setting.GetDefault())));
|
||||
}
|
||||
}
|
||||
|
|
@ -103,30 +107,30 @@ void Config::ReadValues() {
|
|||
// Controls
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
std::string default_param = InputManager::GenerateButtonParamPackage(default_buttons[i]);
|
||||
Settings::values.current_input_profile.buttons[i] =
|
||||
sdl2_config->GetString("Controls", Settings::NativeButton::mapping[i], default_param);
|
||||
Settings::values.current_input_profile.buttons[i] = android_config->GetString(
|
||||
"Controls", Settings::NativeButton::mapping[i], default_param);
|
||||
if (Settings::values.current_input_profile.buttons[i].empty())
|
||||
Settings::values.current_input_profile.buttons[i] = default_param;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
std::string default_param = InputManager::GenerateAnalogParamPackage(default_analogs[i]);
|
||||
Settings::values.current_input_profile.analogs[i] =
|
||||
sdl2_config->GetString("Controls", Settings::NativeAnalog::mapping[i], default_param);
|
||||
Settings::values.current_input_profile.analogs[i] = android_config->GetString(
|
||||
"Controls", Settings::NativeAnalog::mapping[i], default_param);
|
||||
if (Settings::values.current_input_profile.analogs[i].empty())
|
||||
Settings::values.current_input_profile.analogs[i] = default_param;
|
||||
}
|
||||
|
||||
Settings::values.current_input_profile.motion_device = sdl2_config->GetString(
|
||||
Settings::values.current_input_profile.motion_device = android_config->GetString(
|
||||
"Controls", "motion_device",
|
||||
"engine:motion_emu,update_period:100,sensitivity:0.01,tilt_clamp:90.0");
|
||||
Settings::values.current_input_profile.touch_device =
|
||||
sdl2_config->GetString("Controls", "touch_device", "engine:emu_window");
|
||||
Settings::values.current_input_profile.udp_input_address = sdl2_config->GetString(
|
||||
android_config->GetString("Controls", "touch_device", "engine:emu_window");
|
||||
Settings::values.current_input_profile.udp_input_address = android_config->GetString(
|
||||
"Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR);
|
||||
Settings::values.current_input_profile.udp_input_port =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Controls", "udp_input_port",
|
||||
InputCommon::CemuhookUDP::DEFAULT_PORT));
|
||||
static_cast<u16>(android_config->GetInteger("Controls", "udp_input_port",
|
||||
InputCommon::CemuhookUDP::DEFAULT_PORT));
|
||||
|
||||
ReadSetting("Controls", Settings::values.use_artic_base_controller);
|
||||
|
||||
|
|
@ -135,9 +139,9 @@ void Config::ReadValues() {
|
|||
ReadSetting("Core", Settings::values.cpu_clock_percentage);
|
||||
|
||||
// Renderer
|
||||
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", true);
|
||||
Settings::values.use_gles = android_config->GetBoolean("Renderer", "use_gles", true);
|
||||
Settings::values.shaders_accurate_mul =
|
||||
sdl2_config->GetBoolean("Renderer", "shaders_accurate_mul", false);
|
||||
android_config->GetBoolean("Renderer", "shaders_accurate_mul", false);
|
||||
ReadSetting("Renderer", Settings::values.graphics_api);
|
||||
ReadSetting("Renderer", Settings::values.async_presentation);
|
||||
ReadSetting("Renderer", Settings::values.async_shader_compilation);
|
||||
|
|
@ -152,7 +156,7 @@ void Config::ReadValues() {
|
|||
ReadSetting("Renderer", Settings::values.texture_sampling);
|
||||
ReadSetting("Renderer", Settings::values.turbo_limit);
|
||||
// Workaround to map Android setting for enabling the frame limiter to the format Citra expects
|
||||
if (sdl2_config->GetBoolean("Renderer", "use_frame_limit", true)) {
|
||||
if (android_config->GetBoolean("Renderer", "use_frame_limit", true)) {
|
||||
ReadSetting("Renderer", Settings::values.frame_limit);
|
||||
} else {
|
||||
Settings::values.frame_limit = 0;
|
||||
|
|
@ -166,8 +170,9 @@ void Config::ReadValues() {
|
|||
else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Interlaced)
|
||||
default_shader = "Horizontal (builtin)";
|
||||
Settings::values.pp_shader_name =
|
||||
sdl2_config->GetString("Renderer", "pp_shader_name", default_shader);
|
||||
android_config->GetString("Renderer", "pp_shader_name", default_shader);
|
||||
ReadSetting("Renderer", Settings::values.filter_mode);
|
||||
ReadSetting("Renderer", Settings::values.use_integer_scaling);
|
||||
|
||||
ReadSetting("Renderer", Settings::values.bg_red);
|
||||
ReadSetting("Renderer", Settings::values.bg_green);
|
||||
|
|
@ -180,18 +185,19 @@ void Config::ReadValues() {
|
|||
// Layout
|
||||
// Somewhat inelegant solution to ensure layout value is between 0 and 5 on read
|
||||
// since older config files may have other values
|
||||
int layoutInt = (int)sdl2_config->GetInteger(
|
||||
int layoutInt = (int)android_config->GetInteger(
|
||||
"Layout", "layout_option", static_cast<int>(Settings::LayoutOption::LargeScreen));
|
||||
if (layoutInt < 0 || layoutInt > 5) {
|
||||
layoutInt = static_cast<int>(Settings::LayoutOption::LargeScreen);
|
||||
}
|
||||
Settings::values.layout_option = static_cast<Settings::LayoutOption>(layoutInt);
|
||||
Settings::values.screen_gap = static_cast<int>(sdl2_config->GetReal("Layout", "screen_gap", 0));
|
||||
Settings::values.screen_gap =
|
||||
static_cast<int>(android_config->GetReal("Layout", "screen_gap", 0));
|
||||
Settings::values.large_screen_proportion =
|
||||
static_cast<float>(sdl2_config->GetReal("Layout", "large_screen_proportion", 2.25));
|
||||
static_cast<float>(android_config->GetReal("Layout", "large_screen_proportion", 2.25));
|
||||
Settings::values.small_screen_position = static_cast<Settings::SmallScreenPosition>(
|
||||
sdl2_config->GetInteger("Layout", "small_screen_position",
|
||||
static_cast<int>(Settings::SmallScreenPosition::TopRight)));
|
||||
android_config->GetInteger("Layout", "small_screen_position",
|
||||
static_cast<int>(Settings::SmallScreenPosition::TopRight)));
|
||||
ReadSetting("Layout", Settings::values.screen_gap);
|
||||
ReadSetting("Layout", Settings::values.custom_top_x);
|
||||
ReadSetting("Layout", Settings::values.custom_top_y);
|
||||
|
|
@ -208,12 +214,12 @@ void Config::ReadValues() {
|
|||
ReadSetting("Layout", Settings::values.upright_screen);
|
||||
|
||||
Settings::values.portrait_layout_option =
|
||||
static_cast<Settings::PortraitLayoutOption>(sdl2_config->GetInteger(
|
||||
static_cast<Settings::PortraitLayoutOption>(android_config->GetInteger(
|
||||
"Layout", "portrait_layout_option",
|
||||
static_cast<int>(Settings::PortraitLayoutOption::PortraitTopFullWidth)));
|
||||
Settings::values.secondary_display_layout = static_cast<Settings::SecondaryDisplayLayout>(
|
||||
sdl2_config->GetInteger("Layout", "secondary_display_layout",
|
||||
static_cast<int>(Settings::SecondaryDisplayLayout::None)));
|
||||
android_config->GetInteger("Layout", Settings::HKeys::secondary_display_layout.c_str(),
|
||||
static_cast<int>(Settings::SecondaryDisplayLayout::None)));
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_x);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_y);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_width);
|
||||
|
|
@ -252,7 +258,8 @@ void Config::ReadValues() {
|
|||
ReadSetting("System", Settings::values.region_value);
|
||||
ReadSetting("System", Settings::values.init_clock);
|
||||
{
|
||||
std::string time = sdl2_config->GetString("System", "init_time", "946681277");
|
||||
std::string time =
|
||||
android_config->GetString("System", Settings::HKeys::init_time.c_str(), "946681277");
|
||||
try {
|
||||
Settings::values.init_time = std::stoll(time);
|
||||
} catch (...) {
|
||||
|
|
@ -267,24 +274,27 @@ void Config::ReadValues() {
|
|||
|
||||
// Camera
|
||||
using namespace Service::CAM;
|
||||
Settings::values.camera_name[OuterRightCamera] =
|
||||
sdl2_config->GetString("Camera", "camera_outer_right_name", "ndk");
|
||||
Settings::values.camera_config[OuterRightCamera] = sdl2_config->GetString(
|
||||
"Camera", "camera_outer_right_config", std::string{Camera::NDK::BackCameraPlaceholder});
|
||||
Settings::values.camera_name[OuterRightCamera] = android_config->GetString(
|
||||
"Camera", Settings::HKeys::camera_outer_right_name.c_str(), "ndk");
|
||||
Settings::values.camera_config[OuterRightCamera] =
|
||||
android_config->GetString("Camera", Settings::HKeys::camera_outer_right_config.c_str(),
|
||||
std::string{Camera::NDK::BackCameraPlaceholder});
|
||||
Settings::values.camera_flip[OuterRightCamera] =
|
||||
sdl2_config->GetInteger("Camera", "camera_outer_right_flip", 0);
|
||||
android_config->GetInteger("Camera", Settings::HKeys::camera_outer_right_flip.c_str(), 0);
|
||||
Settings::values.camera_name[InnerCamera] =
|
||||
sdl2_config->GetString("Camera", "camera_inner_name", "ndk");
|
||||
Settings::values.camera_config[InnerCamera] = sdl2_config->GetString(
|
||||
"Camera", "camera_inner_config", std::string{Camera::NDK::FrontCameraPlaceholder});
|
||||
android_config->GetString("Camera", Settings::HKeys::camera_inner_name.c_str(), "ndk");
|
||||
Settings::values.camera_config[InnerCamera] =
|
||||
android_config->GetString("Camera", Settings::HKeys::camera_inner_config.c_str(),
|
||||
std::string{Camera::NDK::FrontCameraPlaceholder});
|
||||
Settings::values.camera_flip[InnerCamera] =
|
||||
sdl2_config->GetInteger("Camera", "camera_inner_flip", 0);
|
||||
android_config->GetInteger("Camera", Settings::HKeys::camera_inner_flip.c_str(), 0);
|
||||
Settings::values.camera_name[OuterLeftCamera] =
|
||||
sdl2_config->GetString("Camera", "camera_outer_left_name", "ndk");
|
||||
Settings::values.camera_config[OuterLeftCamera] = sdl2_config->GetString(
|
||||
"Camera", "camera_outer_left_config", std::string{Camera::NDK::BackCameraPlaceholder});
|
||||
android_config->GetString("Camera", Settings::HKeys::camera_outer_left_name.c_str(), "ndk");
|
||||
Settings::values.camera_config[OuterLeftCamera] =
|
||||
android_config->GetString("Camera", Settings::HKeys::camera_outer_left_config.c_str(),
|
||||
std::string{Camera::NDK::BackCameraPlaceholder});
|
||||
Settings::values.camera_flip[OuterLeftCamera] =
|
||||
sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0);
|
||||
android_config->GetInteger("Camera", Settings::HKeys::camera_outer_left_flip.c_str(), 0);
|
||||
|
||||
// Miscellaneous
|
||||
ReadSetting("Miscellaneous", Settings::values.log_filter);
|
||||
|
|
@ -299,26 +309,43 @@ void Config::ReadValues() {
|
|||
|
||||
// Debugging
|
||||
Settings::values.record_frame_times =
|
||||
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
|
||||
android_config->GetBoolean("Debugging", Settings::HKeys::record_frame_times.c_str(), false);
|
||||
ReadSetting("Debugging", Settings::values.renderer_debug);
|
||||
ReadSetting("Debugging", Settings::values.use_gdbstub);
|
||||
ReadSetting("Debugging", Settings::values.gdbstub_port);
|
||||
ReadSetting("Debugging", Settings::values.instant_debug_log);
|
||||
ReadSetting("Debugging", Settings::values.enable_rpc_server);
|
||||
ReadSetting("Debugging", Settings::values.toggle_unique_data_console_type);
|
||||
|
||||
for (const auto& service_module : Service::service_module_map) {
|
||||
bool use_lle = sdl2_config->GetBoolean("Debugging", "LLE\\" + service_module.name, false);
|
||||
bool use_lle =
|
||||
android_config->GetBoolean("Debugging", "LLE\\" + service_module.name, false);
|
||||
Settings::values.lle_modules.emplace(service_module.name, use_lle);
|
||||
}
|
||||
|
||||
// Web Service
|
||||
NetSettings::values.web_api_url =
|
||||
sdl2_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org");
|
||||
NetSettings::values.citra_username = sdl2_config->GetString("WebService", "citra_username", "");
|
||||
NetSettings::values.citra_token = sdl2_config->GetString("WebService", "citra_token", "");
|
||||
android_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org");
|
||||
NetSettings::values.citra_username =
|
||||
android_config->GetString("WebService", "citra_username", "");
|
||||
NetSettings::values.citra_token = android_config->GetString("WebService", "citra_token", "");
|
||||
}
|
||||
|
||||
void Config::Reload() {
|
||||
LoadINI(DefaultINI::sdl2_config_file);
|
||||
for (auto key = Settings::Keys::keys_array.begin(); key != Settings::Keys::keys_array.end();
|
||||
++key) {
|
||||
const auto key_declaration_string = std::string(*key) + " =";
|
||||
// FIXME: This code looks so ass when formatted by clang-format -OS
|
||||
if (std::ranges::find(DefaultINI::android_config_omitted_keys, *key) ==
|
||||
std::end(DefaultINI::android_config_omitted_keys) &&
|
||||
std::string(DefaultINI::android_config_default_file_content)
|
||||
.find(key_declaration_string) == std::string::npos) {
|
||||
ASSERT_MSG(false,
|
||||
"Validation of default content config failed: Missing or malformed key "
|
||||
"declaration {}",
|
||||
*key);
|
||||
}
|
||||
}
|
||||
LoadINI(DefaultINI::android_config_default_file_content);
|
||||
ReadValues();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
|
@ -12,8 +12,8 @@ class INIReader;
|
|||
|
||||
class Config {
|
||||
private:
|
||||
std::unique_ptr<INIReader> sdl2_config;
|
||||
std::string sdl2_config_loc;
|
||||
std::unique_ptr<INIReader> android_config;
|
||||
std::string android_config_loc;
|
||||
|
||||
bool LoadINI(const std::string& default_contents = "", bool retry = true);
|
||||
void ReadValues();
|
||||
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
private:
|
||||
/**
|
||||
* Applies a value read from the sdl2_config to a Setting.
|
||||
* Applies a value read from the android_config to a Setting.
|
||||
*
|
||||
* @param group The name of the INI group
|
||||
* @param setting The yuzu setting to modify
|
||||
|
|
|
|||
|
|
@ -4,73 +4,61 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/hana/string.hpp>
|
||||
#include "common/setting_keys.h"
|
||||
|
||||
namespace Keys = Settings::Keys;
|
||||
|
||||
namespace DefaultINI {
|
||||
|
||||
const char* sdl2_config_file = R"(
|
||||
// All of these setting keys are either not currently used by Android or are too niche to bother
|
||||
// documenting (people can contribute documentation if they care), or some other explained reason
|
||||
constexpr std::array android_config_omitted_keys = {
|
||||
Keys::enable_gamemode,
|
||||
Keys::use_custom_storage,
|
||||
Keys::init_time_offset,
|
||||
Keys::physical_device,
|
||||
Keys::use_gles, // Niche
|
||||
Keys::dump_command_buffers,
|
||||
Keys::use_display_refresh_rate_detection,
|
||||
Keys::screen_top_stretch,
|
||||
Keys::screen_top_leftright_padding,
|
||||
Keys::screen_top_topbottom_padding,
|
||||
Keys::screen_bottom_stretch,
|
||||
Keys::screen_bottom_leftright_padding,
|
||||
Keys::screen_bottom_topbottom_padding,
|
||||
Keys::mono_render_option,
|
||||
Keys::log_regex_filter, // Niche
|
||||
Keys::video_encoder,
|
||||
Keys::video_encoder_options,
|
||||
Keys::video_bitrate,
|
||||
Keys::audio_encoder,
|
||||
Keys::audio_encoder_options,
|
||||
Keys::audio_bitrate,
|
||||
Keys::last_artic_base_addr, // On Android, this value is stored as a "preference"
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
|
||||
// Is this macro nasty? Yes.
|
||||
// Does it make the code way more readable? Also yes.
|
||||
#define DECLARE_KEY(KEY) +Settings::HKeys::KEY+BOOST_HANA_STRING(" =")+
|
||||
|
||||
static const char* android_config_default_file_content = (BOOST_HANA_STRING(R"(
|
||||
[Controls]
|
||||
# The input devices and parameters for each 3DS native input
|
||||
# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..."
|
||||
# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values
|
||||
|
||||
# for button input, the following devices are available:
|
||||
# - "keyboard" (default) for keyboard input. Required parameters:
|
||||
# - "code": the code of the key to bind
|
||||
# - "sdl" for joystick input using SDL. Required parameters:
|
||||
# - "joystick": the index of the joystick to bind
|
||||
# - "button"(optional): the index of the button to bind
|
||||
# - "hat"(optional): the index of the hat to bind as direction buttons
|
||||
# - "axis"(optional): the index of the axis to bind
|
||||
# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right"
|
||||
# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is
|
||||
# triggered if the axis value crosses
|
||||
# - "direction"(only used for axis): "+" means the button is triggered when the axis value
|
||||
# is greater than the threshold; "-" means the button is triggered when the axis value
|
||||
# is smaller than the threshold
|
||||
button_a=
|
||||
button_b=
|
||||
button_x=
|
||||
button_y=
|
||||
button_up=
|
||||
button_down=
|
||||
button_left=
|
||||
button_right=
|
||||
button_l=
|
||||
button_r=
|
||||
button_start=
|
||||
button_select=
|
||||
button_debug=
|
||||
button_gpio14=
|
||||
button_zl=
|
||||
button_zr=
|
||||
button_home=
|
||||
|
||||
# for analog input, the following devices are available:
|
||||
# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters:
|
||||
# - "up", "down", "left", "right": sub-devices for each direction.
|
||||
# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00"
|
||||
# - "modifier": sub-devices as a modifier.
|
||||
# - "modifier_scale": a float number representing the applied modifier scale to the analog input.
|
||||
# Must be in range of 0.0-1.0. Defaults to 0.5
|
||||
# - "sdl" for joystick input using SDL. Required parameters:
|
||||
# - "joystick": the index of the joystick to bind
|
||||
# - "axis_x": the index of the axis to bind as x-axis (default to 0)
|
||||
# - "axis_y": the index of the axis to bind as y-axis (default to 1)
|
||||
circle_pad=
|
||||
c_stick=
|
||||
|
||||
# for motion input, the following devices are available:
|
||||
# - "motion_emu" (default) for emulating motion input from mouse input. Required parameters:
|
||||
# - "update_period": update period in milliseconds (default to 100)
|
||||
# - "sensitivity": the coefficient converting mouse movement to tilting angle (default to 0.01)
|
||||
# - "tilt_clamp": the max value of the tilt angle in degrees (default to 90)
|
||||
# - "cemuhookudp" reads motion input from a udp server that uses cemuhook's udp protocol
|
||||
motion_device=
|
||||
)") DECLARE_KEY(motion_device) BOOST_HANA_STRING(R"(
|
||||
|
||||
# for touch input, the following devices are available:
|
||||
# - "emu_window" (default) for emulating touch input from mouse input to the emulation window. No parameters required
|
||||
# - "cemuhookudp" reads touch input from a udp server that uses cemuhook's udp protocol
|
||||
# - "min_x", "min_y", "max_x", "max_y": defines the udp device's touch screen coordinate system
|
||||
touch_device= engine:emu_window
|
||||
)") DECLARE_KEY(touch_device) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Most desktop operating systems do not expose a way to poll the motion state of the controllers
|
||||
# so as a way around it, cemuhook created a udp client/server protocol to broadcast the data directly
|
||||
|
|
@ -78,136 +66,155 @@ touch_device= engine:emu_window
|
|||
# from any cemuhook compatible motion program.
|
||||
|
||||
# IPv4 address of the udp input server (Default "127.0.0.1")
|
||||
udp_input_address=
|
||||
)") DECLARE_KEY(udp_input_address) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Port of the udp input server. (Default 26760)
|
||||
udp_input_port=
|
||||
)") DECLARE_KEY(udp_input_port) BOOST_HANA_STRING(R"(
|
||||
|
||||
# The pad to request data on. Should be between 0 (Pad 1) and 3 (Pad 4). (Default 0)
|
||||
udp_pad_index=
|
||||
)") DECLARE_KEY(udp_pad_index) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Use Artic Controller when connected to Artic Base Server. (Default 0)
|
||||
use_artic_base_controller=
|
||||
)") DECLARE_KEY(use_artic_base_controller) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Core]
|
||||
# Whether to use the Just-In-Time (JIT) compiler for CPU emulation
|
||||
# 0: Interpreter (slow), 1 (default): JIT (fast)
|
||||
use_cpu_jit =
|
||||
)") DECLARE_KEY(use_cpu_jit) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Change the Clock Frequency of the emulated 3DS CPU.
|
||||
# Underclocking can increase the performance of the game at the risk of freezing.
|
||||
# Overclocking may fix lag that happens on console, but also comes with the risk of freezing.
|
||||
# Range is any positive integer (but we suspect 25 - 400 is a good idea) Default is 100
|
||||
cpu_clock_percentage =
|
||||
)") DECLARE_KEY(cpu_clock_percentage) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Renderer]
|
||||
# Whether to render using OpenGL
|
||||
# 1: OpenGL ES (default), 2: Vulkan
|
||||
graphics_api =
|
||||
)") DECLARE_KEY(graphics_api) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to compile shaders on multiple worker threads (Vulkan only)
|
||||
# 0: Off, 1: On (default)
|
||||
async_shader_compilation =
|
||||
)") DECLARE_KEY(async_shader_compilation) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to emit PICA fragment shader using SPIRV or GLSL (Vulkan only)
|
||||
# 0: GLSL, 1: SPIR-V (default)
|
||||
spirv_shader_gen =
|
||||
)") DECLARE_KEY(spirv_shader_gen) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to disable the SPIRV optimizer. Disabling it reduces stutter, but may slightly worsen performance
|
||||
# 0: Enabled, 1: Disabled (default)
|
||||
disable_spirv_optimizer =
|
||||
)") DECLARE_KEY(disable_spirv_optimizer) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to use hardware shaders to emulate 3DS shaders
|
||||
# 0: Software, 1 (default): Hardware
|
||||
use_hw_shader =
|
||||
)") DECLARE_KEY(use_hw_shader) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to use accurate multiplication in hardware shaders
|
||||
# 0: Off (Default. Faster, but causes issues in some games) 1: On (Slower, but correct)
|
||||
shaders_accurate_mul =
|
||||
)") DECLARE_KEY(shaders_accurate_mul) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to use the Just-In-Time (JIT) compiler for shader emulation
|
||||
# 0: Interpreter (slow), 1 (default): JIT (fast)
|
||||
use_shader_jit =
|
||||
)") DECLARE_KEY(use_shader_jit) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Overrides the sampling filter used by games. This can be useful in certain
|
||||
# cases with poorly behaved games when upscaling.
|
||||
# 0 (default): Game Controlled, 1: Nearest Neighbor, 2: Linear
|
||||
texture_sampling =
|
||||
)") DECLARE_KEY(texture_sampling) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Forces VSync on the display thread. Can cause input delay, so only turn this on
|
||||
# if you have screen tearing, which is unusual on Android
|
||||
# 0 (default): Off, 1: On
|
||||
use_vsync =
|
||||
)") DECLARE_KEY(use_vsync) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Reduce stuttering by storing and loading generated shaders to disk
|
||||
# 0: Off, 1 (default. On)
|
||||
use_disk_shader_cache =
|
||||
)") DECLARE_KEY(use_disk_shader_cache) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Resolution scale factor
|
||||
# 0: Auto (scales resolution to window size), 1: Native 3DS screen resolution, Otherwise a scale
|
||||
# factor for the 3DS resolution
|
||||
resolution_factor =
|
||||
)") DECLARE_KEY(resolution_factor) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Use Integer Scaling when the layout allows
|
||||
# 0: Off (default), 1: On
|
||||
)") DECLARE_KEY(use_integer_scaling) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Turns on the frame limiter, which will limit frames output to the target game speed
|
||||
# 0: Off, 1: On (default)
|
||||
use_frame_limit =
|
||||
)") DECLARE_KEY(use_frame_limit) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Limits the speed of the game to run no faster than this value as a percentage of target speed
|
||||
# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default)
|
||||
frame_limit =
|
||||
)") DECLARE_KEY(frame_limit) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Alternative frame limit which can be triggered by the user
|
||||
# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default)
|
||||
turbo_limit =
|
||||
)") DECLARE_KEY(turbo_limit) BOOST_HANA_STRING(R"(
|
||||
|
||||
# The clear color for the renderer. What shows up on the sides of the bottom screen.
|
||||
# Must be in range of 0.0-1.0. Defaults to 0.0 for all.
|
||||
bg_red =
|
||||
bg_blue =
|
||||
bg_green =
|
||||
)") DECLARE_KEY(bg_red) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(bg_blue) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(bg_green) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Opacity of second layer when using custom layout option (bottom screen unless swapped). Useful if positioning on top of the first layer.
|
||||
custom_second_layer_opacity =
|
||||
)") DECLARE_KEY(custom_second_layer_opacity) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether and how Stereoscopic 3D should be rendered
|
||||
# 0: Off, 1: Half Width Side by Side, 2 (default): Full Width Side by Side, 3: Anaglyph, 4: Interlaced, 5: Reverse Interlaced, 6: Cardboard VR
|
||||
# 0 is no longer supported in the interface, as using render_3d_which_display = 0 has the same effect, but supported here for backwards compatibility
|
||||
render_3d =
|
||||
)") DECLARE_KEY(render_3d) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Change 3D Intensity
|
||||
# 0 - 255: Intensity. 0 (default)
|
||||
factor_3d =
|
||||
)") DECLARE_KEY(factor_3d) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Swap Eyes in 3d
|
||||
# true: Swap eyes, false (default): Do not swap eyes
|
||||
swap_eyes_3d =
|
||||
)") DECLARE_KEY(swap_eyes_3d) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Which Display to render 3d mode to
|
||||
# 0 (default) - None. Equivalent to render_3d=0
|
||||
# 1: Both, 2: Primary Only, 3: Secondary Only
|
||||
render_3d_which_display =
|
||||
)") DECLARE_KEY(render_3d_which_display) BOOST_HANA_STRING(R"(
|
||||
|
||||
# The name of the post processing shader to apply.
|
||||
# Loaded from shaders if render_3d is off or side by side.
|
||||
pp_shader_name =
|
||||
)") DECLARE_KEY(pp_shader_name) BOOST_HANA_STRING(R"(
|
||||
|
||||
# The name of the shader to apply when render_3d is anaglyph.
|
||||
# Loaded from shaders/anaglyph
|
||||
anaglyph_shader_name =
|
||||
)") DECLARE_KEY(anaglyph_shader_name) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to enable linear filtering or not
|
||||
# This is required for some shaders to work correctly
|
||||
# 0: Nearest, 1 (default): Linear
|
||||
filter_mode =
|
||||
)") DECLARE_KEY(filter_mode) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Delays the game render thread by the specified amount of microseconds
|
||||
# Set to 0 for no delay, only useful in dynamic-fps games to simulate GPU delay.
|
||||
delay_game_render_thread_us =
|
||||
)") DECLARE_KEY(delay_game_render_thread_us) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Disables rendering the right eye image.
|
||||
# Disables rendering the right eye image
|
||||
# Greatly improves performance in some games, but can cause flickering in others.
|
||||
# 0 (default): Enable right eye rendering, 1: Disable right eye rendering
|
||||
disable_right_eye_render =
|
||||
# 0 : Enable right eye rendering, 1: Disable right eye rendering
|
||||
)") DECLARE_KEY(disable_right_eye_render) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Perform presentation on separate threads
|
||||
# Improves performance when using Vulkan in most applications.
|
||||
# Adds ~1 frame of input lag.
|
||||
# 0: Enable async presentation, 1 (default): Disable async presentation
|
||||
)") DECLARE_KEY(async_presentation) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Which texture filter should be used
|
||||
# 0 (default): NoFilter
|
||||
# 1: Anime4K
|
||||
# 2: Bicubic
|
||||
# 3: ScaleForce
|
||||
# 4: xBRZ
|
||||
# 5: MMPX
|
||||
)") DECLARE_KEY(texture_filter) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Layout]
|
||||
# Layout for the screen inside the render window, landscape mode
|
||||
|
|
@ -217,12 +224,52 @@ disable_right_eye_render =
|
|||
# 3: Side by Side
|
||||
# 4: Hybrid
|
||||
# 5: Custom Layout
|
||||
layout_option =
|
||||
)") DECLARE_KEY(layout_option) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not the screens should be rotated upright
|
||||
# 0 (default): Not rotated, 1: Rotated upright
|
||||
)") DECLARE_KEY(upright_screen) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Which aspect ratio should be used by the emulated 3DS screens
|
||||
# 0: (default): Default
|
||||
# 1: 16:9
|
||||
# 2: 4:3
|
||||
# 3: 21:9
|
||||
# 4: 16:10
|
||||
# 5: Stretch
|
||||
)") DECLARE_KEY(aspect_ratio) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not the performance overlay should be displayed
|
||||
# 0 (default): Hidden, 1: Shown
|
||||
)") DECLARE_KEY(performance_overlay_enable) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not the emulation framerate should be displayed in the performance overlay
|
||||
# 0: Hidden, 1 (default): Shown
|
||||
)") DECLARE_KEY(performance_overlay_show_fps) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not the emulation frame time should be displayed in the performance overlay
|
||||
# 0 (default): Hidden, 1: Shown
|
||||
)") DECLARE_KEY(performance_overlay_show_frame_time) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not the emulation speed should be displayed as a percentage in the performance overlay
|
||||
)") DECLARE_KEY(performance_overlay_show_speed) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not Azahar's RAM usage should be displayed in the performance overlay
|
||||
)") DECLARE_KEY(performance_overlay_show_app_ram_usage) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not the amount of available RAM should be displayed in the performance overlay
|
||||
)") DECLARE_KEY(performance_overlay_show_available_ram) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not the battery's current temperature should be displayed in the performance overlay
|
||||
)") DECLARE_KEY(performance_overlay_show_battery_temp) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not the performance overlay should have a transparent background to aid visibility
|
||||
)") DECLARE_KEY(performance_overlay_background) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Storage]
|
||||
# Whether to compress the installed CIA contents
|
||||
# 0 (default): Do not compress, 1: Compress
|
||||
compress_cia_installs =
|
||||
)") DECLARE_KEY(compress_cia_installs) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Position of the performance overlay
|
||||
# 0: Top Left
|
||||
|
|
@ -231,38 +278,37 @@ compress_cia_installs =
|
|||
# 3: Bottom Left
|
||||
# 4: Center Bottom
|
||||
# 5: Bottom Right
|
||||
performance_overlay_position =
|
||||
)") DECLARE_KEY(performance_overlay_position) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Screen Gap - adds a gap between screens in all two-screen modes
|
||||
# Measured in pixels relative to the 240px default height of the screens
|
||||
# Scales with the larger screen (so 24 is 10% of the larger screen height)
|
||||
# Default value is 0.0
|
||||
screen_gap =
|
||||
)") DECLARE_KEY(screen_gap) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Large Screen Proportion - Relative size of large:small in large screen mode
|
||||
# Default value is 2.25
|
||||
large_screen_proportion =
|
||||
)") DECLARE_KEY(large_screen_proportion) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Small Screen Position - where is the small screen relative to the large
|
||||
# Default value is 0
|
||||
# 0: Top Right 1: Middle Right 2: Bottom Right
|
||||
# 3: Top Left 4: Middle left 5: Bottom Left
|
||||
# 6: Above the large screen 7: Below the large screen
|
||||
small_screen_position =
|
||||
|
||||
)") DECLARE_KEY(small_screen_position) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Screen placement when using Custom layout option
|
||||
# 0x, 0y is the top left corner of the render window.
|
||||
# suggested aspect ratio for top screen is 5:3
|
||||
# suggested aspect ratio for bottom screen is 4:3
|
||||
custom_top_x =
|
||||
custom_top_y =
|
||||
custom_top_width =
|
||||
custom_top_height =
|
||||
custom_bottom_x =
|
||||
custom_bottom_y =
|
||||
custom_bottom_width =
|
||||
custom_bottom_height =
|
||||
)") DECLARE_KEY(custom_top_x) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_top_y) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_top_width) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_top_height) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_bottom_x) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_bottom_y) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_bottom_width) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_bottom_height) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Orientation option for the emulator
|
||||
# 2 (default): Automatic
|
||||
|
|
@ -270,32 +316,32 @@ custom_bottom_height =
|
|||
# 8: Landscape (Flipped)
|
||||
# 1: Portrait
|
||||
# 9: Portrait (Flipped)
|
||||
screen_orientation =
|
||||
)") DECLARE_KEY(screen_orientation) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Layout for the portrait mode
|
||||
# 0 (default): Top and bottom screens at top, full width
|
||||
# 1: Custom Layout
|
||||
portrait_layout_option =
|
||||
)") DECLARE_KEY(portrait_layout_option) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Screen placement when using Portrait Custom layout option
|
||||
# 0x, 0y is the top left corner of the render window.
|
||||
custom_portrait_top_x =
|
||||
custom_portrait_top_y =
|
||||
custom_portrait_top_width =
|
||||
custom_portrait_top_height =
|
||||
custom_portrait_bottom_x =
|
||||
custom_portrait_bottom_y =
|
||||
custom_portrait_bottom_width =
|
||||
custom_portrait_bottom_height =
|
||||
)") DECLARE_KEY(custom_portrait_top_x) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_portrait_top_y) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_portrait_top_width) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_portrait_top_height) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_portrait_bottom_x) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_portrait_bottom_y) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_portrait_bottom_width) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(custom_portrait_bottom_height) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Swaps the prominent screen with the other screen.
|
||||
# For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen.
|
||||
# 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent
|
||||
swap_screen =
|
||||
)") DECLARE_KEY(swap_screen) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Expands the display area to include the cutout (or notch) area
|
||||
# 0 (default): Off, 1: On
|
||||
expand_to_cutout_area =
|
||||
)") DECLARE_KEY(expand_to_cutout_area) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Secondary Display Layout
|
||||
# What the game should do if a secondary display is connected physically or using
|
||||
|
|
@ -304,129 +350,137 @@ expand_to_cutout_area =
|
|||
# 1 - Show Top Screen Only
|
||||
# 2 - Show Bottom Screen Only
|
||||
# 3 - Show both screens side by side
|
||||
secondary_display_layout =
|
||||
)") DECLARE_KEY(secondary_display_layout) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Screen placement settings when using Cardboard VR (render3d = 4)
|
||||
# 30 - 100: Screen size as a percentage of the viewport. 85 (default)
|
||||
cardboard_screen_size =
|
||||
)") DECLARE_KEY(cardboard_screen_size) BOOST_HANA_STRING(R"(
|
||||
# -100 - 100: Screen X-Coordinate shift as a percentage of empty space. 0 (default)
|
||||
cardboard_x_shift =
|
||||
)") DECLARE_KEY(cardboard_x_shift) BOOST_HANA_STRING(R"(
|
||||
# -100 - 100: Screen Y-Coordinate shift as a percentage of empty space. 0 (default)
|
||||
cardboard_y_shift =
|
||||
)") DECLARE_KEY(cardboard_y_shift) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Which of the available layouts should be cycled by Cycle Layouts
|
||||
# A list of any values from 0 to 5 inclusive (e.g. 0, 1, 2, 5)
|
||||
# Default: 0, 1, 2, 3, 4, 5
|
||||
# 0: Default,
|
||||
# 1: Single Screen,
|
||||
# 2: Large Screen,
|
||||
# 3: Side by Side,
|
||||
# 4: Hybrid Screens,
|
||||
# 5: Custom Layout,
|
||||
)") DECLARE_KEY(layouts_to_cycle) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Utility]
|
||||
# Dumps textures as PNG to dump/textures/[Title ID]/.
|
||||
# 0 (default): Off, 1: On
|
||||
dump_textures =
|
||||
)") DECLARE_KEY(dump_textures) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Reads PNG files from load/textures/[Title ID]/ and replaces textures.
|
||||
# 0 (default): Off, 1: On
|
||||
custom_textures =
|
||||
)") DECLARE_KEY(custom_textures) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Loads all custom textures into memory before booting.
|
||||
# 0 (default): Off, 1: On
|
||||
preload_textures =
|
||||
)") DECLARE_KEY(preload_textures) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Loads custom textures asynchronously with background threads.
|
||||
# 0: Off, 1 (default): On
|
||||
async_custom_loading =
|
||||
)") DECLARE_KEY(async_custom_loading) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Audio]
|
||||
# Whether or not to enable DSP LLE
|
||||
# 0 (default): No, 1: Yes
|
||||
enable_dsp_lle =
|
||||
|
||||
# Whether or not to run DSP LLE on a different thread
|
||||
# 0 (default): No, 1: Yes
|
||||
enable_dsp_lle_thread =
|
||||
# Whether or not audio emulation should be enabled
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
)") DECLARE_KEY(audio_emulation) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not to enable the audio-stretching post-processing effect.
|
||||
# Whether or not to enable the audio-stretching post-processing effect
|
||||
# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter,
|
||||
# at the cost of increasing audio latency.
|
||||
# 0: No, 1 (default): Yes
|
||||
enable_audio_stretching =
|
||||
)") DECLARE_KEY(enable_audio_stretching) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Scales audio playback speed to account for drops in emulation framerate
|
||||
# 0 (default): No, 1: Yes
|
||||
enable_realtime_audio =
|
||||
)") DECLARE_KEY(enable_realtime_audio) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Output volume.
|
||||
# 1.0 (default): 100%, 0.0; mute
|
||||
volume =
|
||||
)") DECLARE_KEY(volume) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Which audio output type to use.
|
||||
# 0 (default): Auto-select, 1: No audio output, 2: Cubeb (if available), 3: OpenAL (if available), 4: SDL2 (if available)
|
||||
output_type =
|
||||
)") DECLARE_KEY(output_type) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Which audio output device to use.
|
||||
# auto (default): Auto-select
|
||||
output_device =
|
||||
)") DECLARE_KEY(output_device) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Which audio input type to use.
|
||||
# 0 (default): Auto-select, 1: No audio input, 2: Static noise, 3: Cubeb (if available), 4: OpenAL (if available)
|
||||
input_type =
|
||||
)") DECLARE_KEY(input_type) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Which audio input device to use.
|
||||
# auto (default): Auto-select
|
||||
input_device =
|
||||
)") DECLARE_KEY(input_device) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Data Storage]
|
||||
# Whether to create a virtual SD card.
|
||||
# 1 (default): Yes, 0: No
|
||||
use_virtual_sd =
|
||||
)") DECLARE_KEY(use_virtual_sd) BOOST_HANA_STRING(R"(
|
||||
|
||||
[System]
|
||||
# The system model that Citra will try to emulate
|
||||
# 0: Old 3DS (default), 1: New 3DS
|
||||
is_new_3ds =
|
||||
)") DECLARE_KEY(is_new_3ds) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to use LLE system applets, if installed
|
||||
# 0: No, 1 (default): Yes
|
||||
lle_applets =
|
||||
)") DECLARE_KEY(lle_applets) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to enable LLE modules for online play
|
||||
# 0 (default): No, 1: Yes
|
||||
enable_required_online_lle_modules =
|
||||
)") DECLARE_KEY(enable_required_online_lle_modules) BOOST_HANA_STRING(R"(
|
||||
|
||||
# The system region that Citra will use during emulation
|
||||
# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
|
||||
region_value =
|
||||
)") DECLARE_KEY(region_value) BOOST_HANA_STRING(R"(
|
||||
|
||||
# The system language that Citra will use during emulation
|
||||
# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish,
|
||||
# 6: Simplified Chinese, 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Traditional Chinese
|
||||
language =
|
||||
)") DECLARE_KEY(language) BOOST_HANA_STRING(R"(
|
||||
|
||||
# The clock to use when citra starts
|
||||
# 0: System clock (default), 1: fixed time
|
||||
init_clock =
|
||||
)") DECLARE_KEY(init_clock) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Time used when init_clock is set to fixed_time in the format %Y-%m-%d %H:%M:%S
|
||||
# set to fixed time. Default 2000-01-01 00:00:01
|
||||
# Note: 3DS can only handle times later then Jan 1 2000
|
||||
init_time =
|
||||
)") DECLARE_KEY(init_time) BOOST_HANA_STRING(R"(
|
||||
|
||||
# The system ticks count to use when citra starts
|
||||
# 0: Random (default), 1: Fixed
|
||||
init_ticks_type =
|
||||
)") DECLARE_KEY(init_ticks_type) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Tick count to use when init_ticks_type is set to Fixed.
|
||||
# Defaults to 0.
|
||||
init_ticks_override =
|
||||
)") DECLARE_KEY(init_ticks_override) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Number of steps per hour reported by the pedometer. Range from 0 to 65,535.
|
||||
# Defaults to 0.
|
||||
steps_per_hour =
|
||||
)") DECLARE_KEY(steps_per_hour) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Plugin loader state, if enabled plugins will be loaded from the SD card.
|
||||
# You can also set if homebrew apps are allowed to enable the plugin loader
|
||||
plugin_loader =
|
||||
allow_plugin_loader =
|
||||
)") DECLARE_KEY(plugin_loader) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(allow_plugin_loader) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Apply region free patch to installed applications
|
||||
# Patches the region of installed applications to be region free, so that they always appear on the home menu.
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
apply_region_free_patch =
|
||||
)") DECLARE_KEY(apply_region_free_patch) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Camera]
|
||||
# Which camera engine to use for the right outer camera
|
||||
|
|
@ -437,66 +491,76 @@ apply_region_free_patch =
|
|||
# If you don't specify an ID, the default setting will be used. For outer cameras,
|
||||
# the back-facing camera will be used. For the inner camera, the front-facing
|
||||
# camera will be used. Please note that 'Legacy' cameras are not supported.
|
||||
camera_outer_right_name =
|
||||
)") DECLARE_KEY(camera_outer_right_name) BOOST_HANA_STRING(R"(
|
||||
|
||||
# A config string for the right outer camera. Its meaning is defined by the camera engine
|
||||
camera_outer_right_config =
|
||||
)") DECLARE_KEY(camera_outer_right_config) BOOST_HANA_STRING(R"(
|
||||
|
||||
# The image flip to apply
|
||||
# 0: None (default), 1: Horizontal, 2: Vertical, 3: Reverse
|
||||
camera_outer_right_flip =
|
||||
)") DECLARE_KEY(camera_outer_right_flip) BOOST_HANA_STRING(R"(
|
||||
|
||||
# ... for the left outer camera
|
||||
camera_outer_left_name =
|
||||
camera_outer_left_config =
|
||||
camera_outer_left_flip =
|
||||
)") DECLARE_KEY(camera_outer_left_name) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(camera_outer_left_config) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(camera_outer_left_flip) BOOST_HANA_STRING(R"(
|
||||
|
||||
# ... for the inner camera
|
||||
camera_inner_name =
|
||||
camera_inner_config =
|
||||
camera_inner_flip =
|
||||
)") DECLARE_KEY(camera_inner_name) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(camera_inner_config) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(camera_inner_flip) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Miscellaneous]
|
||||
# A filter which removes logs below a certain logging level.
|
||||
# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical
|
||||
log_filter = *:Info
|
||||
)") DECLARE_KEY(log_filter) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether or not Azahar-related images should be hidden from the Android gallery
|
||||
# 0 (default): No, 1: Yes
|
||||
)") DECLARE_KEY(android_hide_images) BOOST_HANA_STRING(R"(
|
||||
|
||||
[Debugging]
|
||||
# Record frame time data, can be found in the log directory. Boolean value
|
||||
record_frame_times =
|
||||
)") DECLARE_KEY(record_frame_times) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Whether to enable additional debugging information during emulation
|
||||
# 0 (default): Off, 1: On
|
||||
renderer_debug =
|
||||
)") DECLARE_KEY(renderer_debug) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Port for listening to GDB connections.
|
||||
use_gdbstub=false
|
||||
gdbstub_port=24689
|
||||
)") DECLARE_KEY(use_gdbstub) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(gdbstub_port) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Flush log output on every message
|
||||
# Immediately commits the debug log to file. Use this if Azahar crashes and the log output is being cut.
|
||||
instant_debug_log =
|
||||
)") DECLARE_KEY(instant_debug_log) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Enable RPC server for scripting purposes. Allows accessing guest memory remotely.
|
||||
# 0 (default): Off, 1: On
|
||||
enable_rpc_server =
|
||||
)") DECLARE_KEY(enable_rpc_server) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Enables toggling the unique data console type (Old 3DS <-> New 3DS) to be able to download the opposite system firmware type from system settings.
|
||||
# 0 (default): Off, 1: On
|
||||
)") DECLARE_KEY(toggle_unique_data_console_type) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Delay the start of apps when LLE modules are enabled
|
||||
# 0: Off, 1 (default): On
|
||||
delay_start_for_lle_modules =
|
||||
)") DECLARE_KEY(delay_start_for_lle_modules) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Force deterministic async operations
|
||||
# Only needed for debugging, makes performance worse if enabled
|
||||
# 0: Off (default), 1: On
|
||||
deterministic_async_operations =
|
||||
)") DECLARE_KEY(deterministic_async_operations) BOOST_HANA_STRING(R"(
|
||||
|
||||
# To LLE a service module add "LLE\<module name>=true"
|
||||
|
||||
[WebService]
|
||||
# URL for Web API
|
||||
web_api_url =
|
||||
)") DECLARE_KEY(web_api_url) BOOST_HANA_STRING(R"(
|
||||
# Username and token for Citra Web Service
|
||||
citra_username =
|
||||
citra_token =
|
||||
)";
|
||||
}
|
||||
)") DECLARE_KEY(citra_username) BOOST_HANA_STRING(R"(
|
||||
)") DECLARE_KEY(citra_token) BOOST_HANA_STRING("\n")).c_str();
|
||||
|
||||
// clang-format on
|
||||
|
||||
} // namespace DefaultINI
|
||||
|
|
|
|||
|
|
@ -207,9 +207,10 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||
env->NewGlobalRef(env->FindClass("org/citra/citra_emu/utils/DiskShaderCacheProgress")));
|
||||
jclass load_callback_stage_class =
|
||||
env->FindClass("org/citra/citra_emu/utils/DiskShaderCacheProgress$LoadCallbackStage");
|
||||
s_disk_cache_load_progress = env->GetStaticMethodID(
|
||||
s_disk_cache_progress_class, "loadProgress",
|
||||
"(Lorg/citra/citra_emu/utils/DiskShaderCacheProgress$LoadCallbackStage;II)V");
|
||||
s_disk_cache_load_progress =
|
||||
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress",
|
||||
"(Lorg/citra/citra_emu/utils/"
|
||||
"DiskShaderCacheProgress$LoadCallbackStage;IILjava/lang/String;)V");
|
||||
s_compress_progress_method =
|
||||
env->GetStaticMethodID(s_native_library_class, "onCompressProgress", "(JJ)V");
|
||||
// Initialize LoadCallbackStage map
|
||||
|
|
|
|||
19
src/android/app/src/main/jni/jni_setting_keys.cpp.in
Normal file
19
src/android/app/src/main/jni/jni_setting_keys.cpp.in
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#define JNI_DEFINE_KEY(KEY, KEY_JNI_ESCAPED) \
|
||||
JNIEXPORT jstring JNICALL \
|
||||
Java_org_citra_citra_1emu_features_settings_SettingKeys_##KEY_JNI_ESCAPED( \
|
||||
JNIEnv* env, jobject obj \
|
||||
) { \
|
||||
return env->NewStringUTF(#KEY); \
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
@JNI_SETTING_KEY_DEFINITIONS@
|
||||
|
||||
}
|
||||
|
|
@ -130,12 +130,13 @@ static bool HandleCoreError(Core::System::ResultStatus result, const std::string
|
|||
env->NewStringUTF(details.c_str())) != JNI_FALSE;
|
||||
}
|
||||
|
||||
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) {
|
||||
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max,
|
||||
const std::string& object) {
|
||||
JNIEnv* env = IDCache::GetEnvForThread();
|
||||
env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
|
||||
IDCache::GetDiskCacheLoadProgress(),
|
||||
IDCache::GetJavaLoadCallbackStage(stage), static_cast<jint>(progress),
|
||||
static_cast<jint>(max));
|
||||
static_cast<jint>(max), env->NewStringUTF(object.c_str()));
|
||||
}
|
||||
|
||||
static Camera::NDK::Factory* g_ndk_factory{};
|
||||
|
|
@ -217,7 +218,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||
true, shared_context);
|
||||
|
||||
#elif ENABLE_VULKAN
|
||||
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surface, vulkan_library);
|
||||
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surface, vulkan_library, false);
|
||||
secondary_window =
|
||||
std::make_unique<EmuWindow_Android_Vulkan>(s_secondary_surface, vulkan_library, true);
|
||||
#else
|
||||
|
|
@ -267,7 +268,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||
stop_run = false;
|
||||
pause_emulation = false;
|
||||
|
||||
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
|
||||
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0, "");
|
||||
|
||||
system.GPU().ApplyPerProgramSettings(program_id);
|
||||
|
||||
|
|
@ -275,7 +276,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||
system.GPU().Renderer().Rasterizer()->LoadDefaultDiskResources(stop_run,
|
||||
&LoadDiskCacheProgress);
|
||||
|
||||
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
|
||||
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0, "");
|
||||
|
||||
SCOPE_EXIT({ TryShutdown(); });
|
||||
|
||||
|
|
@ -651,34 +652,38 @@ void Java_org_citra_citra_1emu_NativeLibrary_setUserDirectory(JNIEnv* env,
|
|||
FileUtil::SetCurrentDir(GetJString(env, j_directory));
|
||||
}
|
||||
|
||||
jobjectArray Java_org_citra_citra_1emu_NativeLibrary_getInstalledGamePaths(
|
||||
jobjectArray Java_org_citra_citra_1emu_NativeLibrary_getInstalledGamePathsImpl(
|
||||
JNIEnv* env, [[maybe_unused]] jclass clazz) {
|
||||
std::vector<std::string> games;
|
||||
const FileUtil::DirectoryEntryCallable ScanDir =
|
||||
[&games, &ScanDir](u64*, const std::string& directory, const std::string& virtual_name) {
|
||||
std::string path = directory + virtual_name;
|
||||
if (FileUtil::IsDirectory(path)) {
|
||||
path += '/';
|
||||
FileUtil::ForeachDirectoryEntry(nullptr, path, ScanDir);
|
||||
} else {
|
||||
if (!FileUtil::Exists(path))
|
||||
return false;
|
||||
auto loader = Loader::GetLoader(path);
|
||||
if (loader) {
|
||||
bool executable{};
|
||||
const Loader::ResultStatus result = loader->IsExecutable(executable);
|
||||
if (Loader::ResultStatus::Success == result && executable) {
|
||||
games.emplace_back(path);
|
||||
}
|
||||
Service::FS::MediaType media_type;
|
||||
const FileUtil::DirectoryEntryCallable ScanDir = [&games, &ScanDir, &media_type](
|
||||
u64*, const std::string& directory,
|
||||
const std::string& virtual_name) {
|
||||
std::string path = directory + virtual_name;
|
||||
if (FileUtil::IsDirectory(path)) {
|
||||
path += '/';
|
||||
FileUtil::ForeachDirectoryEntry(nullptr, path, ScanDir);
|
||||
} else {
|
||||
if (!FileUtil::Exists(path))
|
||||
return false;
|
||||
auto loader = Loader::GetLoader(path);
|
||||
if (loader) {
|
||||
bool executable{};
|
||||
const Loader::ResultStatus result = loader->IsExecutable(executable);
|
||||
if (Loader::ResultStatus::Success == result && executable) {
|
||||
games.emplace_back(path + "|" + std::to_string(static_cast<int>(media_type)));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
};
|
||||
media_type = Service::FS::MediaType::SDMC;
|
||||
ScanDir(nullptr, "",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) +
|
||||
"Nintendo "
|
||||
"3DS/00000000000000000000000000000000/"
|
||||
"00000000000000000000000000000000/title/00040000");
|
||||
media_type = Service::FS::MediaType::NAND;
|
||||
ScanDir(nullptr, "",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"00000000000000000000000000000000/title/00040010");
|
||||
|
|
@ -1106,4 +1111,23 @@ void Java_org_citra_citra_1emu_NativeLibrary_setInsertedCartridge(JNIEnv* env, j
|
|||
inserted_cartridge = GetJString(env, path);
|
||||
}
|
||||
|
||||
jboolean Java_org_citra_citra_1emu_NativeLibrary_uninstallTitle(JNIEnv* env, jobject obj,
|
||||
jlong j_titleid, jint j_mediatype) {
|
||||
const auto titleid = static_cast<u64>(j_titleid);
|
||||
const auto result =
|
||||
Service::AM::UninstallProgram(static_cast<Service::FS::MediaType>(j_mediatype), titleid);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Frontend, "Failed to uninstall '{}': 0x{:08X}", std::to_string(titleid),
|
||||
result.raw);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
jboolean Java_org_citra_citra_1emu_NativeLibrary_nativeFileExists(JNIEnv* env, jobject obj,
|
||||
jstring j_path) {
|
||||
const auto path = GetJString(env, j_path);
|
||||
return FileUtil::Exists(path);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
55
src/android/app/src/main/res/layout/dialog_auto_map.xml
Normal file
55
src/android/app/src/main/res/layout/dialog_auto_map.xml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingBottom="24dp"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:focusedByDefault="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_title"
|
||||
style="@style/TextAppearance.Material3.HeadlineSmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
tools:text="Auto-Map Controller" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_face_buttons"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
android:contentDescription="@string/auto_map_image_description"
|
||||
tools:ignore="ImageContrastCheck" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text_message"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
tools:text="Press this button!" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_cancel"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
android:focusable="false"
|
||||
android:text="@android:string/cancel" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -100,7 +100,6 @@
|
|||
<string name="search_recently_added">Acabats d\'afegir</string>
|
||||
<string name="search_installed">Instal·lats</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_circlepad">Pad circular</string>
|
||||
<string name="controller_c">Palanca C</string>
|
||||
<string name="controller_hotkeys">Tecles de drecera</string>
|
||||
|
|
@ -511,8 +510,6 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
|
|||
<string name="unsupported_encrypted">Aplicació cifrada no suportada</string>
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Preparant ombrejadors</string>
|
||||
<string name="building_shaders">Construint ombrejadors</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">Jugar</string>
|
||||
<string name="uninstall_cia">Desinstal·lar Aplicació</string>
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@
|
|||
<string name="search_recently_added">For nyligt tilføjet</string>
|
||||
<string name="search_installed">Installeret</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_circlepad">Circle Pad</string>
|
||||
<string name="controller_c">C-Stick</string>
|
||||
<string name="controller_hotkeys">Genvejstaster</string>
|
||||
|
|
@ -118,6 +117,8 @@
|
|||
<string name="controller_dpad_axis_description">Nogle kontrollere er muligvis ikke i stand til at tilknytte deres D-Pad som en akse. Hvis det er tilfældet, skal du bruge afsnittet D-Pad (knapper).</string>
|
||||
<string name="controller_dpad_button">D-Pad (knapper)</string>
|
||||
<string name="controller_dpad_button_description">Udfyld kun disse D-Pad, hvis du har problemer med opsætningen af D-Pad (akser).</string>
|
||||
<string name="controller_axis_vertical">Vertikal akse</string>
|
||||
<string name="controller_axis_horizontal">Horisontal akse</string>
|
||||
<string name="direction_up">Op</string>
|
||||
<string name="direction_down">Ned</string>
|
||||
<string name="direction_left">Venstre</string>
|
||||
|
|
@ -126,6 +127,8 @@
|
|||
<string name="input_dialog_description">Tryk på eller flyt et input.</string>
|
||||
<string name="input_binding">Inputbinding</string>
|
||||
<string name="input_binding_description">Tryk på eller flyt et input for at binde det til %1$s.</string>
|
||||
<string name="input_binding_description_vertical_axis">Tryk OP på dit joystick.</string>
|
||||
<string name="input_binding_description_horizontal_axis">Tryk HØJRE på dit joystick.</string>
|
||||
<string name="button_home">HOME</string>
|
||||
<string name="button_swap">Byt skærme</string>
|
||||
<string name="button_turbo">Turbo</string>
|
||||
|
|
@ -546,8 +549,6 @@
|
|||
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Forberedelse af shaders</string>
|
||||
<string name="building_shaders">Bygning af shaders</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">Spil</string>
|
||||
<string name="uninstall_cia">Afinstaller applikation</string>
|
||||
|
|
|
|||
|
|
@ -66,13 +66,14 @@
|
|||
<string name="give_permission">Conceder permiso</string>
|
||||
<string name="notification_warning">¿Saltarse la concesión del permiso de notificaciones?</string>
|
||||
<string name="notification_warning_description">Azahar no podrá notificarte sobre información importante.</string>
|
||||
<string name="filesystem_permission_warning">Falta Permisos</string>
|
||||
<string name="filesystem_permission_warning">Faltan Permisos</string>
|
||||
<string name="filesystem_permission_warning_description">Azahar necesita permiso para administrar archivos en este dispositivo para poder almacenar y administrar los datos de usuario de 3DS.\n\nPor favor, otorgue el permiso antes de continuar.</string>
|
||||
<string name="camera_permission">Cámara</string>
|
||||
<string name="camera_permission_description">Concede el permiso de cámara debajo para emular la cámara de la 3DS.</string>
|
||||
<string name="microphone_permission">Micrófono</string>
|
||||
<string name="microphone_permission_description">Concede el permiso de micrófono debajo para emular el micrófono de la 3DS.</string>
|
||||
<string name="filesystem_permission">Sistema de archivos</string>
|
||||
<string name="filesystem_permission_description">Concede el permiso de sistema de archivos debajo para permitir que Azahar almacene archivos.</string>
|
||||
<string name="filesystem_permission_description">Concede el permiso de sistema de archivos abajo para permitir que Azahar almacene archivos.</string>
|
||||
<string name="permission_denied">Permiso denegado</string>
|
||||
<string name="add_games_warning">¿Saltarse la selección de la carpeta de aplicaciones?</string>
|
||||
<string name="add_games_warning_description">Nada se mostrará en la lista de aplicaciones si no se selecciona una carpeta.</string>
|
||||
|
|
@ -92,7 +93,9 @@
|
|||
<string name="cannot_skip">No puedes saltarte el configuración de la carpeta de usuario</string>
|
||||
<string name="cannot_skip_directory_description">Este paso es necesario para permitir que Azahar funcione. Por favor, seleccione un directorio y luego puede continuar.</string>
|
||||
<string name="selecting_user_directory_without_write_permissions">Has perdido los permisos de escritura en tu <a href="https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage">directorio de datos de usuario</a>, donde se guardan las partidas guardadas y otra información. Esto puede ocurrir después de algunas actualizaciones de aplicaciones o de Android. Vuelve a seleccionar el directorio para recuperar los permisos y poder continuar.</string>
|
||||
<string name="invalid_selection">Selección no válido</string>
|
||||
<string name="invalid_selection">Selección no válida</string>
|
||||
<string name="invalid_user_directory">La selección del directorio de usuario no es válida.\nVuelve a seleccionar el directorio de usuario, asegurándote de navegar hasta él desde la raíz del almacenamiento del dispositivo.</string>
|
||||
<string name="filesystem_permission_lost">Azahar ha perdido el permiso para administrar archivos en este dispositivo. Esto puede ocurrir después de alguna actualización de la aplicación o de Android. Vuelve a conceder este permiso en la siguiente pantalla para seguir usando la aplicación.</string>
|
||||
<string name="set_up_theme_settings">Configuración de tema</string>
|
||||
<string name="setup_theme_settings_description">Configura tus preferencias de tema de Azahar.</string>
|
||||
<string name="setup_set_theme">Establecer tema</string>
|
||||
|
|
@ -105,9 +108,17 @@
|
|||
<string name="search_installed">Instalados</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_auto_map">Mapeo de Mando Automático</string>
|
||||
<string name="controller_auto_map_description">Aplica la asignación de mando estándar para todos los botones y ejes</string>
|
||||
<string name="auto_map_prompt">¡Presiona este botón en tu mando!</string>
|
||||
<string name="auto_map_image_description">Botones de 3DS con el botón A resaltado</string>
|
||||
<string name="controller_clear_all">Limpiar Todas las Asignaciones</string>
|
||||
<string name="controller_clear_all_confirm">Esto eliminará todas los asignaciones del mando actual.</string>
|
||||
<string name="controller_circlepad">Pad Circular</string>
|
||||
<string name="controller_c">Palanca C</string>
|
||||
<string name="controller_hotkeys">Teclas de atajo</string>
|
||||
<string name="controller_hotkeys_description">Si la tecla \"Habilitar teclas de acceso rápido\" está asignada, se debe presionar esa tecla además de la tecla de acceso rápido asignada</string>
|
||||
<string name="controller_hotkey_enable_button">Habilitar teclas de acceso rápido</string>
|
||||
<string name="controller_triggers">Botones Traseros</string>
|
||||
<string name="controller_trigger">Botón Trasero</string>
|
||||
<string name="controller_dpad">Pad de Control</string>
|
||||
|
|
@ -115,6 +126,8 @@
|
|||
<string name="controller_dpad_axis_description">Es posible que algunos controladores no puedan asignar su D-pad como un eje. Si ese es el caso, utilice la sección D-Pad (botones).</string>
|
||||
<string name="controller_dpad_button">D-Pad (Botón)</string>
|
||||
<string name="controller_dpad_button_description">Asigne solo el D-pad a éstos si tiene problemas con las asignaciones de botones del D-Pad (Eje).</string>
|
||||
<string name="controller_axis_vertical">Eje Vertical</string>
|
||||
<string name="controller_axis_horizontal">Eje Horizontal</string>
|
||||
<string name="direction_up">Arriba</string>
|
||||
<string name="direction_down">Abajo</string>
|
||||
<string name="direction_left">Izquierda</string>
|
||||
|
|
@ -123,6 +136,8 @@
|
|||
<string name="input_dialog_description">Pulsa o mueve un botón/palanca.</string>
|
||||
<string name="input_binding">Asignación de botones</string>
|
||||
<string name="input_binding_description">Pulsa o mueve un botón para asignarlo a %1$s.</string>
|
||||
<string name="input_binding_description_vertical_axis">Presiona ARRIBA en tu joystick.</string>
|
||||
<string name="input_binding_description_horizontal_axis">Presiona DERECHA en tu joystick.</string>
|
||||
<string name="button_home">HOME</string>
|
||||
<string name="button_swap">Intercambiar Pantallas</string>
|
||||
<string name="button_turbo">Turbo</string>
|
||||
|
|
@ -161,6 +176,8 @@
|
|||
<string name="username">Nombre de usuario/a</string>
|
||||
<string name="new_3ds">Modo New 3DS</string>
|
||||
<string name="lle_applets">Usar Applets LLE (si están instaladas)</string>
|
||||
<string name="apply_region_free_patch">Aplicar parche de región libre a las aplicaciones instaladas</string>
|
||||
<string name="apply_region_free_patch_desc">Parchea la región de las aplicaciones instaladas para que estén libres de región, de modo que siempre aparezcan en el menú home.</string>
|
||||
<string name="enable_required_online_lle_modules">Habilitar los módulos LLE necesarios para las funciones en línea (si están instalados)</string>
|
||||
<string name="enable_required_online_lle_modules_desc">Habilita los módulos LLE necesarios para el modo multijugador en línea, acceso a la eShop, etc.</string>
|
||||
<string name="clock">Reloj</string>
|
||||
|
|
@ -221,6 +238,8 @@
|
|||
Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
||||
<string name="linear_filtering">Filtro Linear</string>
|
||||
<string name="linear_filtering_description">Activa el filtro linear, que hace que los gráficos del juego se vean más suaves.</string>
|
||||
<string name="use_integer_scaling">Escalado a múltiplos enteros</string>
|
||||
<string name="use_integer_scaling_description">Escala las pantallas con un multiplicador entero de la pantalla original de 3DS. Para diseños con dos tamaños de pantalla diferentes, la pantalla más grande se escala con un multiplicador entero.</string>
|
||||
<string name="texture_filter_name">Filtro de Texturas</string>
|
||||
<string name="texture_filter_description">Mejora los gráficos visuales de las aplicaciones aplicando un filtro a las texturas. Los filtros soportados son Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale, y MMPX.</string>
|
||||
<string name="delay_render_thread">Atrasar hilo de renderizado del juego</string>
|
||||
|
|
@ -236,7 +255,8 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
|||
<string name="frame_limit_enable_description">Cuando se active, la velocidad de emulación estará limitada a un porcentaje determinado de la velocidad normal. Cuando se desactive, la velocidad de emulación no tendrá límite y la tecla de acceso rápido de velocidad turbo no funcionará.</string>
|
||||
<string name="frame_limit_slider">Limitar porcentaje de velocidad</string>
|
||||
<string name="frame_limit_slider_description">Especifica el valor al que se limita la velocidad de emulación. Con el valor por defecto del 100%, la emulación se limitará a la velocidad normal. Los valores altos o altos incrementarán o reducirán el límite de velocidad.</string>
|
||||
<string name="android_hide_images">Ocultar imágenes 3DS de Android</string>
|
||||
<string name="android_hide_images">Ocultar las imágenes de 3DS en Android</string>
|
||||
<string name="android_hide_images_description">Evita que Android indexe las imágenes de la cámara, capturas de pantalla y texturas personalizadas de la 3DS y las muestre en la galería. Es posible que tengas que reiniciar el dispositivo después de cambiar esta configuración para que surta efecto.</string>
|
||||
<string name="turbo_limit">Límite de Velocidad Turbo</string>
|
||||
<string name="turbo_limit_description">Límite de velocidad de emulación utilizado mientras la tecla de acceso rápido turbo está activa.</string>
|
||||
<string name="expand_to_cutout_area">Expandir al área de recorte</string>
|
||||
|
|
@ -258,12 +278,15 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
|||
<string name="debug_warning">Aviso: Modificar estas configuraciones reducirán la velocidad de emulación.</string>
|
||||
<string name="stereoscopy">Estereoscopía</string>
|
||||
<string name="render3d">Modo 3D Estereoscópico</string>
|
||||
<string name="render3d_description">Seleccione el modo 3D estereoscópico para renderizado 3D. Los modos lado a lado son los más comunes en la actualidad. Los modos Anaglifo y Entrelazado siempre se aplican a todas las pantallas conectadas.</string>
|
||||
<string name="factor3d">Profundidad</string>
|
||||
<string name="factor3d_description">Especifica el valor del regulador 3D. Debería estar puesto a más allá del 0% cuando el Modo 3D Estereoscópico está activado.\nNota: Los valores de profundidad superiores al 100 % no son posibles en hardware real y pueden causar problemas gráficos.</string>
|
||||
<string name="disable_right_eye_render">Desactivar Renderizado de Ojo Derecho</string>
|
||||
<string name="disable_right_eye_render_description">Mejora significativamente el rendimiento en algunas aplicaciones, pero puede causar parpadeo en otros.</string>
|
||||
<string name="swap_eyes_3d">Intercambiar Ojos</string>
|
||||
<string name="swap_eyes_3d_description">Intercambia qué ojo se muestra en cada lado. Combinado con el modo Lado a Lado, ¡permite ver en 3D cruzando los ojos!</string>
|
||||
<string name="render_3d_which_display">Renderizado 3D Estereoscópico</string>
|
||||
<string name="render_3d_which_display_description">Decide si se activa el 3D estereoscópico y en qué pantallas. Las opciones de pantalla única solo son relevantes cuando se conectan varias pantallas.</string>
|
||||
<string name="render_3d_which_display_both">Activado (todas las pantallas)</string>
|
||||
<string name="render_3d_which_display_primary">Activado (solo pantalla principal)</string>
|
||||
<string name="render_3d_which_display_secondary">Activado (solo pantalla secundaria)</string>
|
||||
|
|
@ -303,9 +326,10 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
|||
<string name="hw_shaders_description">Usa el hardware para emular los sombreadores de 3DS. Cuando se active, el rendimiento mejorará notablemente.</string>
|
||||
<string name="cpu_clock_speed">Velocidad de reloj de la CPU</string>
|
||||
<string name="vsync">Activar Sincronización Vertical</string>
|
||||
<string name="vsync_description">Sincroniza la frecuencia de fotogramas del juego con la frecuencia de actualización de tu dispositivo. Puede causar latencia de entrada adicional, pero puede reducir el tearing en algunos casos.</string>
|
||||
<string name="renderer_debug">Renderizador de depuración</string>
|
||||
<string name="renderer_debug_description">Archiva información adicional gráfica relacionada con la depuración. Cuando está activada, el rendimiento de los juegos será reducido considerablemente</string>
|
||||
<string name="instant_debug_log">Limpiar la salida del registro en cada mensaje</string>
|
||||
<string name="instant_debug_log">Escribir la salida del registro en cada mensaje</string>
|
||||
<string name="instant_debug_log_description">Inmediatamente guarda el registro de depuración en el archivo. Utilice ésto si Azahar se bloquea y la salida del registro se está cortando.</string>
|
||||
<string name="delay_start_lle_modules">Retrasar el comienzo con módulos LLE</string>
|
||||
<string name="delay_start_lle_modules_description">Retrasa el inicio de la aplicación cuando los módulos LLE están habilitados.</string>
|
||||
|
|
@ -313,6 +337,8 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
|||
<string name="deterministic_async_operations_description">Hace que las operaciones asíncronas sean deterministas para la depuración. Habilitar esta opción puede causar bloqueos.</string>
|
||||
<string name="enable_rpc_server">Activar servidor RPC</string>
|
||||
<string name="enable_rpc_server_desc">Activa el servidor RPC en el puerto 45987. Esto permite leer/escribir de manera remota la memoria emulada.</string>
|
||||
<string name="toggle_unique_data_console_type">Cambiar tipo de consola en los datos únicos de consola</string>
|
||||
<string name="toggle_unique_data_console_type_desc">Permite alternar el tipo de consola (Old 3DS ↔ New 3DS) para poder descargar el firmware del sistema opuesto desde la configuración del sistema.</string>
|
||||
<string name="shader_jit">Activar Sombreador JIT</string>
|
||||
<string name="shader_jit_description">Usar el motor JIT en lugar del intérprete para la emulación del sombreador de software.</string>
|
||||
|
||||
|
|
@ -323,6 +349,8 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
|||
<string name="layout_screen_orientation_landscape_reverse">Horizontal invertida</string>
|
||||
<string name="layout_screen_orientation_portrait">Retrato</string>
|
||||
<string name="layout_screen_orientation_portrait_reverse">Retrato invertido</string>
|
||||
<string name="layouts_to_cycle">Ciclo de Estilos</string>
|
||||
<string name="layouts_to_cycle_description">Selecciona qué estilos se pueden ciclar con la tecla de acceso rápido</string>
|
||||
<string name="aspect_ratio_default">Por defecto</string>
|
||||
<string name="aspect_ratio_16_9">16:9</string>
|
||||
<string name="aspect_ratio_4_3">4:3</string>
|
||||
|
|
@ -431,11 +459,12 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
|||
<string name="emulation_secondary_display_default">Por defecto del sistema (espejo)</string>
|
||||
<string name="emulation_screen_layout_custom">Estilo personalizado</string>
|
||||
<string name="bg_color">Color de fondo</string>
|
||||
<string name="bg_color_description">El color que aparece detrás de las pantallas durante la emulación, representado como un valor RGB.</string>
|
||||
<string name="bg_red">Rojo</string>
|
||||
<string name="bg_green">Verde</string>
|
||||
<string name="bg_blue">Azul</string>
|
||||
<string name="second_screen_opacity">Opacidad personalizado de la segunda pantalla</string>
|
||||
<string name="second_screen_opacity_description">La opacidad de la segunda pantalla 3DS al usar el pantalla personalizado. Útil si la segunda pantalla ésta posición en la parte superior de la primera pantalla.</string>
|
||||
<string name="second_screen_opacity_description">La opacidad de la segunda pantalla de 3DS al usar el pantalla personalizado. Útil si la segunda pantalla ésta posicionada en la parte superior de la primera pantalla.</string>
|
||||
<string name="emulation_small_screen_position">Posición Pantalla Pequeña</string>
|
||||
<string name="small_screen_position_description">¿Dónde debería aparecer la pantalla pequeña en relación con la grande en Disposicion de Pantalla Grande?</string>
|
||||
<string name="small_screen_position_top_right">Arriba a la Derecha</string>
|
||||
|
|
@ -532,9 +561,11 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
|||
<string name="fatal_error_message">Ha ocurrido un error fatal. Mira el registro para más detalles.\nSeguir con la emulación podría resultar en diversos cuelgues y bugs.</string>
|
||||
<string name="unsupported_encrypted">Aplicación encriptada no soportada</string>
|
||||
<string name="invalid_system_mode">Modo de sistema no válido</string>
|
||||
<string name="invalid_system_mode_message">Las aplicaciones exclusivas de New 3DS no se pueden cargar sin activar el modo New 3DS.</string>
|
||||
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Preparando shaders</string>
|
||||
<string name="building_shaders">Construyendo shaders</string>
|
||||
<string name="building_shaders">Construyendo%s</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">Jugar</string>
|
||||
|
|
@ -579,7 +610,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
|||
<string name="performance_overlay_show_battery_temp">Mostrar la temperatura de la batería</string>
|
||||
<string name="performance_overlay_show_battery_temp_description">Muestra la temperatura actual de la batería en Celsius y Fahrenheit.</string>
|
||||
<string name="performance_overlay_position">Posición de la información</string>
|
||||
<string name="performance_overlay_position_description">Elegir donde el superposición de rendimiento esta mostrado en el pantalla</string>
|
||||
<string name="performance_overlay_position_description">Elegir donde la superposición de rendimiento está mostrada en la pantalla</string>
|
||||
<string name="performance_overlay_position_top_left">Arriba a la Izquierda</string>
|
||||
<string name="performance_overlay_position_top_right">Arriba a la Derecha</string>
|
||||
<string name="performance_overlay_position_bottom_left">Abajo a la Izquierda</string>
|
||||
|
|
@ -883,15 +914,17 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
|
|||
|
||||
<!-- File Compression -->
|
||||
<string name="compress">Comprimir</string>
|
||||
<string name="compressing">Compresando...</string>
|
||||
<string name="compressing">Comprimiendo...</string>
|
||||
<string name="decompress">Descomprimir</string>
|
||||
<string name="decompressing">Descomprimiendo…</string>
|
||||
<string name="compress_success">Compresión completada con éxito.</string>
|
||||
<string name="compress_unsupported">Compresión no está soportado con este archivo.</string>
|
||||
<string name="compress_unsupported">Compresión no soportada con este archivo.</string>
|
||||
<string name="compress_already">Este archivo ya está comprimido.</string>
|
||||
<string name="compress_failed">Falló la compresión.</string>
|
||||
<string name="decompress_success">Descompresión completada con éxito.</string>
|
||||
<string name="decompress_unsupported">Descompresión no está soportado con este archivo.</string>
|
||||
<string name="decompress_unsupported">Descompresión no soportada con este archivo.</string>
|
||||
<string name="decompress_not_compressed">El archivo no está comprimido.</string>
|
||||
<string name="decompress_failed"> Falló la descompresión.</string>
|
||||
</resources>
|
||||
<string name="compress_decompress_installed_app">Las aplicaciones ya instaladas no se pueden comprimir ni descomprimir.</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@
|
|||
<string name="search_recently_added">Ostatnio dodane</string>
|
||||
<string name="search_installed">Zainstalowane</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_circlepad">Analog</string>
|
||||
<string name="controller_c">C-Stick</string>
|
||||
<string name="controller_hotkeys">Skróty klawiszowe</string>
|
||||
|
|
@ -229,6 +228,8 @@
|
|||
<string name="async_shaders_description">Kompiluje shadery w tle, aby zmniejszyć zacinanie się podczas rozgrywki. Po włączeniu należy spodziewać się tymczasowych błędów graficznych</string>
|
||||
<string name="linear_filtering">Filtrowanie Linear</string>
|
||||
<string name="linear_filtering_description">Włącza filtrowanie liniowe, które sprawia, że grafika w grach jest płynniejsza.</string>
|
||||
<string name="use_integer_scaling">Skalowanie całkowitoliczbowe</string>
|
||||
<string name="use_integer_scaling_description">Skaluje ekrany za pomocą całkowitego mnożnika oryginalnego ekranu 3DS. W przypadku układów z dwoma różnymi rozmiarami ekranu największy ekran jest skalowany całkowicie.</string>
|
||||
<string name="texture_filter_name">Filtr tekstur</string>
|
||||
<string name="texture_filter_description">Ulepsza oprawę wizualną aplikacji poprzez zastosowanie filtrów do tekstur. Obsługiwane filtry to Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale i MMPX.</string>
|
||||
<string name="delay_render_thread">Opóźnienie Renderowania Wątku Gry</string>
|
||||
|
|
@ -550,7 +551,7 @@
|
|||
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Przygotowanie shaderów</string>
|
||||
<string name="building_shaders">Tworzenie shaderów</string>
|
||||
<string name="building_shaders">Tworzenie%s</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">Odtwórz</string>
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@
|
|||
<string name="search_recently_added">Recentemente adicionado</string>
|
||||
<string name="search_installed">Instalado</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_circlepad">Analógico</string>
|
||||
<string name="controller_c">Direcional C-Stick</string>
|
||||
<string name="controller_hotkeys">Teclas de atalho</string>
|
||||
|
|
@ -118,6 +117,8 @@
|
|||
<string name="controller_dpad_axis_description">Alguns controles podem não ser capazes de mapear os D-pads para um eixo. Se esse for o caso, use a seção de D-Pad (Botões).</string>
|
||||
<string name="controller_dpad_button">D-Pad (Botão)</string>
|
||||
<string name="controller_dpad_button_description">Só mapeie o D-pad para isso se você se você estiver encontrando problemas com o mapeamento de botão do D-Pad (Eixo).</string>
|
||||
<string name="controller_axis_vertical">Eixo Vertical</string>
|
||||
<string name="controller_axis_horizontal">Eixo Horizontal</string>
|
||||
<string name="direction_up">Cima</string>
|
||||
<string name="direction_down">Baixo</string>
|
||||
<string name="direction_left">Esquerda</string>
|
||||
|
|
@ -126,6 +127,8 @@
|
|||
<string name="input_dialog_description">Pressione ou mova uma entrada.</string>
|
||||
<string name="input_binding">Mapeamento de controles</string>
|
||||
<string name="input_binding_description">Pressione ou mova um botão/alavanca para mapear para %1$s.</string>
|
||||
<string name="input_binding_description_vertical_axis">Pressione para CIMA no seu joystick.</string>
|
||||
<string name="input_binding_description_horizontal_axis">Pressione para a DIREITA no seu joystick.</string>
|
||||
<string name="button_home">Menu Principal</string>
|
||||
<string name="button_swap">Trocar telas</string>
|
||||
<string name="button_turbo">Turbo</string>
|
||||
|
|
@ -546,7 +549,7 @@
|
|||
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Preparando Shaders</string>
|
||||
<string name="building_shaders">Construindo Shaders</string>
|
||||
<string name="building_shaders">Construindo %s</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">Jogar</string>
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@
|
|||
<string name="search_recently_added">Добавленные недавно</string>
|
||||
<string name="search_installed">Установленные</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_circlepad">Джойстик</string>
|
||||
<string name="controller_c">C-стик</string>
|
||||
<string name="controller_hotkeys">Горячие клавиши</string>
|
||||
|
|
@ -304,8 +303,6 @@
|
|||
<string name="fatal_error_message">Возникла критическая ошибка. Откройте лог для получения информации.\nВозобновление эмуляции может привести к сбоям и вылетам.</string>
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Подготовка шейдеров</string>
|
||||
<string name="building_shaders">Построение шейдеров</string>
|
||||
|
||||
<!-- Cheats -->
|
||||
<string name="cheats">Чит-коды</string>
|
||||
<string name="cheats_add">Добавить чит-код</string>
|
||||
|
|
|
|||
|
|
@ -99,7 +99,6 @@
|
|||
<string name="search_recently_added">Son eklenen</string>
|
||||
<string name="search_installed">Yüklü</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_circlepad">Circle Pad</string>
|
||||
<string name="controller_c">C-Stick</string>
|
||||
<string name="controller_hotkeys">Kısayol tuşları</string>
|
||||
|
|
@ -481,8 +480,6 @@
|
|||
<string name="unsupported_encrypted">Desteklenmeyen şifreli uygulama</string>
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Gölgelendiriciler Hazırlanıyor</string>
|
||||
<string name="building_shaders">Gölgelendiriciler Oluşturuluyor</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">Oyna</string>
|
||||
<string name="uninstall_cia">Uygulamayı Sil</string>
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@
|
|||
<string name="search_recently_added">最近添加</string>
|
||||
<string name="search_installed">已安装</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_circlepad">方向摇杆</string>
|
||||
<string name="controller_c">C 摇杆</string>
|
||||
<string name="controller_hotkeys">热键</string>
|
||||
|
|
@ -528,8 +527,6 @@
|
|||
<string name="unsupported_encrypted">不支持的加密应用</string>
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">正在准备着色器</string>
|
||||
<string name="building_shaders">正在构建着色器</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">开始游戏</string>
|
||||
<string name="uninstall_cia">卸载应用</string>
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@
|
|||
<string name="search_recently_added">Kürzlich hinzugefügt</string>
|
||||
<string name="search_installed">Installiert</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_circlepad">Schiebepad</string>
|
||||
<string name="controller_c">C-Stick</string>
|
||||
<string name="controller_hotkeys">Tastenkürzel</string>
|
||||
|
|
@ -503,8 +502,6 @@
|
|||
<string name="unsupported_encrypted">Nicht unterstützte verschlüsselte Anwendung</string>
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Shader werden vorbereitet</string>
|
||||
<string name="building_shaders">Shader werden erstellt</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">Spielen</string>
|
||||
<string name="uninstall_cia">Anwendung deinstallieren</string>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,400 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_notification_running">Το Azahar εκτελείται</string>
|
||||
<!-- Home Strings -->
|
||||
<string name="grid_menu_core_settings">Ρυθμίσεις</string>
|
||||
<string name="home_options">Επιλογές</string>
|
||||
<string name="home_search">Αναζήτηση</string>
|
||||
<string name="home_games">Εφαρμογές</string>
|
||||
<string name="install_game_content">Εγκατάσταση αρχείου CIA</string>
|
||||
<string name="about">Σχετικά</string>
|
||||
<string name="about">Πληροφορίες</string>
|
||||
<string name="citra_description">Ένας εξομοιωτής 3DS ανοικτού κώδικα</string>
|
||||
<string name="install_cia_title">Εγκατάσταση CIA</string>
|
||||
|
||||
<string name="select_gpu_driver_install">Εγκατάσταση</string>
|
||||
<string name="select_gpu_driver_install_success">Εγκαταστάθηκε %s</string>
|
||||
<string name="select_gpu_driver_default">Προεπιλογή</string>
|
||||
<string name="select_gpu_driver_install_success">Εγκαταστάθηκε το %s</string>
|
||||
<string name="licenses">Άδειες χρήσης</string>
|
||||
<!-- Setup strings -->
|
||||
<string name="welcome">Καλώς ορίσατε!</string>
|
||||
<string name="step_complete">Ολοκληρώθηκε!</string>
|
||||
<string name="games">Εφαρμογές</string>
|
||||
<string name="done">Τέλος</string>
|
||||
<string name="text_continue">Συνέχεια</string>
|
||||
<string name="notifications">Ειδοποιήσεις</string>
|
||||
<string name="camera_permission">Κάμερα</string>
|
||||
<string name="microphone_permission">Μικρόφωνο</string>
|
||||
<string name="filesystem_permission">Σύστημα αρχείων</string>
|
||||
<string name="select_emulator_data_folders">Φάκελοι δεδομένων</string>
|
||||
<string name="warning_help">Βοήθεια</string>
|
||||
<string name="warning_skip">Παράλειψη</string>
|
||||
<string name="warning_cancel">Ακύρωση</string>
|
||||
<string name="select">Επιλογή</string>
|
||||
<string name="invalid_selection">Μη έγκυρη επιλογή</string>
|
||||
<string name="set_up_theme_settings">Ρυθμίσεις θέματος</string>
|
||||
<string name="setup_set_theme">Ορισμός θέματος</string>
|
||||
|
||||
<string name="controller_axis_vertical">Κάθετος άξονας</string>
|
||||
<string name="controller_axis_horizontal">Οριζόντιος άξονας</string>
|
||||
<string name="button_swap">Εναλλαγή οθονών</string>
|
||||
<!-- System files strings -->
|
||||
<string name="setup_system_files">Αρχεία συστήματος</string>
|
||||
<string name="setup_system_files_o3ds">Ρύθμιση για Old 3DS</string>
|
||||
<string name="setup_system_files_n3ds">Ρύθμιση για New 3DS</string>
|
||||
<!-- Generic buttons (Shared with lots of stuff) -->
|
||||
<string name="generic_buttons">Κουμπιά</string>
|
||||
<string name="button">Κουμπί</string>
|
||||
|
||||
<!-- System settings strings -->
|
||||
<string name="emulation_settings">Ρυθμίσεις εξομοίωσης</string>
|
||||
<string name="username">Όνομα χρήστη</string>
|
||||
<string name="new_3ds">Λειτουργία New 3DS</string>
|
||||
<string name="clock">Ρολόι</string>
|
||||
<string name="init_clock">Ρολόι</string>
|
||||
<string name="device_clock">Ρολόι συσκευής</string>
|
||||
<string name="simulated_clock">Εξομοιωμένο ρολόι</string>
|
||||
<string name="profile_settings">Ρυθμίσεις προφίλ</string>
|
||||
<string name="emulated_region">Περιοχή</string>
|
||||
<string name="emulated_language">Γλώσσα</string>
|
||||
<string name="birthday">Γενέθλια</string>
|
||||
<string name="birthday_month">Μήνας</string>
|
||||
<string name="birthday_day">Ημέρα</string>
|
||||
<string name="country">Χώρα</string>
|
||||
<string name="mac_address">Διεύθυνση MAC</string>
|
||||
<!-- Camera settings strings -->
|
||||
<string name="inner_camera">Εσωτερική κάμερα</string>
|
||||
<string name="camera_device">Κάμερα</string>
|
||||
<string name="graphics_api">API γραφικών</string>
|
||||
<string name="texture_filter_name">Φίλτρο υφής</string>
|
||||
<string name="shaders_accurate_mul">Ακριβής πολλαπλασιασμός</string>
|
||||
<string name="frame_limit_enable">Περιορισμός ταχύτητας</string>
|
||||
<string name="internal_resolution">Εσωτερική ανάλυση</string>
|
||||
<string name="internal_resolution_setting_1x">Εγγενής (400x240)</string>
|
||||
<string name="factor3d">Βάθος</string>
|
||||
<string name="cardboard_vr">Cardboard VR</string>
|
||||
<string name="dump_textures">Αποτύπωση υφών</string>
|
||||
<string name="custom_textures">Προσαρμοσμένες υφές</string>
|
||||
<!-- Audio settings strings -->
|
||||
<string name="audio_volume">Ένταση ήχου</string>
|
||||
<string name="audio_input_type">Συσκευή εισόδου ήχου</string>
|
||||
<string name="sound_output_mode">Λειτουργία εξόδου ήχου</string>
|
||||
|
||||
<string name="vsync">Ενεργοποίηση V-Sync</string>
|
||||
<!-- Layout settings strings -->
|
||||
<string name="layout_screen_orientation">Προσανατολισμός οθόνης</string>
|
||||
<string name="aspect_ratio_default">Προεπιλογή</string>
|
||||
<string name="aspect_ratio_16_9">16:9</string>
|
||||
<string name="aspect_ratio_4_3">4:3</string>
|
||||
<string name="aspect_ratio_21_9_fullscreen">21:9</string>
|
||||
<string name="aspect_ratio_16_10_fullscreen_stretched">16:10</string>
|
||||
<!-- Miscellaneous -->
|
||||
<string name="clear">Απαλοιφή</string>
|
||||
<string name="slider_default">Προεπιλογή</string>
|
||||
<string name="saving">Αποθήκευση…</string>
|
||||
<string name="loading">Φόρτωση…</string>
|
||||
<string name="next">Επόμενο</string>
|
||||
<string name="back">Πίσω</string>
|
||||
<string name="learn_more">Μάθετε περισσότερα</string>
|
||||
<string name="close">Κλείσιμο</string>
|
||||
<string name="option_default">Προεπιλογή</string>
|
||||
<string name="install">Εγκατάσταση</string>
|
||||
<string name="delete">Διαγραφή</string>
|
||||
<string name="reset_all_settings">Επαναφορά όλων των ρυθμίσεων;</string>
|
||||
<string name="auto_select">Αυτόματη επιλογή</string>
|
||||
<string name="cancelling">Ακύρωση…</string>
|
||||
<string name="visibility">Ορατότητα</string>
|
||||
<string name="information">Πληροφορίες</string>
|
||||
|
||||
<!-- Add Directory Screen-->
|
||||
<string name="select_game_folder">Επιλογή φακέλου παιχνιδιού</string>
|
||||
|
||||
<!-- Game Properties -->
|
||||
<string name="properties">Ιδιότητες</string>
|
||||
<!-- Preferences Screen -->
|
||||
<string name="preferences_settings">Ρυθμίσεις</string>
|
||||
<string name="preferences_general">Γενικά</string>
|
||||
<string name="preferences_system">Σύστημα</string>
|
||||
<string name="preferences_camera">Κάμερα</string>
|
||||
<string name="preferences_graphics">Γραφικά</string>
|
||||
<string name="preferences_audio">Ήχος</string>
|
||||
<string name="preferences_debug">Έλεγχος σφαλμάτων</string>
|
||||
<string name="preferences_theme">Θέμα και χρώμα</string>
|
||||
<string name="preferences_layout">Διάταξη</string>
|
||||
|
||||
<string name="loader_error_invalid_format">Μη έγκυρη μορφή ROM</string>
|
||||
<string name="emulation_save_state">Αποθήκευση κατάστασης</string>
|
||||
<string name="emulation_load_state">Φόρτωση κατάστασης</string>
|
||||
<string name="emulation_edit_layout">Επεξεργασία διάταξης</string>
|
||||
<string name="emulation_done">Τέλος</string>
|
||||
<string name="emulation_control_scale">Προσαρμογή κλίμακας</string>
|
||||
<string name="emulation_control_scale_global">Καθολική κλίμακα</string>
|
||||
<string name="emulation_control_scale_reset_all">Επαναφορά όλων</string>
|
||||
<string name="emulation_control_opacity">Προσαρμογή αδιαφάνειας</string>
|
||||
<string name="emulation_open_cheats">Άνοιγμα cheat</string>
|
||||
<string name="emulation_screen_layout_largescreen">Μεγάλη οθόνη</string>
|
||||
<string name="emulation_screen_layout_single">Μονή οθόνη</string>
|
||||
<string name="emulation_screen_layout_hybrid">Υβριδικές οθόνες</string>
|
||||
<string name="emulation_portrait_layout_top_full">Προεπιλογή</string>
|
||||
<string name="emulation_screen_layout_custom">Προσαρμοσμένη διάταξη</string>
|
||||
<string name="bg_red">Κόκκινο</string>
|
||||
<string name="bg_green">Πράσινο</string>
|
||||
<string name="bg_blue">Μπλε</string>
|
||||
<string name="emulation_top_screen">Πάνω οθόνη</string>
|
||||
<string name="emulation_bottom_screen">Κάτω οθόνη</string>
|
||||
<string name="emulation_custom_layout_x">Θέση X</string>
|
||||
<string name="emulation_custom_layout_y">Θέση Y</string>
|
||||
<string name="emulation_custom_layout_width">Πλάτος</string>
|
||||
<string name="emulation_custom_layout_height">Ύψος</string>
|
||||
<string name="emulation_close_game">Κλείσιμο παιχνιδιού</string>
|
||||
<string name="menu_emulation_amiibo">Amiibo</string>
|
||||
<string name="menu_emulation_amiibo_load">Φόρτωση</string>
|
||||
<string name="menu_emulation_amiibo_remove">Αφαίρεση</string>
|
||||
<string name="select_amiibo">Επιλογή αρχείου Amiibo</string>
|
||||
<string name="amiibo_load_error">Σφάλμα φόρτωσης Amiibo</string>
|
||||
<string name="pause_emulation">Παύση εξομοίωσης</string>
|
||||
<string name="resume_emulation">Συνέχιση εξομοίωσης</string>
|
||||
<string name="load_settings">Φόρτωση ρυθμίσεων…</string>
|
||||
|
||||
<string name="move_data">Μετακίνηση δεδομένων</string>
|
||||
<string name="moving_data">Μετακίνηση δεδομένων…</string>
|
||||
<string name="copy_file_name">Αντιγραφή αρχείου: %s</string>
|
||||
<!-- Software Keyboard -->
|
||||
<string name="software_keyboard">Εικονικό πληκτρολόγιο</string>
|
||||
<!-- Camera -->
|
||||
<string name="camera_select_image">Επιλογή εικόνας</string>
|
||||
<string name="camera">Κάμερα</string>
|
||||
<!-- Microphone -->
|
||||
<string name="microphone">Μικρόφωνο</string>
|
||||
<!-- Core Errors -->
|
||||
<string name="abort_button">Ακύρωση</string>
|
||||
<string name="continue_button">Συνέχεια</string>
|
||||
<string name="system_archive_general">Ένα αρχείο συστήματος</string>
|
||||
<string name="save_load_error">Σφάλμα αποθήκευσης/φόρτωσης</string>
|
||||
<string name="fatal_error">Κρίσιμο σφάλμα</string>
|
||||
<string name="unsupported_encrypted">Μη υποστηριζόμενη κρυπτογραφημένη εφαρμογή</string>
|
||||
<string name="game_context_open_app">Άνοιγμα φακέλου εφαρμογής</string>
|
||||
<string name="shortcut">Συντόμευση</string>
|
||||
<string name="shortcut_name">Όνομα συντόμευσης</string>
|
||||
<string name="edit_icon">Επεξεργασία εικονιδίου</string>
|
||||
<string name="create_shortcut">Δημιουργία συντόμευσης</string>
|
||||
<string name="game_context_file">Αρχείο:</string>
|
||||
<string name="game_context_type">Τύπος:</string>
|
||||
<string name="performance_overlay_show_speed">Εμφάνιση ταχύτητας</string>
|
||||
<!-- Cheats -->
|
||||
<string name="cheats">Cheat</string>
|
||||
<string name="cheats_add">Προσθήκη cheat</string>
|
||||
<string name="cheats_name">Όνομα</string>
|
||||
<string name="cheats_notes">Σημειώσεις</string>
|
||||
<string name="cheats_code">Κώδικας</string>
|
||||
<string name="cheats_edit">Επεξεργασία</string>
|
||||
<string name="cheats_delete">Διαγραφή</string>
|
||||
<string name="cia_install_notification_title">Εγκατάσταση CIA</string>
|
||||
<!-- Memory Sizes -->
|
||||
<string name="memory_formatted">%1$s %2$s</string>
|
||||
<string name="memory_byte">Byte</string>
|
||||
<string name="memory_byte_shorthand">B</string>
|
||||
<string name="memory_kilobyte">KB</string>
|
||||
<string name="memory_megabyte">MB</string>
|
||||
<string name="memory_gigabyte">GB</string>
|
||||
<string name="memory_terabyte">TB</string>
|
||||
<string name="memory_petabyte">PB</string>
|
||||
<string name="memory_exabyte">EB</string>
|
||||
|
||||
<!-- Material You theme -->
|
||||
<string name="material_you">Material You</string>
|
||||
<!-- Static theme color -->
|
||||
<string name="static_theme_color">Χρώμα θέματος</string>
|
||||
<!-- Region names -->
|
||||
<string name="system_region_jpn">JPN</string>
|
||||
<string name="system_region_usa">USA</string>
|
||||
<string name="system_region_eur">EUR</string>
|
||||
<string name="system_region_aus">AUS</string>
|
||||
<string name="system_region_chn">CHN</string>
|
||||
<string name="system_region_kor">KOR</string>
|
||||
<string name="system_region_twn">TWN</string>
|
||||
|
||||
<!-- Language names -->
|
||||
<string name="language_japanese">Ιαπωνικά (日本語)</string>
|
||||
<string name="language_french">Γαλλικά (Français)</string>
|
||||
<string name="language_german">Γερμανικά (Deutsch)</string>
|
||||
<string name="language_italian">Ιταλικά (Italiano)</string>
|
||||
<string name="language_spanish">Ισπανικά (Español)</string>
|
||||
<string name="language_simplified_chinese">Απλοποιημένα Κινεζικά (简体中文)</string>
|
||||
<string name="language_korean">Κορεατικά (한국어)</string>
|
||||
<string name="language_dutch">Ολλανδικά (Nederlands)</string>
|
||||
<string name="language_portuguese">Πορτογαλικά (Português)</string>
|
||||
<string name="language_russian">Ρωσικά (Русский)</string>
|
||||
<string name="language_traditional_chinese">Παραδοσιακά Κινεζικά (正體中文)</string>
|
||||
|
||||
<string name="device_camera">Κάμερα συσκευής</string>
|
||||
|
||||
<!-- Graphics API names -->
|
||||
<string name="opengles">OpenGLES</string>
|
||||
<string name="vulkan">Vulkan</string>
|
||||
|
||||
<!-- Texture filter names -->
|
||||
<string name="anime4k">Anime4K</string>
|
||||
<string name="xbrz">xBRZ</string>
|
||||
<string name="mmpx">MMPX</string>
|
||||
|
||||
<!-- Countries -->
|
||||
<string name="japan">Ιαπωνία</string>
|
||||
<string name="anguilla">Ανγκουίλα</string>
|
||||
<string name="antigua_and_barbuda">Αντίγκουα και Μπαρμπούντα</string>
|
||||
<string name="argentina">Αργεντινή</string>
|
||||
<string name="aruba">Αρούμπα</string>
|
||||
<string name="bahamas">Μπαχάμες</string>
|
||||
<string name="barbados">Μπαρμπάντος</string>
|
||||
<string name="belize">Μπελίζ</string>
|
||||
<string name="bolivia">Βολιβία</string>
|
||||
<string name="brazil">Βραζιλία</string>
|
||||
<string name="british_virgin_islands">Βρετανικές Παρθένοι Νήσοι</string>
|
||||
<string name="canada">Καναδάς</string>
|
||||
<string name="cayman_islands">Νήσοι Κέιμαν</string>
|
||||
<string name="chile">Χιλή</string>
|
||||
<string name="colombia">Κολομβία</string>
|
||||
<string name="costa_rica">Κόστα Ρίκα</string>
|
||||
<string name="dominica">Δομινίκα</string>
|
||||
<string name="dominican_republic">Δομινικανή Δημοκρατία</string>
|
||||
<string name="ecuador">Εκουαδόρ</string>
|
||||
<string name="el_salvador">Ελ Σαλβαδόρ</string>
|
||||
<string name="french_guiana">Γαλλική Γουιάνα</string>
|
||||
<string name="grenada">Γρενάδα</string>
|
||||
<string name="guadeloupe">Γουαδελούπη</string>
|
||||
<string name="guatemala">Γουατεμάλα</string>
|
||||
<string name="guyana">Γουιάνα</string>
|
||||
<string name="haiti">Αϊτή</string>
|
||||
<string name="honduras">Ονδούρα</string>
|
||||
<string name="jamaica">Τζαμάικα</string>
|
||||
<string name="matinique">Μαρτινίκα</string>
|
||||
<string name="mexico">Μεξικό</string>
|
||||
<string name="monsterrat">Μοντσερράτ</string>
|
||||
<string name="netherlands_antilles">Ολλανδικές Αντίλλες</string>
|
||||
<string name="nicaragua">Νικαράγουα</string>
|
||||
<string name="panama">Παναμάς</string>
|
||||
<string name="paraguay">Παραγουάη</string>
|
||||
<string name="peru">Περού</string>
|
||||
<string name="saint_lucia">Αγία Λουκία</string>
|
||||
<string name="suriname">Σουρινάμ</string>
|
||||
<string name="trinidad_and_tobago">Τρινιντάντ και Τομπάγκο</string>
|
||||
<string name="united_states">Ηνωμένες Πολιτείες</string>
|
||||
<string name="uruguay">Ουρουγουάη</string>
|
||||
<string name="us_virgin_islands">Αμερικανικές Παρθένοι Νήσοι</string>
|
||||
<string name="venezuela">Βενεζουέλα</string>
|
||||
<string name="albania">Αλβανία</string>
|
||||
<string name="australia">Αυστραλία</string>
|
||||
<string name="austria">Αυστρία</string>
|
||||
<string name="belgium">Βέλγιο</string>
|
||||
<string name="bosnia_and_herzegovnia">Βοσνία και Ερζεγοβίνη</string>
|
||||
<string name="botswana">Μποτσουάνα</string>
|
||||
<string name="bulgaria">Βουλγαρία</string>
|
||||
<string name="croatia">Κροατία</string>
|
||||
<string name="cyprus">Κύπρος</string>
|
||||
<string name="czech_republic">Τσεχία</string>
|
||||
<string name="denmark">Δανία</string>
|
||||
<string name="estonia">Εσθονία</string>
|
||||
<string name="finland">Φινλανδία</string>
|
||||
<string name="france">Γαλλία</string>
|
||||
<string name="germany">Γερμανία</string>
|
||||
<string name="greece">Ελλάδα</string>
|
||||
<string name="hungary">Ουγγαρία</string>
|
||||
<string name="iceland">Ισλανδία</string>
|
||||
<string name="ireland">Ιρλανδία</string>
|
||||
<string name="italy">Ιταλία</string>
|
||||
<string name="latvia">Λετονία</string>
|
||||
<string name="lesotho">Λεσότο</string>
|
||||
<string name="liechtenstein">Λιχτενστάιν</string>
|
||||
<string name="lithuania">Λιθουανία</string>
|
||||
<string name="luxembourg">Λουξεμβούργο</string>
|
||||
<string name="macedonia">Βόρεια Μακεδονία</string>
|
||||
<string name="malta">Μάλτα</string>
|
||||
<string name="montenegro">Μαυροβούνιο</string>
|
||||
<string name="mozambique">Μοζαμβίκη</string>
|
||||
<string name="namibia">Ναμίμπια</string>
|
||||
<string name="netherlands">Ολλανδία</string>
|
||||
<string name="new_zealand">Νέα Ζηλανδία</string>
|
||||
<string name="norway">Νορβηγία</string>
|
||||
<string name="poland">Πολωνία</string>
|
||||
<string name="portugal">Πορτογαλία</string>
|
||||
<string name="romania">Ρουμανία</string>
|
||||
<string name="russia">Ρωσία</string>
|
||||
<string name="serbia">Σερβία</string>
|
||||
<string name="slovakia">Σλοβακία</string>
|
||||
<string name="slovenia">Σλοβενία</string>
|
||||
<string name="south_africa">Νότια Αφρική</string>
|
||||
<string name="spain">Ισπανία</string>
|
||||
<string name="swaziland">Εσουατίνι</string>
|
||||
<string name="sweden">Σουηδία</string>
|
||||
<string name="switzerland">Ελβετία</string>
|
||||
<string name="turkey">Τουρκία</string>
|
||||
<string name="united_kingdom">Ηνωμένο Βασίλειο</string>
|
||||
<string name="zambia">Ζάμπια</string>
|
||||
<string name="zimbabwe">Ζιμπάμπουε</string>
|
||||
<string name="azerbaijan">Αζερμπαϊτζάν</string>
|
||||
<string name="mauritania">Μαυριτανία</string>
|
||||
<string name="mali">Μάλι</string>
|
||||
<string name="niger">Νίγηρας</string>
|
||||
<string name="chad">Τσαντ</string>
|
||||
<string name="sudan">Σουδάν</string>
|
||||
<string name="eritrea">Ερυθραία</string>
|
||||
<string name="djibouti">Τζιμπουτί</string>
|
||||
<string name="somalia">Σομαλία</string>
|
||||
<string name="andorra">Ανδόρρα</string>
|
||||
<string name="gibraltar">Γιβραλτάρ</string>
|
||||
<string name="guernsey">Γκέρνζι</string>
|
||||
<string name="isle_of_man">Νήσος του Μαν</string>
|
||||
<string name="jersey">Τζέρσεϊ</string>
|
||||
<string name="monaco">Μονακό</string>
|
||||
<string name="taiwan">Ταϊβάν</string>
|
||||
<string name="south_korea">Νότια Κορέα</string>
|
||||
<string name="hong_kong">Χονγκ Κονγκ</string>
|
||||
<string name="macau">Μακάο</string>
|
||||
<string name="indonesia">Ινδονησία</string>
|
||||
<string name="singapore">Σιγκαπούρη</string>
|
||||
<string name="thailand">Ταϊλάνδη</string>
|
||||
<string name="philippines">Φιλιππίνες</string>
|
||||
<string name="malaysia">Μαλαισία</string>
|
||||
<string name="china">Κίνα</string>
|
||||
<string name="united_arab_emirates">Ηνωμένα Αραβικά Εμιράτα</string>
|
||||
<string name="india">Ινδία</string>
|
||||
<string name="egypt">Αίγυπτος</string>
|
||||
<string name="oman">Ομάν</string>
|
||||
<string name="qatar">Κατάρ</string>
|
||||
<string name="kuwait">Κουβέιτ</string>
|
||||
<string name="saudi_arabia">Σαουδική Αραβία</string>
|
||||
<string name="syria">Συρία</string>
|
||||
<string name="bahrain">Μπαχρέιν</string>
|
||||
<string name="jordan">Ιορδανία</string>
|
||||
<string name="san_marino">Άγιος Μαρίνος</string>
|
||||
<string name="vatican_city">Βατικανό</string>
|
||||
<string name="bermuda">Βερμούδες</string>
|
||||
|
||||
<!-- Months -->
|
||||
<string name="january">Ιανουάριος</string>
|
||||
<string name="february">Φεβρουάριος</string>
|
||||
<string name="march">Μάρτιος</string>
|
||||
<string name="april">Απρίλιος</string>
|
||||
<string name="may">Μάιος</string>
|
||||
<string name="june">Ιούνιος</string>
|
||||
<string name="july">Ιούλιος</string>
|
||||
<string name="august">Αύγουστος</string>
|
||||
<string name="september">Σεπτέμβριος</string>
|
||||
<string name="october">Οκτώβριος</string>
|
||||
<string name="november">Νοέμβριος</string>
|
||||
<string name="december">Δεκέμβριος</string>
|
||||
|
||||
<string name="artic_base">Artic Base</string>
|
||||
<!-- Quickload&Save-->
|
||||
<string name="emulation_quicksave_slot">Γρήγορη αποθήκευση</string>
|
||||
<string name="emulation_quicksave">Γρήγορη αποθήκευση</string>
|
||||
<string name="emulation_quickload">Γρήγορη φόρτωση</string>
|
||||
<string name="emulation_occupied_quicksave_slot">Γρήγορη αποθήκευση - %1$tF %1$tR</string>
|
||||
<!-- File Compression -->
|
||||
<string name="compress">Συμπίεση</string>
|
||||
<string name="compressing">Συμπίεση…</string>
|
||||
<string name="decompress">Αποσυμπίεση</string>
|
||||
<string name="decompressing">Αποσυμπίεση…</string>
|
||||
<string name="compress_failed">Η συμπίεση απέτυχε.</string>
|
||||
<string name="decompress_failed">Η αποσυμπίεση απέτυχε.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
<string name="notification_warning">Ne pas autoriser les notifications ?</string>
|
||||
<string name="notification_warning_description">Azahar ne pourra pas vous avertir des informations importantes.</string>
|
||||
<string name="filesystem_permission_warning">Autorisations manquantes</string>
|
||||
<string name="filesystem_permission_warning_description">Azahar a besoin de l\'autorisation de gérer les fichiers de cet appareil afin de stocker et gérer ses données.\n\nVeuillez accorder l\'autorisation \"Accès à tous les fichiers\" avant de continuer.</string>
|
||||
<string name="filesystem_permission_warning_description">Azahar a besoin de l\'autorisation de gérer les fichiers de cet appareil afin de stocker et gérer ses données.\n\nVeuillez accorder l\'autorisation \"Accès à tous les fichiers\" pour continuer.</string>
|
||||
<string name="camera_permission">Caméra</string>
|
||||
<string name="camera_permission_description">Accorder l\'autorisation de la caméra ci-dessous pour émuler la caméra 3DS.</string>
|
||||
<string name="microphone_permission">Microphone</string>
|
||||
|
|
@ -108,9 +108,17 @@
|
|||
<string name="search_installed">Installé</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_auto_map">Assigner les boutons de la manette automatiquement</string>
|
||||
<string name="controller_auto_map_description">Applique un assignement standard de manette pour tous les boutons et axes</string>
|
||||
<string name="auto_map_prompt">Appuyez sur ce bouton de votre manette !</string>
|
||||
<string name="auto_map_image_description">Les quatre boutons situés à droite de la 3DS avec le bouton A surligné</string>
|
||||
<string name="controller_clear_all">Réinitialiser toutes les assignations de touche</string>
|
||||
<string name="controller_clear_all_confirm">Cela effacera toutes les assignations de touche de manette actuelles.</string>
|
||||
<string name="controller_circlepad">Pad circulaire</string>
|
||||
<string name="controller_c">Stick C</string>
|
||||
<string name="controller_hotkeys">Raccourcis</string>
|
||||
<string name="controller_hotkeys_description">Si la touche \"Activer les raccourcis\" est assignée, celle-ci doit être pressée en plus de tout autre touche de raccourci.</string>
|
||||
<string name="controller_hotkey_enable_button">Activer les raccourcis</string>
|
||||
<string name="controller_triggers">Gachettes</string>
|
||||
<string name="controller_trigger">Déclencheur</string>
|
||||
<string name="controller_dpad">Manette +</string>
|
||||
|
|
@ -229,9 +237,11 @@
|
|||
<string name="async_shaders_description">Compile les shaders en arrière-plan pour réduire les saccades pendant le jeu. Lorsqu\'il est activé, prévoyez des problèmes graphiques temporaires.</string>
|
||||
<string name="linear_filtering">Filtrage linéaire</string>
|
||||
<string name="linear_filtering_description">Active le filtrage linéaire, qui améliorera le lissage graphique du jeu.</string>
|
||||
<string name="use_integer_scaling">Redimensionnement par nombre entier</string>
|
||||
<string name="use_integer_scaling_description">Redimensionne les écrans avec un multiple entier de la taille de l\'écran original de la 3DS. Pour les dispositions avec deux tailles d\'écrans différentes, c\'est l\'écran le plus large qui est redimensionné par un multiple entier.</string>
|
||||
<string name="texture_filter_name">Filtrage des textures</string>
|
||||
<string name="texture_filter_description">Améliore l\'aspect visuel des applications en appliquant un filtre aux textures. Les filtres pris en charge sont Anime4K Ultrafast, Bicubique, ScaleForce, xBRZ freescale et MMPX.</string>
|
||||
<string name="delay_render_thread">Retarder le thread de rendu du jeu</string>
|
||||
<string name="delay_render_thread">Retarder le fil de rendu du jeu</string>
|
||||
<string name="delay_render_thread_description">Délai le thread de rendu du jeu lorsqu\'il soumet des données au GPU. Cela permet de résoudre les problèmes de performance dans les (très rares) applications avec des fréquences d\'images dynamiques.</string>
|
||||
<string name="advanced">Avancé</string>
|
||||
<string name="texture_sampling_name">Échantillonnage de texture</string>
|
||||
|
|
@ -315,10 +325,10 @@
|
|||
<string name="hw_shaders_description">Utilise le hardware pour émuler les shaders de la 3DS. Lorsqu\'il est activé, la performance des jeux sera améliorée de manière significative.</string>
|
||||
<string name="cpu_clock_speed">Fréquence d\'horloge du CPU</string>
|
||||
<string name="vsync">Activer la synchronisation verticale (VSync)</string>
|
||||
<string name="vsync_description">Synchronise la fréquence d\'images du jeu avec la fréquence de rafraîchissement de votre appareil. Peut rajouter de la latence d\'entrée mais peut réduire le tearing dans certains cas.</string>
|
||||
<string name="vsync_description">Synchronise la fréquence d\'images du jeu avec la fréquence de rafraîchissement de votre appareil. Peut rajouter de la latence d\'entrée mais peut réduire le déchirement d\'écran dans certains cas.</string>
|
||||
<string name="renderer_debug">Rendu de débogage</string>
|
||||
<string name="renderer_debug_description">Enregistre des informations de débogage supplémentaires liées aux graphiques. Lorsqu\'il est activé, les performances du jeu seront significativement réduites.</string>
|
||||
<string name="instant_debug_log">Vider la sortie des logs sur chaque message</string>
|
||||
<string name="instant_debug_log">Vider la sortie des logs à chaque message</string>
|
||||
<string name="instant_debug_log_description">Enregistre immédiatement le log de débogage dans un fichier. A utiliser si Azahar se plante et que la sortie du journal est coupée.</string>
|
||||
<string name="delay_start_lle_modules">Démarrage différé avec les modules LLE</string>
|
||||
<string name="delay_start_lle_modules_description">Retarde le démarrage de l\'application lorsque les modules LLE sont activés.</string>
|
||||
|
|
@ -326,6 +336,8 @@
|
|||
<string name="deterministic_async_operations_description">Rend les opérations asynchrones déterministes pour le débogage. L\'activation de cette fonction peut entraîner des blocages.</string>
|
||||
<string name="enable_rpc_server">Activer le serveur RPC</string>
|
||||
<string name="enable_rpc_server_desc">Active le serveur RPC sur le port 45987. Cela permet de lire/écrire à distance la mémoire invitée.</string>
|
||||
<string name="toggle_unique_data_console_type">Basculer le type de console des données uniques</string>
|
||||
<string name="toggle_unique_data_console_type_desc">Change le type de console des données uniques (Old 3DS ↔ New 3DS) afin de pouvoir télécharger le firmware système opposé depuis les paramètres de la console.</string>
|
||||
<string name="shader_jit">Activer Shader JIT</string>
|
||||
<string name="shader_jit_description">Utilisez le moteur JIT à la place de l\'interpréteur pour l\'émulation des shaders logiciels.</string>
|
||||
|
||||
|
|
@ -336,6 +348,8 @@
|
|||
<string name="layout_screen_orientation_landscape_reverse">Paysage inversé</string>
|
||||
<string name="layout_screen_orientation_portrait">Portait</string>
|
||||
<string name="layout_screen_orientation_portrait_reverse">Portait inversé</string>
|
||||
<string name="layouts_to_cycle">Dispositions à alterner</string>
|
||||
<string name="layouts_to_cycle_description">Quelles dispositions sont alternées par le raccourci Alterner les dispositions</string>
|
||||
<string name="aspect_ratio_default">Par défaut</string>
|
||||
<string name="aspect_ratio_16_9">16:9</string>
|
||||
<string name="aspect_ratio_4_3">4:3</string>
|
||||
|
|
@ -473,7 +487,7 @@
|
|||
<string name="emulation_custom_layout_y">Position Y</string>
|
||||
<string name="emulation_custom_layout_width">Largeur</string>
|
||||
<string name="emulation_custom_layout_height">Hauteur</string>
|
||||
<string name="emulation_cycle_landscape_layouts">Dispositions de cycle</string>
|
||||
<string name="emulation_cycle_landscape_layouts">Dispositions à alterner</string>
|
||||
<string name="emulation_swap_screens">Permuter les écrans</string>
|
||||
<string name="emulation_rotate_upright">Tourner l\'écran à la verticale</string>
|
||||
<string name="emulation_touch_overlay_reset">Réinitialiser l\'overlay</string>
|
||||
|
|
@ -550,7 +564,7 @@
|
|||
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Préparation des shaders</string>
|
||||
<string name="building_shaders">Construction des shaders</string>
|
||||
<string name="building_shaders">Construction %s</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">Jouer</string>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_disclaimer">Questo software eseguirà applicazioni per la console portatile Nintendo 3DS. Nessun titolo è incluso.
|
||||
Prima di iniziare con l\'emulazione, seleziona una cartella che conterrà i dati utente.
|
||||
Cos\'è questo:
|
||||
<a href='https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage'> Wiki - Citra Android user data and storage</a></string>
|
||||
<string name="app_disclaimer">Questo software eseguirà applicazioni per la console portatile Nintendo 3DS. Nessun titolo è incluso.\n\nPrima di iniziare con l\'emulazione, seleziona una cartella che conterrà i dati utente.\n\nCos\'è questo:\n<a href='https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage'> Wiki - Citra Android user data and storage</a></string>
|
||||
<string name="app_notification_channel_description">Notifiche emulatore Azahar 3DS</string>
|
||||
<string name="app_notification_running">Azahar è in esecuzione</string>
|
||||
<string name="app_game_install_description">Ora è necessario selezionare una cartella Applicazioni. Azahar mostrerà tutte le ROM 3DS all\'interno della cartella selezionata nell\'app. Le ROM CIA, gli aggiornamenti e DLC dovranno essere installati separatamente cliccando sulla cartella e selezionando installa CIA.</string>
|
||||
|
|
@ -24,8 +21,7 @@ Cos\'è questo:
|
|||
<string name="install_gpu_driver_description">Installa driver alternativi per possibili miglioramenti delle prestazioni o dell\'accuratezza</string>
|
||||
<string name="driver_already_installed">Driver già installato</string>
|
||||
<string name="custom_driver_not_supported">Driver personalizzato non supportato</string>
|
||||
<string name="custom_driver_not_supported_description">Il caricamento di driver personalizzati non è disponibile per questo dispositivo.
|
||||
Controlla ancora questa opzione in futuro per controllare se il supporto è stato aggiunto!</string>
|
||||
<string name="custom_driver_not_supported_description">Il caricamento di driver personalizzati non è supportato su questo dispositivo.\nControlla di nuovo in futuro per verificare eventuali aggiornamenti!</string>
|
||||
<string name="share_log_not_found">Nessun file di log trovato</string>
|
||||
<string name="select_games_folder">Seleziona cartella applicazioni</string>
|
||||
<string name="select_games_folder_description">Permette ad Azahar di popolare la lista di applicazioni</string>
|
||||
|
|
@ -57,28 +53,27 @@ Controlla ancora questa opzione in futuro per controllare se il supporto è stat
|
|||
<string name="licenses">Licenze</string>
|
||||
<!-- Setup strings -->
|
||||
<string name="welcome">Benvenuto!</string>
|
||||
<string name="welcome_description">Scopri come impostare Azahar e immergiti nell\'emulazione.</string>
|
||||
<string name="welcome_description">Scopri come impostare <b>Azahar</b> e immergiti nell\'emulazione.</string>
|
||||
<string name="get_started">Inizia</string>
|
||||
<string name="step_complete">Completato!</string>
|
||||
<string name="games">Applicazioni</string>
|
||||
<string name="games_description">Seleziona la tua cartella <b>Applicazioni</b> usando il pulsante qui sotto.</string>
|
||||
<string name="done">Fatto</string>
|
||||
<string name="done_description">Adesso sei pronto.
|
||||
Divertiti usando l\'emulatore!</string>
|
||||
<string name="done_description">Adesso sei pronto.\nDivertiti usando l\'emulatore!</string>
|
||||
<string name="text_continue">Continua</string>
|
||||
<string name="notifications">Notifiche</string>
|
||||
<string name="notifications_description">Concedi il permesso di notifica usando il pulsante qui sotto.</string>
|
||||
<string name="give_permission">Concedi il permesso</string>
|
||||
<string name="notification_warning">Vuoi saltare la concessione del permesso di notifica?</string>
|
||||
<string name="notification_warning">Vuoi saltare l\'autorizzazione per le notifiche?</string>
|
||||
<string name="notification_warning_description">Azahar non avrà il permesso di notificarti con informazioni importanti.</string>
|
||||
<string name="filesystem_permission_warning">Permessi mancanti</string>
|
||||
<string name="filesystem_permission_warning_description">Azahar richiede l\'autorizzazione per gestire i file su questo dispositivo per archiviare e gestire i propri dati.\n\nDare il permesso \"Filesystem\" prima di continuare.</string>
|
||||
<string name="camera_permission">Fotocamera</string>
|
||||
<string name="camera_permission_description">Concedi il permesso alla fotocamera qui sotto per emulare la fotocamera del 3DS</string>
|
||||
<string name="camera_permission_description">Concedi il permesso alla fotocamera qui sotto per emulare la fotocamera del 3DS.</string>
|
||||
<string name="microphone_permission">Microfono</string>
|
||||
<string name="microphone_permission_description">Concedi il permesso all\'utilizzo del microfono per emulare il microfono del 3DS</string>
|
||||
<string name="microphone_permission_description">Concedi il permesso all\'utilizzo del microfono per emulare il microfono del 3DS.</string>
|
||||
<string name="filesystem_permission">Filesystem</string>
|
||||
<string name="filesystem_permission_description">Dare il permesso del file system qui sotto per consentire ad Azahar di archiviare file.</string>
|
||||
<string name="filesystem_permission_description">Autorizza l\'accesso al filesystem per consentire il salvataggio dei dati.</string>
|
||||
<string name="permission_denied">Permesso negato</string>
|
||||
<string name="add_games_warning">Saltare la selezione della cartella applicazioni?</string>
|
||||
<string name="add_games_warning_description">Non verrà mostrato alcun software nella lista applicazioni se non viene selezionata alcuna cartella.</string>
|
||||
|
|
@ -91,15 +86,15 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="warning_cancel">Annulla</string>
|
||||
<string name="select_citra_user_folder">Seleziona cartella utente</string>
|
||||
<string name="select_citra_user_folder_description"><![CDATA[Seleziona la tua cartella <a href=\"https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage\">utente</a> usando il pulsante qui sotto.]]></string>
|
||||
<string name="select_which_user_directory_to_use">Sembra che tu abbia impostato la cartella utente sia per Lime3DS che per Azahar. Questo probabilmente è dovuto al fatto che hai eseguito l\'aggiornamento ad Azahar e, al momento della richiesta, hai scelto una directory utente diversa da quella utilizzata per Lime3DS.\n\nQuesto potrebbe averti fatto pensare di aver perso salvataggi o altre impostazioni - ci scusiamo se è successo.\n\nDesideri tornare a utilizzare la tua cartella utente originale di Lime3DS, ripristinando impostazioni e salvataggi da Lime3DS, oppure preferisci mantenere la cartella utente attuale di Azahar?\n\nNessuna delle cartelle verrà eliminata, indipendentemente dalla tua scelta, e potrai passare liberamente da una all\'altra utilizzando l\'opzione \"Seleziona Cartella Utente\".</string>
|
||||
<string name="select_which_user_directory_to_use">Sembra che tu abbia impostato cartelle utente sia per Lime3DS che per Azahar. Questo è probabilmente dovuto al fatto che hai eseguito l\'aggiornamento ad Azahar e, al momento della richiesta, hai scelto una cartella utente diversa da quella utilizzata per Lime3DS.\n\nQuesto potrebbe averti fatto pensare di aver perso salvataggi o altre impostazioni - ci scusiamo se è successo.\n\nDesideri tornare a utilizzare la tua cartella utente originale di Lime3DS, ripristinando impostazioni e salvataggi da Lime3DS, oppure preferisci mantenere la cartella utente attuale di Azahar?\n\nNessuna delle cartelle verrà eliminata, indipendentemente dalla tua scelta, e potrai passare liberamente da una all\'altra utilizzando l\'opzione \"Seleziona Cartella Utente\".</string>
|
||||
<string name="keep_current_azahar_directory">Mantieni la cartella di Azahar attuale</string>
|
||||
<string name="use_prior_lime3ds_directory">Usa la cartella precedente di Lime3DS</string>
|
||||
<string name="select">Seleziona</string>
|
||||
<string name="cannot_skip">Non puoi saltare la configurazione della cartella utente</string>
|
||||
<string name="cannot_skip_directory_description">Questo passaggio è richiesto per permettere che Azahar funzioni. Quando la cartella verrà selezionata potrai continuare.</string>
|
||||
<string name="selecting_user_directory_without_write_permissions">Hai perso i permessi di scrittura sulla tua <a href="https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage">cartella dei dati utente</a>, dove sono memorizzati i salvataggi e altre informazioni. Questo può accadere dopo alcuni aggiornamenti app o Android. Ri-seleziona la cartella per recuperare le autorizzazioni in modo da poter continuare.</string>
|
||||
<string name="cannot_skip_directory_description">Questo passaggio è necessario per consentire ad Azahar di funzionare. Seleziona una cartella per poter continuare.</string>
|
||||
<string name="selecting_user_directory_without_write_permissions">Hai perso i permessi di scrittura sulla tua <a href="https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage">cartella dei dati utente</a>, dove sono memorizzati i salvataggi e altre informazioni. Questo può accadere dopo alcuni aggiornamenti app o Android. Seleziona nuovamente la cartella per ripristinare i permessi e continuare.</string>
|
||||
<string name="invalid_selection">Selezione non valida</string>
|
||||
<string name="invalid_user_directory">La selezione della directory utente non era valida.\nSeleziona nuovamente la directory utente, assicurandoti di accedervi dalla radice dello spazio di archiviazione del tuo dispositivo.</string>
|
||||
<string name="invalid_user_directory">La cartella utente selezionata non è valida.\nSelezionala di nuovo assicurandoti di partire dalla memoria principale del dispositivo.</string>
|
||||
<string name="filesystem_permission_lost">Azahar ha perso l\'autorizzazione a gestire i file su questo dispositivo. Ciò può accadere dopo alcuni aggiornamenti di app o Android. Si prega di concedere nuovamente questa autorizzazione nella schermata successiva per continuare a utilizzare l\'app.</string>
|
||||
<string name="set_up_theme_settings">Impostazioni tema</string>
|
||||
<string name="setup_theme_settings_description">Configura le impostazioni del tema di Azahar.</string>
|
||||
|
|
@ -113,9 +108,17 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="search_installed">Installati</string>
|
||||
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_auto_map">Mappatura automatica controller</string>
|
||||
<string name="controller_auto_map_description">Applica la mappatura standard per tutti i tasti e gli assi</string>
|
||||
<string name="auto_map_prompt">Premi questo tasto sul controller!</string>
|
||||
<string name="auto_map_image_description">Schema tasti 3DS con il tasto A evidenziato</string>
|
||||
<string name="controller_clear_all">Rimuovi tutte le assegnazioni</string>
|
||||
<string name="controller_clear_all_confirm">Tutte le assegnazioni attuali dei controller verranno rimosse.</string>
|
||||
<string name="controller_circlepad">Pad scorrevole</string>
|
||||
<string name="controller_c">Levetta C</string>
|
||||
<string name="controller_hotkeys">Scorciatoie</string>
|
||||
<string name="controller_hotkeys">Tasti rapidi</string>
|
||||
<string name="controller_hotkeys_description">Se il tasto \"Abilita tasti rapidi\" è assegnato, va premuto insieme al tasto rapido configurato.</string>
|
||||
<string name="controller_hotkey_enable_button">Abilita tasti rapidi</string>
|
||||
<string name="controller_triggers">Grilletti</string>
|
||||
<string name="controller_trigger">Grilletto</string>
|
||||
<string name="controller_dpad">Tasti direzionali</string>
|
||||
|
|
@ -133,6 +136,8 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="input_dialog_description">Premi o sposta un comando</string>
|
||||
<string name="input_binding">Assegnazione Input</string>
|
||||
<string name="input_binding_description">Premi o muovi un comando per assegnarlo a %1$s.</string>
|
||||
<string name="input_binding_description_vertical_axis">Premi UP sul tuo controller.</string>
|
||||
<string name="input_binding_description_horizontal_axis">Premi RIGHT sul tuo controller.</string>
|
||||
<string name="button_home">Home</string>
|
||||
<string name="button_swap">Inverti schermi</string>
|
||||
<string name="button_turbo">Turbo</string>
|
||||
|
|
@ -143,11 +148,11 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="turbo_disabled_toast">Velocità Turbo disabilitata</string>
|
||||
|
||||
<!-- System files strings -->
|
||||
<string name="setup_system_files">File di Sistema</string>
|
||||
<string name="setup_system_files">File di sistema</string>
|
||||
<string name="setup_system_files_description">Esegui operazioni sui file di sistema come installare file di sistema o avviare il Menu Home</string>
|
||||
<string name="setup_tool_connect">Connettiti a Artic Setup Tool </string>
|
||||
<string name="setup_system_files_preamble"><![CDATA[Azahar necessita di dati unici della console e file firmware provenienti da una console reale per poter utilizzare alcune delle sue funzionalità. Questi file e dati possono essere configurati con <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a>.<br>Note: <ul><li><b>Questa operazione installerà dati unici della console su Azahar, non condividere le tue cartelle utente o NAND dopo aver completato il processo di configurazione!</b></li><li>Durante il processo di configurazione, Azahar si collegherà alla console che sta eseguendo lo strumento di configurazione. Puoi scollegare la console in seguito dalla scheda \"File di sistema\" nel menu delle opzioni dell\'emulatore.</li><li>Non andare online contemporaneamente con Azahar e la tua console 3DS dopo aver configurato i file di sistema, poiché ciò potrebbe causare problemi.</li><li>La configurazione del vecchio 3DS è necessaria affinché la configurazione del nuovo 3DS funzioni (si consiglia di configurare entrambi).</li><li>Entrambe le modalità di configurazione funzioneranno indipendentemente dal modello della console che esegue lo strumento di configurazione.</li></ul>]]></string>
|
||||
<string name="setup_system_files_detect">Recupero dello stato attuale dei file di sistema, per favore attendi...</string>
|
||||
<string name="setup_system_files_detect">Recupero dello stato attuale dei file di sistema, attendere...</string>
|
||||
<string name="delete_system_files">Scollega i dati univoci della console</string>
|
||||
<string name="delete_system_files_description"><![CDATA[Questa azione scollegherà la tua console reale da Azahar, con le seguenti conseguenze:<br><ul><li>il tuo OTP, SecureInfo e LocalFriendCodeSeed verranno rimossi da Azahar.</li><li>La tua lista amici verrà reimpostata e verrai disconnesso dal tuo account NNID/PNID.</li><li>I file di sistema e i titoli eshop ottenuti tramite Azahar diventeranno inaccessibili finché la stessa console non verrà nuovamente collegata tramite lo strumento di configurazione (i dati di salvataggio non andranno persi).</li></ul><br>Continuare?]]></string>
|
||||
<string name="setup_system_files_o3ds">Setup Old 3DS</string>
|
||||
|
|
@ -213,7 +218,7 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="outer_left_camera">Fotocamera Esterna di Sinistra</string>
|
||||
<string name="outer_right_camera">Fotocamera Esterna di Destra</string>
|
||||
<string name="image_source">Sorgente Fotocamera</string>
|
||||
<string name="image_source_description">Imposta l\'immagine sorgente della fotocamera virtuale. Puoi utilizzare un file immagine, oppure la fotocamera del dispositivo quando supportato.</string>
|
||||
<string name="image_source_description">Imposta la sorgente dell\'immagine per la fotocamera virtuale. Puoi usare un file immagine o la fotocamera del dispositivo, se supportata.</string>
|
||||
<string name="camera_device">Fotocamera</string>
|
||||
<string name="camera_device_description">Se l\'impostazione \"Origine immagine\" è impostata su \"Fotocamera dispositivo\", questa imposta la fotocamera fisica da utilizzare.</string>
|
||||
<string name="camera_facing_front">Fronte</string>
|
||||
|
|
@ -232,6 +237,8 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="async_shaders_description">Compila gli shader in background per ridurre gli scatti durante il gioco. Se l\'opzione è abilitata, potrebbero verificarsi dei glitch grafici temporanei.</string>
|
||||
<string name="linear_filtering">Filtraggio lineare</string>
|
||||
<string name="linear_filtering_description">Abilita il filtraggio lineare, che fa sembrare più smussata la grafica dei giochi.</string>
|
||||
<string name="use_integer_scaling">Scalabilità intera</string>
|
||||
<string name="use_integer_scaling_description">Scala gli schermi usando un multiplo intero della risoluzione originale del 3DS. Nei layout con schermi di dimensioni diverse, la scalabilità intera viene applicata allo schermo più grande.</string>
|
||||
<string name="texture_filter_name">Filtro texture</string>
|
||||
<string name="texture_filter_description">Migliora la grafica delle applicazioni applicando un filtro alle texture. I filtri supportati sono Anime4k Ultrafast, Bicubic, ScaleForce, xBRZ freescale e MMPX.</string>
|
||||
<string name="delay_render_thread">Ritarda il thread di rendering del gioco</string>
|
||||
|
|
@ -244,13 +251,13 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="asynchronous_gpu">Abilita l\'emulazione GPU asincrona</string>
|
||||
<string name="asynchronous_gpu_description">Usa un thread separato per l\'emulazione asincrona della GPU. Quando è abilitato le prestazioni saranno migliori.</string>
|
||||
<string name="frame_limit_enable">Limita velocità</string>
|
||||
<string name="frame_limit_enable_description">Quando l\'opzione è abilitata, la velocità di emulazione sarà limitata a una percentuale specificata della velocità normale. Se è disabilitata, la velocità di emulazione non verrà limitata e la scorciatoia della velocità Turbo non funzionerà.</string>
|
||||
<string name="frame_limit_enable_description">Se attiva, la velocità di emulazione viene limitata a una percentuale specifica. Se disattivata, la velocità non avrà limiti e il tasto rapido per il turbo non funzionerà.</string>
|
||||
<string name="frame_limit_slider">Limite della velocità in percentuale</string>
|
||||
<string name="frame_limit_slider_description">Specifica a quale percentuale limitare la velocità d\'emulazione. Utilizzando l\'impostazione predefinita di 100% l\'emulazione sarà limitata alla velocità normale. Valori superiori o inferiori aumenteranno o diminuiranno il limite di velocità.</string>
|
||||
<string name="android_hide_images">Nascondi le immagini 3DS da Android</string>
|
||||
<string name="android_hide_images_description">Impedisci che le immagini della fotocamera 3DS, degli screenshot e delle texture personalizzate vengano indicizzate da Android e visualizzate nella galleria. Potrebbe essere necessario riavviare il dispositivo dopo aver modificato questa impostazione per avere effetto.</string>
|
||||
<string name="turbo_limit">Limite della velocità Turbo</string>
|
||||
<string name="turbo_limit_description">Limite di velocità dell\'emulazione usato quando la scorciatoia della velocità Turbo è attiva.</string>
|
||||
<string name="turbo_limit_description">Limite di velocità dell\'emulazione usato quando il tasto rapido della velocità Turbo è attiva.</string>
|
||||
<string name="expand_to_cutout_area">Espandi all\'area di ritaglio</string>
|
||||
<string name="expand_to_cutout_area_description">Espande l\'area di visualizzazione per includere l\'area di ritaglio (o notch).</string>
|
||||
<string name="internal_resolution">Risoluzione interna</string>
|
||||
|
|
@ -273,7 +280,7 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="render3d_description">Scegli la modalità 3D stereoscopica per il rendering 3D. Le modalità \"Affiancato\" sono le più comuni nell\'uso moderno. Le modalità \"Anaglifo\" e \"Interlacciato\" si applicheranno sempre a tutti i display collegati.</string>
|
||||
<string name="factor3d">Profondità</string>
|
||||
<string name="factor3d_description">Specifica il valore del regolatore di profondità 3D. Questo valore deve essere impostato su un valore superiore allo 0% quando è abilitato il 3D stereoscopico.\nNota: Valori di profondità superiori al 100% non sono possibili su un dispositivo reale e possono causare problemi grafici</string>
|
||||
<string name="disable_right_eye_render">Disabilita il rendering dell\'occhio destro</string>
|
||||
<string name="disable_right_eye_render">Disattiva rendering occhio destro</string>
|
||||
<string name="disable_right_eye_render_description">Migliora notevolmente le prestazioni in alcune applicazioni, ma può causare flickering in altre.</string>
|
||||
<string name="swap_eyes_3d">Inverti occhi</string>
|
||||
<string name="swap_eyes_3d_description">Cambia quale occhio viene visualizzato in quale lato. In combinazione con la modalità \"Affiancato\" è possibile vedere il 3D incrociando gli occhi!</string>
|
||||
|
|
@ -329,6 +336,8 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="deterministic_async_operations_description">Rende le operazioni asincrone deterministiche per il debug. Abilitare questa opzione potrebbe causare blocchi.</string>
|
||||
<string name="enable_rpc_server">Abilita server RPC</string>
|
||||
<string name="enable_rpc_server_desc">Abilita il server RPC sulla porta 45987. Questo permette di leggere e scrivere remotamente la memoria guest.</string>
|
||||
<string name="toggle_unique_data_console_type">Alterna tipo dati univoci console</string>
|
||||
<string name="toggle_unique_data_console_type_desc">Alterna il tipo di console (Old 3DS ↔ New 3DS) per scaricare il firmware del sistema opposto dalle impostazioni.</string>
|
||||
<string name="shader_jit">Abilita shader JIT</string>
|
||||
<string name="shader_jit_description">Usa il motore JIT al posto dell\'interprete per l\'emulazione software degli shader.</string>
|
||||
|
||||
|
|
@ -339,6 +348,8 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="layout_screen_orientation_landscape_reverse">Orizzontale rovesciato</string>
|
||||
<string name="layout_screen_orientation_portrait">Verticale</string>
|
||||
<string name="layout_screen_orientation_portrait_reverse">Verticale rovesciato</string>
|
||||
<string name="layouts_to_cycle">Layout da ciclare</string>
|
||||
<string name="layouts_to_cycle_description">Quali layout vengono alternati dal tasto rapido \"Cicla layout\"</string>
|
||||
<string name="aspect_ratio_default">Default</string>
|
||||
<string name="aspect_ratio_16_9">16:9</string>
|
||||
<string name="aspect_ratio_4_3">4:3</string>
|
||||
|
|
@ -367,14 +378,14 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="install">Installa</string>
|
||||
<string name="delete">Cancella</string>
|
||||
<string name="reset_all_settings">Reimpostare tutte le impostazioni?</string>
|
||||
<string name="reset_all_settings_description">Tutte le impostazioni avanzate verranno reimpostate alla loro configurazione predefinita. Questa operazione non può essere annullata.</string>
|
||||
<string name="reset_all_settings_description">Tutte le impostazioni avanzate verranno ripristinate ai valori predefiniti. L\'operazione non è annullabile.</string>
|
||||
<string name="settings_reset">Reimpostazione impostazioni</string>
|
||||
<string name="select_rtc_date">Seleziona data RTC</string>
|
||||
<string name="select_rtc_time">Seleziona orario RTC</string>
|
||||
<string name="reset_setting_confirmation">Vuoi reimpostare questa opzione al suo valore predefinito?</string>
|
||||
<string name="setting_not_editable">Non puoi modificare questo ora</string>
|
||||
<string name="setting_disabled">Impostazione disabilitata</string>
|
||||
<string name="setting_disabled_description">Questa impostazione è attualmente disattivata a causa di un\'altra impostazione che non è il valore appropriato.</string>
|
||||
<string name="setting_disabled_description">Questa impostazione è disattivata perché un\'altra opzione non ha il valore richiesto.</string>
|
||||
<string name="setting_not_editable_description">Questa opzione non può essere modificata mentre un gioco è in esecuzione.</string>
|
||||
<string name="auto_select">Seleziona automaticamente</string>
|
||||
<string name="start">Avvia</string>
|
||||
|
|
@ -383,7 +394,7 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="information">Informazione</string>
|
||||
|
||||
<!-- Add Directory Screen-->
|
||||
<string name="select_game_folder">Seleziona cartella dei giochi</string>
|
||||
<string name="select_game_folder">Seleziona cartella del gioco</string>
|
||||
|
||||
<!-- Game Properties -->
|
||||
<string name="properties">Proprietà</string>
|
||||
|
|
@ -498,7 +509,7 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="lock_drawer">Blocca menù laterale</string>
|
||||
<string name="unlock_drawer">Sblocca menù laterale</string>
|
||||
|
||||
<string name="write_permission_needed">L\'emulatore ha bisogno dei permessi per l\'archiviazione dei dati su memoria esterna per funzionare correttamente</string>
|
||||
<string name="write_permission_needed">Accesso alla memoria esterna richiesto per il funzionamento dell\'emulatore</string>
|
||||
<string name="load_settings">Caricando le Impostazioni...</string>
|
||||
|
||||
<string name="external_storage_not_mounted">La memoria esterna deve essere disponibile per poter utilizzare Azahar</string>
|
||||
|
|
@ -553,7 +564,7 @@ Divertiti usando l\'emulatore!</string>
|
|||
|
||||
<!-- Disk Shader Cache -->
|
||||
<string name="preparing_shaders">Preparazione degli shader</string>
|
||||
<string name="building_shaders">Compilazione degli shader</string>
|
||||
<string name="building_shaders">Compilazione %s</string>
|
||||
|
||||
<!-- About Game Dialog -->
|
||||
<string name="play">Riproduci</string>
|
||||
|
|
@ -636,7 +647,7 @@ Divertiti usando l\'emulatore!</string>
|
|||
<string name="cia_install_error_aborted">L\'installazione di \"%s\" è stata annullata.\n Consulta i log per maggiori dettagli</string>
|
||||
<string name="cia_install_error_invalid">\"%s\" non è un CIA valido</string>
|
||||
<string name="cia_install_error_encrypted">\"%s\" deve essere decriptato prima di essere usato in Azahar.\n Un 3DS reale è richiesto</string>
|
||||
<string name="cia_install_error_unknown">Errore Sconosciuto durante l\'installazione di \"%s\".\n Consulta i log per maggiori dettagli</string>
|
||||
<string name="cia_install_error_unknown">Errore sconosciuto durante l\'installazione di \"%s\".\n Consulta i log per maggiori dettagli</string>
|
||||
|
||||
<!-- Memory Sizes -->
|
||||
<string name="memory_formatted">%1$s%2$s</string>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
<!-- Home Strings -->
|
||||
<string name="grid_menu_core_settings">Innstillinger</string>
|
||||
<!-- Input related strings -->
|
||||
<string name="controller_circlepad">Gliplate</string>
|
||||
<string name="controller_c">C-Spak</string>
|
||||
<string name="controller_triggers">Utløser</string>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue