diff --git a/.github/ISSUE_TEMPLATE/01-bug-report.yml b/.github/ISSUE_TEMPLATE/01-bug-report.yml index d2f1567266..9a218c4daa 100644 --- a/.github/ISSUE_TEMPLATE/01-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/01-bug-report.yml @@ -42,7 +42,7 @@ body: attributes: label: Version/Commit description: You can find this information under Information/System Information - placeholder: 1.19.1 (Git 0792144fe3) + placeholder: 1.20.0 (Git ab3b175) validations: required: true @@ -56,8 +56,8 @@ body: - type: dropdown id: nigthly attributes: - label: Check in the nightly version - description: This issue is reproducible with [nightly builds](https://buildbot.libretro.com/nightly/)? + label: Present in the nightly version + description: Is the issue reproducible with current [nightly builds](https://buildbot.libretro.com/nightly/)? options: - I don't know - Yes, this is reproduced in the nightly build diff --git a/.github/workflows/Android.yml b/.github/workflows/Android.yml index da68bb12d8..dbb0d7ee67 100644 --- a/.github/workflows/Android.yml +++ b/.github/workflows/Android.yml @@ -30,7 +30,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: retroarch-android-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/DOS-DJGPP.yml b/.github/workflows/DOS-DJGPP.yml index d144a2f108..6f5595ce05 100644 --- a/.github/workflows/DOS-DJGPP.yml +++ b/.github/workflows/DOS-DJGPP.yml @@ -31,7 +31,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-DOS-dummy-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/MSYS2.yml b/.github/workflows/MSYS2.yml new file mode 100644 index 0000000000..3d0bb30415 --- /dev/null +++ b/.github/workflows/MSYS2.yml @@ -0,0 +1,77 @@ +name: CI Windows (MSYS2) + +on: + push: + pull_request: + repository_dispatch: + types: [run_build] + +permissions: + contents: read + +jobs: + msys2-build-test: + strategy: + fail-fast: false + matrix: + sys: [MINGW64, UCRT64,CLANG64] + runs-on: windows-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.sys }} + update: true + install: base-devel git + pacboy: >- + gettext:p + gobject-introspection:p + graphite2:p + p11-kit:p + qt6:p + qt6-3d:p + qt6-charts:p + qt6-datavis3d:p + qt6-imageformats:p + qt6-location:p + qt6-lottie:p + qt6-networkauth:p + qt6-quick3dphysics:p + qt6-quicktimeline:p + qt6-remoteobjects:p + qt6-scxml:p + qt6-sensors:p + qt6-serialbus:p + qt6-speech:p + qt6-tools:p + qt6-translations:p + qt6-virtualkeyboard:p + qt6-webchannel:p + qt6-websockets:p + x264:p + cc:p + + - name: Configure and build RetroArch + shell: msys2 {0} + run: | + echo "Building RetroArch in ${{ matrix.sys }} environment" + ./configure + make -j$(nproc) + + - name: Collect DLLs and binaries + shell: msys2 {0} + run: | + echo "Collecting DLLs and binaries" + mkdir -p dist + cp retroarch.exe dist/ + ldd retroarch.exe|grep $MINGW_PREFIX |awk '{print $3}'|xargs -I {} cp {} dist/ + + - name: Archive build artifacts + if: success() + uses: actions/upload-artifact@v4 + with: + name: retroarch-${{ matrix.sys }} + path: dist/ diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index 37e6026ee7..10ab355ec3 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -26,7 +26,7 @@ jobs: id: slug run: echo "sha8=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_OUTPUT - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RetroArch-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/Miyoo.yml b/.github/workflows/Miyoo.yml index 2a7556ba1a..de6018a50a 100644 --- a/.github/workflows/Miyoo.yml +++ b/.github/workflows/Miyoo.yml @@ -31,7 +31,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: retroarch_miyoo_arm32${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/PS2.yml b/.github/workflows/PS2.yml index eba2153e8a..4e60d718f0 100644 --- a/.github/workflows/PS2.yml +++ b/.github/workflows/PS2.yml @@ -36,7 +36,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-PS2-dummy-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/PS3-PSL1GHT.yml b/.github/workflows/PS3-PSL1GHT.yml new file mode 100644 index 0000000000..f98b459454 --- /dev/null +++ b/.github/workflows/PS3-PSL1GHT.yml @@ -0,0 +1,44 @@ +name: CI PS3/PSL1GHT + +on: + push: + pull_request: + repository_dispatch: + types: [run_build] + +permissions: + contents: read + +env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + +jobs: + build: + runs-on: ubuntu-latest + container: + image: git.libretro.com:5050/libretro-infrastructure/libretro-build-psl1ght:latest + options: --user root + + steps: + - uses: actions/checkout@v3 + + - name: Compile Salamander + run: | + make -f Makefile.psl1ght.salamander -j$(getconf _NPROCESSORS_ONLN) clean + make -f Makefile.psl1ght.salamander -j$(getconf _NPROCESSORS_ONLN) + + - name: Compile RA + run: | + make -f Makefile.psl1ght -j$(getconf _NPROCESSORS_ONLN) clean + make -f Makefile.psl1ght -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 + + - name: Get short SHA + id: slug + run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" + + - uses: actions/upload-artifact@v4 + with: + name: RA-psl1ght-dummy-${{ steps.slug.outputs.sha8 }} + path: | + retroarch_psl1ght_salamander.elf + retroarch_psl1ght.elf diff --git a/.github/workflows/PS4-ORBIS.yml b/.github/workflows/PS4-ORBIS.yml index 60773e9bc0..2296eed6d0 100644 --- a/.github/workflows/PS4-ORBIS.yml +++ b/.github/workflows/PS4-ORBIS.yml @@ -37,7 +37,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: bin-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/PSP.yml b/.github/workflows/PSP.yml index d1b3a9b06a..2ae652d0d6 100644 --- a/.github/workflows/PSP.yml +++ b/.github/workflows/PSP.yml @@ -42,7 +42,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-PSP-dummy-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/PSVita.yml b/.github/workflows/PSVita.yml index 9be7c3dbfe..87e5933e9e 100644 --- a/.github/workflows/PSVita.yml +++ b/.github/workflows/PSVita.yml @@ -35,7 +35,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-PSVita-dummy-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/RS90.yml b/.github/workflows/RS90.yml index 1fea310bdf..34332c5ce0 100644 --- a/.github/workflows/RS90.yml +++ b/.github/workflows/RS90.yml @@ -31,7 +31,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: retroarch_rs90_mips32${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/RetroFW.yml b/.github/workflows/RetroFW.yml index 24ec76f2ba..cb57960e1d 100644 --- a/.github/workflows/RetroFW.yml +++ b/.github/workflows/RetroFW.yml @@ -31,7 +31,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: retroarch_retrofw_mips32${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/Switch-libnx.yml b/.github/workflows/Switch-libnx.yml index 75a25054f8..df26e01f19 100644 --- a/.github/workflows/Switch-libnx.yml +++ b/.github/workflows/Switch-libnx.yml @@ -30,7 +30,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-libnx-dummy-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/WiiU.yml b/.github/workflows/WiiU.yml index 2b2bd74c6f..2a53051107 100644 --- a/.github/workflows/WiiU.yml +++ b/.github/workflows/WiiU.yml @@ -25,12 +25,12 @@ jobs: - name: Compile Salamander run: | make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) SALAMANDER_BUILD=1 clean - make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) SALAMANDER_BUILD=1 V=1 + make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) SALAMANDER_BUILD=1 - name: Compile RA run: | make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) clean - make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 V=1 + make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 - name: Get short SHA id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" diff --git a/.gitignore b/.gitignore index d3470d8fa6..a29b8ebd83 100644 --- a/.gitignore +++ b/.gitignore @@ -196,6 +196,8 @@ retroarch.js retroarch.js.mem *.bc *.wasm +*.wasm.map +obj-emscripten/ # only ignore .js files in the repo root /*.js diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 008b804c4f..dc90946426 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -331,7 +331,7 @@ build-retroarch-linux-i686: .build-retroarch-macos-xcode: # Metal/Universal x86_64 arm64 is default tags: - - macosx-packaging + - mac-apple-silicon stage: build variables: XCARCHIVE_PATH: pkg/apple/build/RetroArchUniversal @@ -358,6 +358,8 @@ build-retroarch-osx-universal-metal: build-retroarch-osx-opengl-x64: extends: .build-retroarch-macos-xcode + tags: + - macosx-packaging variables: XCARCHIVE_PATH: pkg/apple/build/RetroArchOpenGL XCPROJECT_NAME: RetroArch @@ -388,8 +390,6 @@ build-retroarch-osx-opengl-x64: build-retroarch-ios-arm64: extends: .build-retroarch-macos-xcode - tags: - - mac-apple-silicon variables: XCPROJECT_NAME: RetroArch_iOS13 XCCONFIG: GitLabCI.xcconfig @@ -408,6 +408,8 @@ build-retroarch-ios-arm64: build-retroarch-ios9: extends: .build-retroarch-macos-xcode + tags: + - macosx-packaging variables: XCPROJECT_NAME: RetroArch_iOS9 XCCONFIG: GitLabCI.xcconfig diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index b68a4af620..0000000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,191 +0,0 @@ -{ - "configurations": [ - { - "name": "Mac", - "includePath": [ - "/usr/include", - "/usr/local/include", - "${workspaceRoot}", - "${workspaceRoot}/libretro-common/include" - ], - "defines": [], - "intelliSenseMode": "clang-x64", - "browse": { - "path": [ - "/usr/include", - "/usr/local/include", - "${workspaceRoot}" - ], - "limitSymbolsToIncludedHeaders": true, - "databaseFilename": "" - }, - "macFrameworkPath": [ - "/System/Library/Frameworks", - "/Library/Frameworks" - ] - }, - { - "name": "Linux", - "includePath": [ - "/usr/include", - "/usr/local/include", - "${workspaceRoot}", - "${workspaceFolder}/libretro-common/include", - "${workspaceRoot}/libretro-common/include" - ], - "defines": [], - "intelliSenseMode": "clang-x64", - "browse": { - "path": [ - "/usr/include", - "/usr/local/include", - "${workspaceRoot}" - ], - "limitSymbolsToIncludedHeaders": true, - "databaseFilename": "" - } - }, - { - "name": "Win32", - "includePath": [ - "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/um", - "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt", - "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared", - "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt", - "${workspaceRoot}", - "${workspaceFolder}/libretro-common/include" - ], - "defines": [ - "_DEBUG", - "UNICODE" - ], - "intelliSenseMode": "msvc-x64", - "browse": { - "path": [ - "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/um", - "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt", - "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared", - "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt", - "${workspaceRoot}" - ], - "limitSymbolsToIncludedHeaders": true, - "databaseFilename": "" - }, - "cStandard": "c11", - "cppStandard": "c++17", - "configurationProvider": "ms-vscode.makefile-tools" - }, - { - "name": "msys2-mingw32", - "includePath": [ - "C:/msys64/mingw32/include", - "C:/msys64/mingw32/i686-w64-mingw32/include", - "${workspaceRoot}/libretro-common/include", - "${workspaceRoot}/include", - "${workspaceRoot}" - ], - "defines": [ - "_DEBUG", - "UNICODE" - ], - "intelliSenseMode": "msvc-x64", - "browse": { - "path": [ - "C:/msys64/mingw32/include", - "C:/msys64/mingw32/i686-w64-mingw32/include", - "${workspaceRoot}/libretro-common/include", - "${workspaceRoot}/include", - "${workspaceRoot}" - ], - "limitSymbolsToIncludedHeaders": true, - "databaseFilename": "" - } - }, - { - "name": "msys2-mingw64", - "includePath": [ - "C:/msys64/mingw64/include", - "C:/msys64/mingw64/x86_64-w64-mingw32/include", - "${workspaceRoot}/libretro-common/include", - "${workspaceRoot}/include", - "${workspaceRoot}" - ], - "defines": [ - "_DEBUG", - "UNICODE" - ], - "intelliSenseMode": "msvc-x64", - "browse": { - "path": [ - "C:/msys64/mingw64/include", - "C:/msys64/mingw64/x86_64-w64-mingw32/include", - "${workspaceRoot}/libretro-common/include", - "${workspaceRoot}/include", - "${workspaceRoot}" - ], - "limitSymbolsToIncludedHeaders": true, - "databaseFilename": "" - } - }, - { - "name": "Switch", - "includePath": [ - "/opt/devkitpro/devkitA64/aarch64-none-elf/include", - "/opt/devkitpro/devkitA64/lib/gcc/aarch64-none-elf/8.3.0/include", - "/opt/devkitpro/libnx/include", - "/opt/devkitpro/portlibs/switch/include", - "/opt/devkitpro/portlibs/switch/include/freetype2", - "${workspaceFolder}/**" - ], - "defines": [ - "_DEBUG", - "UNICODE", - "_UNICODE", - "__aarch64__", - "__SWITCH__", - "HAVE_LIBNX" - ], - "windowsSdkVersion": "10.0.17763.0", - "compilerPath": "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc", - "cStandard": "c11", - "cppStandard": "c++11", - "intelliSenseMode": "gcc-x64" - }, - { - "name": "WiiU", - "includePath": [ - "/opt/devkitpro/devkitPPC/powerpc-eabi/include", - "/opt/devkitpro/devkitPPC/lib/gcc/powerpc-eabi/6.3.0/include", - "/opt/devkitpro/portlibs/ppc/include", - "${workspaceFolder}/**" - ], - "defines": [ - "WIIU", - "WIIU_HID" - ], - "windowsSdkVersion": "10.0.17763.0", - "compilerPath": "/opt/devkitpro/devkitPPC/bin/powerpc-eabi-gcc", - "cStandard": "c11", - "cppStandard": "c++11", - "intelliSenseMode": "gcc-x64" - }, - { - "name": "ps2sdk-ee", - "includePath": [ - "${env:PS2DEV}/ps2sdk/common/include", - "${env:PS2DEV}/ps2sdk/ee/include", - "${env:PS2DEV}/gsKit/include", - "${workspaceFolder}/**" - ], - "defines": [ - "PS2", - "_EE" - ], - "compilerPath": "${env:PS2DEV}/ee/bin/mips64r5900el-ps2-elf-gcc", - "cStandard": "c11", - "cppStandard": "c++11", - "intelliSenseMode": "gcc-x64" - } - ], - "version": 4 -} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 28f4114a39..0000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "(gdb) Launch", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/retroarch.exe", - "args": ["-v"], - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": true, - "MIMode": "gdb", - "miDebuggerPath": "c:\\msys64\\mingw64\\bin\\gdb.exe", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] - }, - { - "name": "(gdb) Attach", - "type": "cppdbg", - "request": "attach", - "program": "${workspaceFolder}/retroarch.exe", - "processId": "${command:pickProcess}", - "MIMode": "gdb", - "miDebuggerPath": "c:\\msys64\\mingw64\\bin\\gdb.exe", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] - }, - { - "name": "PSP-GDB Debugger", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/retroarchpsp.elf", - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "setupCommands": [ - { - "text": "symbol-file ${workspaceFolder}/retroarchpsp.elf", - "description": "read symbols for elf file", - "ignoreFailures": true - }, - { - "description": "Enable all-exceptions", - "text": "-exec \"catch throw\"", - "ignoreFailures": true - } - ], - "showDisplayString": true, - "targetArchitecture": "mips", - "MIMode": "gdb", - "miDebuggerPath": "/usr/local/pspdev/bin/psp-gdb", - "miDebuggerServerAddress": "127.0.0.1:10001", - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 4a0e9d8e42..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - /*"terminal.integrated.shell.windows": "C:\\msys64\\usr\\bin\\bash.exe", - "terminal.integrated.env.windows": { - "PATH": "/mingw64/lib/ccache/bin:/mingw64/lib/ccache/bin:/mingw64/lib/ccache/bin:/mingw64/bin:/usr/local/bin:/usr/bin:/bin:$PATH", - "MSYSTEM": "MINGW64", - },*/ - "terminal.integrated.cursorBlinking": true, - "editor.tabSize": 3, - "editor.detectIndentation": false, - "editor.renderWhitespace": "all", - "editor.insertSpaces": true, - "editor.formatOnSave": false, - "editor.ruler": [80], - "files.associations": { - "*.h": "c", - "*.in": "c", - "*.rh": "c", - "array": "c", - "iosfwd": "c", - "xlocbuf": "c", - "xmemory0": "c", - "ios": "c", - "list": "c", - "unordered_map": "c", - "unordered_set": "c", - "sstream": "cpp", - "hash_map": "c", - "hash_set": "c", - "initializer_list": "c", - "string_view": "c", - "utility": "c", - "thread": "c", - "xlocale": "c", - "deque": "c", - "vector": "c", - "xhash": "c", - "xiosbase": "c", - "xstring": "c", - "xtree": "c", - "xutility": "c" - }, - "C_Cpp.dimInactiveRegions": false, -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index e34d4bc668..0000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "linux clean build", - "type": "shell", - "group": "build", - "command": "make clean && ./configure && make -j12" - }, - { - "label": "linux clean", - "type": "shell", - "group": "build", - "command": "make clean" - }, - { - "label": "linux build with debug symbols", - "type": "shell", - "group": "build", - "command": "DEBUG=1 make -j12" - }, - { - "label": "linux build", - "type": "shell", - "group": "build", - "command": "make -j12" - }, - { - "label": "linux build and run", - "type": "shell", - "group": "build", - "command": "make -j12 && ./retroarch -v" - }, - { - "label": "linux build and run with debug symbols", - "type": "shell", - "group": "build", - "command": "DEBUG=1 make -j12 && ./retroarch -v" - }, - { - "label": "msys2-mingw64 build", - "type": "shell", - - "group": { - "kind": "build", - "isDefault": true - }, - - "command": "./configure; make -j2", - "options": { - "shell": { - "executable": "C:\\msys64\\usr\\bin\\bash.exe", - "args": [ - "-c" - ] - } - } - }, - { - "label": "msys2-mingw64 build with debug symbols", - "type": "shell", - - "group": "build", - - "command": "./configure; DEBUG=1 make -j2", - "options": { - "shell": { - "executable": "C:\\msys64\\usr\\bin\\bash.exe", - "args": [ - "-c" - ] - } - } - }, - { - "label": "msys2-mingw64 rebuild", - "type": "shell", - - "group": "build", - - "command": "make -j2", - "options": { - "shell": { - "executable": "C:\\msys64\\usr\\bin\\bash.exe", - "args": [ - "-c" - ] - } - } - }, - { - "label": "msys2-mingw64 clean", - "type": "shell", - - "group": "build", - - "command": "make clean", - "options": { - "shell": { - "executable": "C:\\msys64\\usr\\bin\\bash.exe", - "args": [ - "-c" - ] - } - } - }, - { - "label": "msys2-mingw64 run", - "type": "shell", - - "group": { - "kind": "test", - "isDefault": true }, - - "command": "./retroarch -v", - "options": { - "shell": { - "executable": "C:\\msys64\\usr\\bin\\bash.exe", - "args": [ - "-c" - ] - } - } - } - ] -} \ No newline at end of file diff --git a/AUTHORS.h b/AUTHORS.h index 0987b0a242..4bd15142d3 100644 --- a/AUTHORS.h +++ b/AUTHORS.h @@ -315,7 +315,7 @@ Mike Swanson (chungy) mikeOSX minucce misson20000 -Mohmoud (esoptron) (Hedonium) +esoptron Monroe88 Morgane (MorganeAD) mprobinson diff --git a/CHANGES.md b/CHANGES.md index 8d54800a69..a9ad792ab4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,126 @@ # Future +# 1.21.0 +- 3DS: Fix unique IDs for newer cores +- 3DS: Enable TLS (SSL) +- 3DS: Fix UI freeze when threaded rendering is enabled +- 3DS: Fix crash on load content +- 3DS: Other minor fixes +- APPLE: Enable Vulkan emulated mailbox +- APPLE: Include b2 core in App Store builds +- APPLE: CoreMIDI driver for IOS/MacOS +- APPLE: CoreLocation driver for IOS/MacOS +- AUTOCONF: Enable alternative display name in autoconfig files +- AUTOCONF: Make autoconfig failure messages optional +- AUDIO: Option to mute on rewind +- AUDIO/PIPEWIRE: Fix app launch when pipewire service is stopped +- AUDIO/PIPEWIRE: Fix speedup with threaded video mode +- AUDIO/PIPEWIRE: Fix latency setting and microphone handling +- AUDIO/PIPEWIRE: Pass the new rate to the audio driver +- CAMERA: Add PipeWire camera driver +- CAMERA: Add ffmpeg camera driver +- CHEAT: Rewrite part of cheat_manager_load_cb_second_pass() +- CHEEVOS: Include achievement state in netplay states +- CHEEVOS: Fix crash when entering achievements in quick menu while client is not present +- CHEEVOS: Restore cheevos_badges_enable for HAVE_GFX_WIDGETS builds +- CLI: Allow --entryslot to fall back to normal states +- CLOUDSYNC: Fix Windows path issues +- CLOUDSYNC: Workaround for duplicated requests bug +- CLOUDSYNC: Workaround for 301 redirects +- CLOUDSYNC: Handle ignored directories properly +- EMSCRIPTEN: Added new AudioWorklet driver, a fast callback-based audio driver +- EMSCRIPTEN: Scale window to correct size +- EMSCRIPTEN: Additional platform functions +- EMSCRIPTEN: Add new default video context driver: emscriptenwebgl_ctx +- EMSCRIPTEN: Add new audio driver: AudioWorklet +- EMSCRIPTEN: Add new modernized web player which will eventually replace the existing one +- EMSCRIPTEN/RWEBINPUT: Add touch input support +- GAMECUBE: Fixes +- GENERAL: Fix save state auto increment +- GENERAL: Fix softpatching with periods/dots in the file name +- GENERAL: Fix compilation with --enable-videocore +- GENERAL: Allow asset directory redefinition and other directory overrides via environment variables +- GENERAL: Allow override of player 1/2 input with machine learning models (needs recompilation and external library) +- GENERAL: Fix performance counter option not remembered between sessions +- GENERAL: Create security statement +- GENERAL: Fix crash when core is not selected +- GENERAL: Use core fps instead of screen refresh for calculating dropped frames +- INPUT: Fix a crash when initializing illuminance sensor on Linux +- INPUT: Analog-to-digital refactor, fixing behavior when analogs are assigned to keys +- INPUT: Turbo fire overhaul. See https://github.com/libretro/RetroArch/pull/17633 +- INPUT/ANDROID: Fix game focus and pause handling +- INPUT/COCOA: Include gravity in acceleration sensor values +- INPUT/COCOA: Fix relative mouse input +- INPUT/COCOA: Allow mouse input while mouse overlay is active +- INPUT/WINRAW: Invert mouse index order +- IOS: Ensure webserver notice can be dismissed +- IOS: Fix rescanning manual playlists after app update +- IOS: Fix clean playlist function +- IOS: Fix crash when scanning +- IOS: Fix jump back to selected item when closing content +- IOS: Fix shared GL context setup +- IOS: Update Launch Screen +- IOS: Screen orientation lock through display server +- IOS: Fix rescanning manual playlists after app update +- LAKKA: Remove bluetooth device after disconnection +- LINUX/X11: Extend X11 input driver with XInput2 extensions for multi-mouse +- MACOS: Fix some sandbox handling in App Store builds +- MACOS: Reset keyboard state when focus is lost +- MENU: Add SSL support to the information list +- MENU: Add warning to BFI and related menu items +- MENU: Fix latency statistics when using runahead +- MENU: Fix opening file inside archive with core selection +- MENU: Main menu unified between different menu drivers +- MENU: Visibility toggle for playlist tabs +- MENU: Color the notification icon by message category +- MENU: Gray Dark+Light theme adjustments +- MENU/GLUI: Menu back button switches tabs like in other menu drivers +- MENU/GLUI: Tab selection option is honored +- MENU/GLUI: Fix CD icon appearing when no icon is specified +- MENU/GLUI: Allow fullscreen thumbnail browsing +- MENU/GLUI: Save state thumbnails +- MENU/PLAYLISTS: Random selection/shuffle function +- MENU/QT: Fix desktop menu crash with Cheevos disabled +- MENU/RGUI: Cleanups of certain menu items +- MENU/RGUI: Thumbnail fixes +- MENU/OZONE: Fix messagebox background +- MENU/XMB: Fix Light theme, font shadow +- MENU/XMB: Appearance menu cleanup +- MENU/XMB: Icon thumbnail can be any of the existing types +- MISC: Guard nanosleep prototype behind _POSIX_TIMERS +- MISC: Use fabsf and intended threshold for refresh rate check +- MISC: Use platform-specific checks for invalid descriptors +- MIDI: Add dropdown items for midi device selection +- NETWORK: Refactor of net_http, improvements for task blocking and performance +- NETWORK: Follow http redirects in net_http +- NETWORK: Expire failed DNS lookups much faster +- NETWORK: Fix netplay when using netpacket interface with recent cheevos +- NETWORK/HTTP: Fix crash in net_http_resolve() in single-thread mode +- OVERLAY: Fix overlay lightgun, mouse & pointer +- OVERLAY: Preferred overlay loading is now default only on mobile platforms +- OVERLAY: Improve analog recentering when touching the area just outside the recentering zone +- QT: Enable non-png thumbnails also for Qt interface +- REPLAY: Fix issue when replaying old format input recordings in newer RetroArch +- TTS: Fix initial text-to-speech on Windows +- TVOS: Fix 720p display +- TVOS: Fix refresh rate fetching on tvOS 13/14 +- TVOS: Update Top Shelf art +- SAVESTATES: Reset state index when loading new content +- UWP: Fix slang shader compilation +- VIDEO: Enable BFI setting for mobile platforms (mind the warnings) +- VIDEO/OpenGLES: Fix FP/sRGB FBO support +- VIDEO/SHADERS: Allow exact refresh rate sync with shader subframes +- VIDEO/SHADERS: FIX shader wildcards +- VIDEO/VULKAN: Enable adaptive vsync +- VIDEO/V4L2: Added resolution picker/forcing. +- VIDEO/V4L2: Rewrote logic for finding ALSA audio devices in enumerate_audio_devices function +- VIDEO/V4L2: Added a skip for some of the interface queries that fail and aren't required for magewell usb. +- VITA: Fixes +- WINDOWS: Win32 socket improvements +- WII: Fixes +- WIIU: Fixes +- WEBPLAYER: Update core list for 1.20.0 + # 1.20.0 - AUDIO: Fix audio handling in case of RARCH_NETPLAY_CTL_USE_CORE_PACKET_INTERFACE - AUDIO: Include missing audio filters on some platforms @@ -46,7 +167,7 @@ - INPUT/UDEV: Enable mouse buttons 4 and 5 - INPUT/WAYLAND: Enable horizontal scroll and mouse buttons 4 and 5 - INPUT/WAYLAND: Simulate lightgun input for cores -- INPUT/WAYLAND: Support for cursor-shape-v1 and content-type-v1 protocol +- INPUT/WAYLAND: Support for cursor-shape-v1 protocol - INPUT/X11: Enable mouse buttons 4 and 5 - iOS: Enable vibration by default - iOS: Better handling of physical mice/magic keyboard trackpad @@ -114,6 +235,7 @@ - VIDEO/VULKAN: Fix Vulkan window freezes when swapchain becomes suboptimal - VIDEO/VULKAN: Prefer IMMEDIATE mode without vsync - VIDEO/X11: Support inhibit of Xss screensaver +- VIDEO/WAYLAND: Support for content-type-v1 protocol - VITA: Enable analog L2/R2 triggers when a DS3 controller is used with PS Vita - WAYLAND: Fix segfault when relative pointer is not supported - WAYLAND: Use reverse DNS name for desktop file and icon diff --git a/Makefile b/Makefile index 8f162a436c..ca736ddab3 100644 --- a/Makefile +++ b/Makefile @@ -171,7 +171,34 @@ ifneq ($(MOC_HEADERS),) RARCH_OBJ += $(MOC_OBJ) endif -all: $(TARGET) config.mk +all: info $(TARGET) config.mk + +define INFO +ASFLAGS: $(ASFLAGS) +CC: $(CC) +CFLAGS: $(CFLAGS) +CPPFLAGS: $(CPPFLAGS) +CXX: $(CXX) +CXXFLAGS: $(CXXFLAGS) +DEFINES: $(DEFINES) +LDFLAGS: $(LDFLAGS) +LIBRARY_DIRS: $(LIBRARY_DIRS) +LIBS: $(LIBS) +LINK: $(LINK) +MD: $(MD) +MOC: $(MOC) +MOC_TMP: $(MOC_TMP) +OBJCFLAGS: $(OBJCFLAGS) +QT_VERSION: $(QT_VERSION) +RARCH_OBJ: $(RARCH_OBJ) +WINDRES: $(WINDRES) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif $(MOC_SRC): @$(if $(Q), $(shell echo echo MOC $<),) @@ -285,9 +312,10 @@ uninstall: rm -rf $(DESTDIR)$(ASSETS_DIR) clean: - rm -rf $(OBJDIR_BASE) - rm -f $(TARGET) - rm -f *.d + @$(if $(Q), echo $@,) + $(Q)rm -rf $(OBJDIR_BASE) + $(Q)rm -f $(TARGET) + $(Q)rm -f *.d .PHONY: all install uninstall clean diff --git a/Makefile.common b/Makefile.common index 01bae782ee..c9ed198348 100644 --- a/Makefile.common +++ b/Makefile.common @@ -790,6 +790,9 @@ ifeq ($(HAVE_EMSCRIPTEN), 1) ifeq ($(HAVE_RWEBAUDIO), 1) OBJ += audio/drivers/rwebaudio.o endif + ifeq ($(HAVE_AUDIOWORKLET), 1) + OBJ += audio/drivers/audioworklet.o + endif endif ifeq ($(HAVE_BLUETOOTH), 1) @@ -929,6 +932,10 @@ ifeq ($(HAVE_PIPEWIRE), 1) OBJ += audio/drivers_microphone/pipewire.o endif + ifeq ($(HAVE_PIPEWIRE_STABLE), 1) + OBJ += camera/drivers/pipewire.o + endif + LIBS += $(PIPEWIRE_LIBS) DEF_FLAGS += $(PIPEWIRE_CFLAGS) endif @@ -978,6 +985,12 @@ ifeq ($(HAVE_WINMM), 1) LIBS += -lwinmm endif +ifeq ($(HAVE_COREMIDI), 1) + OBJ += midi/drivers/coremidi.o + DEFINES += -DHAVE_COREMIDI + LIBS += -framework CoreMIDI +endif + # Audio Resamplers ifeq ($(HAVE_NEON),1) @@ -1337,6 +1350,10 @@ ifeq ($(HAVE_X11), 1) ifeq ($(HAVE_XCB),1) LIBS += -lX11-xcb endif + ifeq ($(HAVE_XI2),1) + LIBS += -lXi + DEFINES += -DHAVE_XI2 + endif ifeq ($(HAVE_XSCRNSAVER),1) LIBS += -lXss endif @@ -1494,6 +1511,7 @@ ifeq ($(HAVE_PLAIN_DRM), 1) INCLUDE_DIRS += -I/usr/include/libdrm endif LIBS += -ldrm + HAVE_AND_WILL_USE_DRM = 1 endif ifeq ($(HAVE_VITAGL), 1) @@ -1526,7 +1544,10 @@ ifeq ($(HAVE_GL_CONTEXT), 1) endif ifeq ($(HAVE_EMSCRIPTEN), 1) - OBJ += gfx/drivers_context/emscriptenegl_ctx.o + ifeq ($(HAVE_EGL), 1) + OBJ += gfx/drivers_context/emscriptenegl_ctx.o + endif + OBJ += gfx/drivers_context/emscriptenwebgl_ctx.o endif ifeq ($(HAVE_MALI_FBDEV), 1) @@ -1570,10 +1591,11 @@ ifeq ($(HAVE_GL_CONTEXT), 1) DEF_FLAGS += $(OPENGLES_CFLAGS) ifeq ($(HAVE_OPENGLES3), 1) DEFINES += -DHAVE_OPENGLES3 + OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_es3.o else DEFINES += -DHAVE_OPENGLES2 + OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_es2.o endif - OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_es2.o else DEFINES += -DHAVE_GL_SYNC OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_gl.o @@ -1990,6 +2012,7 @@ ifeq ($(HAVE_BUILTINZLIB), 1) HAVE_ZLIB_COMMON = 1 OBJ += $(DEPS_DIR)/libz/adler32.o \ $(DEPS_DIR)/libz/libz-crc32.o \ + $(DEPS_DIR)/libz/compress.o \ $(DEPS_DIR)/libz/deflate.o \ $(DEPS_DIR)/libz/gzclose.o \ $(DEPS_DIR)/libz/gzlib.o \ @@ -1999,6 +2022,7 @@ ifeq ($(HAVE_BUILTINZLIB), 1) $(DEPS_DIR)/libz/inflate.o \ $(DEPS_DIR)/libz/inftrees.o \ $(DEPS_DIR)/libz/trees.o \ + $(DEPS_DIR)/libz/uncompr.o \ $(DEPS_DIR)/libz/zutil.o INCLUDE_DIRS += -I$(LIBRETRO_COMM_DIR)/include/compat/zlib else ifeq ($(HAVE_ZLIB),1) @@ -2168,6 +2192,65 @@ ifeq ($(HAVE_V4L2),1) LIBS += $(V4L2_LIBS) endif +# FFmpeg + +ifeq ($(HAVE_FFMPEG), 1) + DEFINES += -DHAVE_FFMPEG + INCLUDE_DIRS += -Iffmpeg + DEF_FLAGS += $(FFMPEG_CFLAGS) -Wno-deprecated-declarations + LIBS += $(FFMPEG_LIBS) + + ifeq ($(HAVE_AVCODEC), 1) + DEFINES += -DHAVE_AVCODEC + DEF_FLAGS += $(AVCODEC_CFLAGS) + LIBS += $(AVCODEC_LIBS) + endif + + ifeq ($(HAVE_AVDEVICE), 1) + DEFINES += -DHAVE_AVDEVICE + DEF_FLAGS += $(AVDEVICE_CFLAGS) + LIBS += $(AVDEVICE_LIBS) + endif + + ifeq ($(HAVE_AVFORMAT), 1) + DEFINES += -DHAVE_AVFORMAT + DEF_FLAGS += $(AVFORMAT_CFLAGS) + LIBS += $(AVFORMAT_LIBS) + endif + + ifeq ($(HAVE_AVUTIL), 1) + DEFINES += -DHAVE_AVUTIL + DEF_FLAGS += $(AVUTIL_CFLAGS) + LIBS += $(AVUTIL_LIBS) + endif + + ifeq ($(HAVE_SWSCALE), 1) + DEFINES += -DHAVE_SWSCALE + DEF_FLAGS += $(SWSCALE_CFLAGS) + LIBS += $(SWSCALE_LIBS) + endif + + ifeq ($(HAVE_SWRESAMPLE), 1) + DEFINES += -DHAVE_SWRESAMPLE + DEF_FLAGS += $(SWRESAMPLE_CFLAGS) + LIBS += $(SWRESAMPLE_LIBS) + endif +endif + +ifeq ($(HAVE_FFMPEG), 1) +ifeq ($(HAVE_AVFORMAT), 1) +ifeq ($(HAVE_AVDEVICE), 1) +ifeq ($(HAVE_AVCODEC), 1) +ifeq ($(HAVE_AVUTIL), 1) +ifeq ($(HAVE_SWSCALE), 1) + OBJ += camera/drivers/ffmpeg.o +endif +endif +endif +endif +endif +endif + # Accessibility ifeq ($(HAVE_ACCESSIBILITY), 1) DEFINES += -DHAVE_ACCESSIBILITY @@ -2192,11 +2275,16 @@ ifeq ($(HAVE_NETWORKING), 1) $(LIBRETRO_COMM_DIR)/net/net_socket.o \ core_updater_list.o \ network/natt.o \ - tasks/task_http.o \ tasks/task_netplay_lan_scan.o \ tasks/task_netplay_nat_traversal.o \ tasks/task_netplay_find_content.o + ifeq ($(HAVE_EMSCRIPTEN), 1) + OBJ += tasks/task_http_emscripten.o + else + OBJ += tasks/task_http.o + endif + ifeq ($(HAVE_MENU), 1) OBJ += tasks/task_pl_thumbnail_download.o endif @@ -2403,7 +2491,7 @@ ifeq ($(HAVE_FFMPEG), 1) cores/libretro-ffmpeg/video_buffer.o \ $(LIBRETRO_COMM_DIR)/rthreads/tpool.o - LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(SWRESAMPLE_LIBS) $(FFMPEG_LIBS) + LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(SWRESAMPLE_LIBS) $(FFMPEG_LIBS) $(AVDEVICE_LIBS) DEFINES += -DHAVE_FFMPEG DEF_FLAGS += $(AVCODEC_CFLAGS) $(AVFORMAT_CFLAGS) $(AVUTIL_CFLAGS) $(SWSCALE_CFLAGS) $(SWRESAMPLE_CFLAGS) \ -Wno-deprecated-declarations @@ -2648,4 +2736,36 @@ ifeq ($(HAVE_ODROIDGO2), 1) gfx/drivers/oga_gfx.o endif +ifeq ($(HAVE_GAME_AI),1) + DEFINES += -DHAVE_GAME_AI + OBJ += ai/game_ai.o +endif + +# Detect the operating system +UNAME := $(shell uname -s) + +# Check if the system is MSYS2 (MINGW64 or MINGW32) +ifneq ($(findstring MINGW,$(UNAME)),) +$(info Detected MSYS2 environment) + +NT_VERSION := $(shell \ + echo '#include ' > temp.c; \ + echo '#ifdef _WIN32_WINNT' >> temp.c; \ + echo '#define GET_MACRO_VALUE(x) #x' >> temp.c; \ + echo '#define EXPAND_MACRO_VALUE(x) GET_MACRO_VALUE(x)' >> temp.c; \ + echo '#pragma message("_WIN32_WINNT=" EXPAND_MACRO_VALUE(_WIN32_WINNT))' >> temp.c; \ + echo '#endif' >> temp.c; \ + $(CC) -c temp.c 2>&1 | sed -n 's/^.*_WIN32_WINNT=\(0x[0-9A-Fa-f]\+\).*/\1/p'; \ + rm -f temp.c temp.o) + +ifneq ($(NT_VERSION),) +ifeq ($(shell [ $$(( $(NT_VERSION) )) -gt $$(( 0x602 )) ] && echo true),true) +LIBS += -lxaudio2_9 +endif +else +$(warning Windows NT version macro (_WIN32_WINNT) is not defined.) +endif + +endif + ################################## diff --git a/Makefile.ctr b/Makefile.ctr index 45d6f91936..ad4093bc9c 100644 --- a/Makefile.ctr +++ b/Makefile.ctr @@ -3,8 +3,8 @@ LIBRETRO = DEBUG = 0 CONSOLE_LOG = 0 -GRIFFIN_BUILD = 1 -HAVE_STATIC_DUMMY ?= 0 +GRIFFIN_BUILD = 0 +HAVE_STATIC_DUMMY ?= 0 WHOLE_ARCHIVE_LINK = 0 BUILD_3DSX = 1 BUILD_3DS = 0 @@ -89,21 +89,22 @@ else HAVE_REWIND = 1 HAVE_AUDIOMIXER = 1 HAVE_RWAV = 1 - #HAVE_NETWORKING = 1 - #HAVE_IFINFO = 1 - #HAVE_CHEEVOS = 1 - #HAVE_SOCKET_LEGACY = 1 + HAVE_CHEATS = 1 + HAVE_VIDEO_FILTER = 1 + HAVE_DSP_FILTER = 1 + HAVE_CONFIGFILE = 1 + HAVE_OVERLAY = 1 + HAVE_GFX_WIDGETS = 1 + HAVE_NETWORKING = 1 + HAVE_IFINFO = 1 + HAVE_CHEEVOS = 1 HAVE_THREADS = 1 - #HAVE_SSL = 1 - #HAVE_BUILTINMBEDTLS = 1 + HAVE_BUILTINMBEDTLS = 1 HAVE_CORE_INFO_CACHE = 1 + HAVE_CLOUDSYNC = 1 include Makefile.common CFLAGS += $(DEF_FLAGS) - BLACKLIST := - BLACKLIST += input/input_overlay.o - BLACKLIST += tasks/task_overlay.o - OBJ := $(filter-out $(BLACKLIST),$(OBJ)) endif ifeq ($(strip $(DEVKITPRO)),) @@ -154,8 +155,7 @@ LIBDIRS := -L. -L$(CTRULIB)/lib ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -marm -mfpu=vfp -mtp=soft CFLAGS += -mword-relocations \ - -fomit-frame-pointer -ffast-math \ - -Werror=implicit-function-declaration \ + -ffast-math \ $(ARCH) #CFLAGS += -Wall @@ -168,7 +168,7 @@ endif ifeq ($(DEBUG), 1) CFLAGS += -O0 -g else - CFLAGS += -O3 + CFLAGS += -fomit-frame-pointer -O3 endif ifeq ($(CONSOLE_LOG), 1) @@ -188,17 +188,17 @@ CFLAGS += -I. \ -Ideps \ -Ideps/7zip \ -Ideps/stb \ + -Ideps/mbedtls \ -Ideps/rcheevos/include \ -Ilibretro-common/include \ -Ilibretro-common/include/compat/zlib CFLAGS += -DRARCH_INTERNAL -DRARCH_CONSOLE -CFLAGS += -DHAVE_DSP_FILTER -CFLAGS += -DHAVE_VIDEO_FILTER CFLAGS += -DHAVE_FILTERS_BUILTIN $(DEFINES) -CFLAGS += -DHAVE_CHEATS +CFLAGS += -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_CORES -DHAVE_UPDATE_CORE_INFO CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 +CFLAGS += -Werror=implicit-function-declaration ASFLAGS := -g $(ARCH) -O3 LDFLAGS += -specs=ctr/3dsx_custom.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) @@ -222,6 +222,10 @@ else LIBS += -lctru endif +ifneq ($(V),1) + Q := @ +endif + ifeq ($(BUILD_3DSX), 1) TARGET_3DSX := $(TARGET).3dsx $(TARGET).smdh endif @@ -234,16 +238,7 @@ ifeq ($(BUILD_CIA), 1) TARGET_CIA := $(TARGET).cia endif -.PHONY: $(BUILD) clean all - -all: $(TARGET) - -$(TARGET): $(TARGET_3DSX) $(TARGET_3DS) $(TARGET_CIA) -$(TARGET).3dsx: $(TARGET).elf -$(TARGET).elf: $(OBJ) $(LIB_CORE_FULL) - PREFIX := $(DEVKITARM)/bin/arm-none-eabi- - CC := $(PREFIX)gcc CXX := $(PREFIX)g++ AS := $(PREFIX)as @@ -277,6 +272,36 @@ else MAKEROM = $(CTRMAKEROM) endif +.PHONY: $(BUILD) clean all + +all: info $(TARGET) + +define INFO +AR: $(AR) +ASFLAGS: $(ASFLAGS) +CC: $(CC) +CFLAGS: $(CFLAGS) +CXX: $(CXX) +CXXFLAGS: $(CXXFLAGS) +INCDIRS: $(INCDIRS) +LD: $(LD) +LDFLAGS: $(LDFLAGS) +LIBDIRS: $(LIBDIRS) +LIBS: $(LIBS) +OBJ: $(OBJ) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif + + +$(TARGET): $(TARGET_3DSX) $(TARGET_3DS) $(TARGET_CIA) +$(TARGET).3dsx: $(TARGET).elf +$(TARGET).elf: $(OBJ) $(LIB_CORE_FULL) + %.o: %.vsh %.gsh $(DEVKITTOOLS)/bin/picasso $^ -o $*.shbin $(DEVKITTOOLS)/bin/bin2s $*.shbin | $(PREFIX)as -o $@ @@ -288,19 +313,24 @@ endif rm $*.shbin %.o: %.cpp - $(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS) + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS) %.o: %.c - $(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS) + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS) %.o: %.s - $(CC) -c -o $@ $< $(ASFLAGS) + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) -c -o $@ $< $(ASFLAGS) %.o: %.S - $(CC) -c -o $@ $< $(ASFLAGS) + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) -c -o $@ $< $(ASFLAGS) %.a: - $(AR) -rc $@ $^ + @$(if $(Q), $(shell echo echo AR $<),) + $(Q)$(AR) -rc $@ $^ %.vsh: @@ -316,7 +346,8 @@ endif $(DEVKITTOOLS)/bin/3dsxtool $< $@ $(_3DSXFLAGS) $(TARGET).elf: ctr/3dsx_custom_crt0.o - $(LD) $(LDFLAGS) $(OBJ) $(LIBDIRS) $(LIBS) -o $@ + @$(if $(Q), $(shell echo echo LD $@),) + $(Q)$(LD) $(LDFLAGS) $(OBJ) $(LIBDIRS) $(LIBS) -o $@ $(NM) -CSn $@ > $(notdir $*.lst) $(TARGET).bnr: $(TARGET).elf $(APP_BANNER) $(APP_AUDIO) @@ -332,15 +363,16 @@ $(TARGET).cia: $(TARGET).elf $(TARGET).bnr $(TARGET).icn $(APP_RSF) $(MAKEROM) -f cia -o $@ $(MAKEROM_ARGS_COMMON) -DAPP_ENCRYPTED=false clean: - rm -f $(OBJ) - rm -f $(TARGET).3dsx - rm -f $(TARGET).elf - rm -f $(TARGET).3ds - rm -f $(TARGET).cia - rm -f $(TARGET).smdh - rm -f $(TARGET).bnr - rm -f $(TARGET).icn - rm -f ctr/ctr_config_*.o - rm -f ctr/3dsx_custom_crt0.o + @$(if $(Q), echo $@,) + $(Q)rm -f $(OBJ) + $(Q)rm -f $(TARGET).3dsx + $(Q)rm -f $(TARGET).elf + $(Q)rm -f $(TARGET).3ds + $(Q)rm -f $(TARGET).cia + $(Q)rm -f $(TARGET).smdh + $(Q)rm -f $(TARGET).bnr + $(Q)rm -f $(TARGET).icn + $(Q)rm -f ctr/ctr_config_*.o + $(Q)rm -f ctr/3dsx_custom_crt0.o .PHONY: clean diff --git a/Makefile.ctr.salamander b/Makefile.ctr.salamander index a00f2c2e33..1c51011ee8 100644 --- a/Makefile.ctr.salamander +++ b/Makefile.ctr.salamander @@ -85,7 +85,6 @@ ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -marm -mfpu=vfp -mtp=so CFLAGS += -mword-relocations \ -fomit-frame-pointer -ffast-math \ - -Werror=implicit-function-declaration \ $(ARCH) #CFLAGS += -Wall @@ -111,6 +110,7 @@ CFLAGS += -I. -Ideps/7zip -Ideps/stb -Ilibretro-common/include -Ilibretro-common CFLAGS += -DRARCH_CONSOLE -DIS_SALAMANDER CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 +CFLAGS += -Werror=implicit-function-declaration ASFLAGS := -g $(ARCH) -O3 LDFLAGS += -specs=ctr/3dsx_custom.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) diff --git a/Makefile.dos b/Makefile.dos index 73d6a07742..2f36430112 100644 --- a/Makefile.dos +++ b/Makefile.dos @@ -195,6 +195,10 @@ else LIB_CORE += -lretro_dos endif +ifneq ($(V),1) + Q := @ +endif + DEPENDS_TMP := $(OFILES:.o=.d) DEPENDS := $(filter-out libretro_libnx.a,$(DEPENDS_TMP)) @@ -203,19 +207,43 @@ DEPENDS := $(filter-out libretro_libnx.a,$(DEPENDS_TMP)) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- -all : $(OUTPUT) +all: info $(OUTPUT) + +define INFO +CC: $(CC) +CFLAGS: $(CFLAGS) +CXX: $(CXX) +DEPENDS: $(DEPENDS) +LDFLAGS: $(LDFLAGS) +LIBDIRS: $(LIBDIRS) +LIBS: $(LIBS) +LIB_CORE: $(LIB_CORE) +OBJ: $(OBJ) +OUTPUT: $(OUTPUT) +PLATEXTRA: $(PLATEXTRA) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif $(OUTPUT): $(OBJ) - $(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) -L. $(LIB_CORE) $(LIBS) + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) -L. $(LIB_CORE) $(LIBS) %.o: %.c - $(CC) -c -o $@ $(CFLAGS) $< + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< %.o: %.cpp - $(CXX) -c -o $@ $(CFLAGS) $< + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) -c -o $@ $(CFLAGS) $< clean: - rm -f $(DEPENDS) $(OBJ) $(OUTPUT) + @$(if $(Q), $(shell echo echo RM),) + $(Q)rm -f $(DEPENDS) $(OBJ) $(OUTPUT) #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data diff --git a/Makefile.emscripten b/Makefile.emscripten index 475cbcc3e3..0d44cb2580 100644 --- a/Makefile.emscripten +++ b/Makefile.emscripten @@ -7,29 +7,33 @@ else TARGET := $(LIBRETRO)_libretro.js endif endif - -EOPT = USE_ZLIB=1 # Emscripten specific options -EOPTS = $(addprefix -s $(EMPTY), $(EOPT)) # Add '-s ' to each option +TARGET_BASE := $(subst .js,,$(TARGET)) OS = Emscripten OBJ := -DEFINES := -DRARCH_INTERNAL -DHAVE_MAIN -DEFINES += -DHAVE_FILTERS_BUILTIN +DEFINES := -DRARCH_INTERNAL -DHAVE_MAIN -DEMSCRIPTEN -DNO_CANVAS_RESIZE +DEFINES += -DHAVE_FILTERS_BUILTIN -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORE_INFO + HAVE_PATCH = 1 HAVE_DSP_FILTER = 1 HAVE_VIDEO_FILTER = 1 HAVE_OVERLAY = 1 +HAVE_NETWORKING ?= 1 +HAVE_LIBRETRODB = 1 +HAVE_COMPRESSION = 1 +HAVE_UPDATE_ASSETS = 1 +HAVE_ONLINE_UPDATER = 1 HAVE_GLSL = 1 HAVE_SCREENSHOTS = 1 HAVE_REWIND = 1 HAVE_AUDIOMIXER = 1 HAVE_CC_RESAMPLER = 1 -HAVE_EGL = 1 +HAVE_EGL ?= 0 HAVE_OPENGLES = 1 -HAVE_RJPEG = 0 -HAVE_RPNG = 1 +HAVE_RJPEG = 0 +HAVE_RPNG = 1 HAVE_EMSCRIPTEN = 1 -HAVE_MENU = 1 +HAVE_MENU ?= 1 HAVE_GFX_WIDGETS = 1 HAVE_RGUI = 1 HAVE_SDL = 0 @@ -41,13 +45,23 @@ HAVE_STATIC_AUDIO_FILTERS = 1 HAVE_STB_FONT = 1 HAVE_CONFIGFILE = 1 HAVE_COMMAND = 1 -HAVE_STDIN_CMD = 1 +HAVE_STDIN_CMD ?= 1 HAVE_CHEATS = 1 HAVE_IBXM = 1 HAVE_CORE_INFO_CACHE = 1 HAVE_7ZIP = 1 HAVE_BSV_MOVIE = 1 -HAVE_AL = 1 +HAVE_CHD ?= 0 +HAVE_NETPLAYDISCOVERY ?= 0 + +HAVE_AL ?= 1 + +# enables pthreads, requires special headers on the web server: +# see https://web.dev/articles/coop-coep +HAVE_THREADS ?= 0 + +# requires HAVE_THREADS +HAVE_AUDIOWORKLET ?= 0 # WARNING -- READ BEFORE ENABLING # The rwebaudio driver is known to have several audio bugs, such as @@ -55,77 +69,206 @@ HAVE_AL = 1 # It works perfectly on chrome, but even firefox has really bad audio quality. # I should also note, the driver on iOS is completely broken (crashes the page). # You have been warned. -HAVE_RWEBAUDIO = 0 +HAVE_RWEBAUDIO ?= 0 + +# whether the browser thread is allowed to block to wait for audio to play, +# may lead to the issues mentioned above. +# currently this variable is only used by audioworklet; +# rwebaudio will always busywait and openal will never busywait. +ALLOW_AUDIO_BUSYWAIT ?= 0 + +# minimal asyncify; better performance than full asyncify, +# but sleeping on the main thread is only possible in some places. +MIN_ASYNC ?= 0 + +# runs RetroArch on a pthread instead of the browser thread; requires HAVE_THREADS +PROXY_TO_PTHREAD ?= 0 + +# recommended FS when using HAVE_THREADS +HAVE_WASMFS ?= 0 + +# enables OPFS (origin private file system) and FETCHFS, requires PROXY_TO_PTHREAD +HAVE_EXTRA_WASMFS ?= 0 + +# enable javascript filesystem tracking, incompatible with HAVE_WASMFS +FS_DEBUG ?= 0 + +# help diagnose GL problems (can cause issues in normal operation) +GL_DEBUG ?= 0 + +# does nothing on its own, but automatically selected by some other options +WASM_WORKERS = 0 + +HAVE_OPENGLES ?= 1 +HAVE_OPENGLES3 ?= 0 ASYNC ?= 0 -ifeq ($(LIBRETRO), mupen64plus) - ASYNC = 1 -endif - LTO ?= 0 -ifeq ($(LIBRETRO), tyrquake) - LTO = 0 -endif +PTHREAD_POOL_SIZE ?= 4 -PTHREAD ?= 0 +STACK_SIZE ?= 4194304 +INITIAL_HEAP ?= 134217728 -MEMORY ?= 134217728 - -PRECISE_F32 = 1 +# 4194304 ----- 4 MiB (Stack: recommended) +# 8388608 ----- 8 MiB +# 16777216 ---- 16 MiB +# 33554432 ---- 32 MiB +# 67108864 ---- 64 MiB +# 134217728 --- 128 MiB (Heap: recommended) (Stack: recommended for some cores [mupen64plus_next]) +# 268435456 --- 256 MiB (Heap: recommended for some cores [mupen64plus_next]) +# 536870912 --- 512 MiB (Heap: needed for some cores [mednafen_psx(_hw)]) +# 1073741824 -- 1 GiB +# 1610612736 -- 1.5 GiB +# 2147483648 -- 2 GiB OBJDIR := obj-emscripten -#if you compile with SDL2 flag add this Emscripten flag "-s USE_SDL=2" to LDFLAGS: +EXPORTED_FUNCTIONS = _main,_malloc,_free,_cmd_savefiles,_cmd_save_state,_cmd_load_state,_cmd_undo_save_state,_cmd_undo_load_state,_cmd_take_screenshot,\ +_cmd_toggle_menu,_cmd_reload_config,_cmd_toggle_grab_mouse,_cmd_toggle_game_focus,_cmd_reset,_cmd_toggle_pause,_cmd_pause,_cmd_unpause,\ +_cmd_set_volume,_cmd_set_shader,_cmd_cheat_set_code,_cmd_cheat_get_code,_cmd_cheat_toggle_index,_cmd_cheat_get_code_state,_cmd_cheat_realloc,\ +_cmd_cheat_get_size,_cmd_cheat_apply_cheats,EmscriptenSendCommand,EmscriptenReceiveCommandReply -LIBS := -s USE_ZLIB=1 -LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s TOTAL_MEMORY=$(MEMORY) -s NO_EXIT_RUNTIME=0 -s FULL_ES2=1 \ - -s "EXPORTED_RUNTIME_METHODS=['callMain', 'FS', 'PATH', 'ERRNO_CODES']" \ - -s ALLOW_MEMORY_GROWTH=1 -s "EXPORTED_FUNCTIONS=['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_load_state', '_cmd_take_screenshot']" \ - -s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \ - -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 \ - --js-library emscripten/library_errno_codes.js \ - --js-library emscripten/library_rwebcam.js +EXPORTS := callMain,FS,PATH,ERRNO_CODES,ENV,stringToNewUTF8,UTF8ToString,Browser,EmscriptenSendCommand,EmscriptenReceiveCommandReply -ifeq ($(HAVE_RWEBAUDIO), 1) - LDFLAGS += --js-library emscripten/library_rwebaudio.js - DEFINES += -DHAVE_RWEBAUDIO -endif -ifeq ($(HAVE_AL), 1) - LDFLAGS += -lopenal - DEFINES += -DHAVE_AL - ASYNC = 1 -endif +LIBS := -s USE_ZLIB=1 +CFLAGS := -s USE_ZLIB=1 -ifneq ($(PTHREAD), 0) - LDFLAGS += -s WASM_MEM_MAX=1073741824 -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD) - CFLAGS += -pthread - HAVE_THREADS=1 -else - HAVE_THREADS=0 -endif - -ifeq ($(ASYNC), 1) - LDFLAGS += -s ASYNCIFY=$(ASYNC) -s ASYNCIFY_STACK_SIZE=8192 - ifeq ($(DEBUG), 1) - LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE +ifeq ($(HAVE_EXTRA_WASMFS), 1) + LIBS += -lfetchfs.js -lopfs.js + DEFINES += -DHAVE_EXTRA_WASMFS + override HAVE_WASMFS = 1 + ifeq ($(PROXY_TO_PTHREAD), 0) + $(error ERROR: HAVE_EXTRA_WASMFS requires PROXY_TO_PTHREAD) endif endif +ifeq ($(HAVE_WASMFS), 1) + LIBS += -s WASMFS -s FORCE_FILESYSTEM=1 +endif + +# note: real PROXY_TO_PTHREAD is not used here; we do the pthread management ourselves +ifeq ($(PROXY_TO_PTHREAD), 1) + LIBS += -s OFFSCREENCANVAS_SUPPORT + DEFINES += -DPROXY_TO_PTHREAD -DEMSCRIPTEN_STACK_SIZE=$(STACK_SIZE) + override HAVE_THREADS = 1 + override WASM_WORKERS = 1 + # use the default stack size for the browser thread; the RetroArch thread will be created with the specified stack size + override STACK_SIZE = 4194304 +else ifeq ($(HAVE_AL), 1) + override ASYNC = 1 +endif + ifeq ($(HAVE_SDL2), 1) LIBS += -s USE_SDL=2 DEFINES += -DHAVE_SDL2 endif +LDFLAGS := -L. --no-heap-copy -s STACK_SIZE=$(STACK_SIZE) -s INITIAL_MEMORY=$(INITIAL_HEAP) \ + -s EXPORTED_RUNTIME_METHODS=$(EXPORTS) \ + -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="$(EXPORTED_FUNCTIONS)" \ + -s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \ + -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 \ + -s ENVIRONMENT=web,worker \ + --extern-pre-js emscripten/pre.js \ + --js-library emscripten/library_rwebcam.js \ + --js-library emscripten/library_platform_emscripten.js + +ifeq ($(HAVE_OPENGLES), 1) + ifeq ($(HAVE_OPENGLES3), 1) + LDFLAGS += -s FULL_ES3=1 -s MIN_WEBGL_VERSION=2 -s MAX_WEBGL_VERSION=2 + else + LDFLAGS += -s FULL_ES2=1 -s MIN_WEBGL_VERSION=1 -s MAX_WEBGL_VERSION=2 + endif +endif + +ifeq ($(GL_DEBUG), 1) + LDFLAGS += -s GL_ASSERTIONS=1 -s GL_DEBUG=1 + DEFINES += -DHAVE_GL_DEBUG_ES=1 +endif + +ifeq ($(FS_DEBUG), 1) + LDFLAGS += -s FS_DEBUG=1 +endif + +ifeq ($(HAVE_RWEBAUDIO), 1) + LDFLAGS += --js-library emscripten/library_rwebaudio.js + DEFINES += -DHAVE_RWEBAUDIO +endif + +ifeq ($(HAVE_AUDIOWORKLET), 1) + LDFLAGS += -s AUDIO_WORKLET=1 + DEFINES += -DHAVE_AUDIOWORKLET + override WASM_WORKERS = 1 + ifeq ($(HAVE_THREADS), 0) + $(error ERROR: AUDIOWORKLET requires HAVE_THREADS) + endif + ifeq ($(PROXY_TO_PTHREAD), 1) + else ifeq ($(ASYNC), 1) + else + DEFINES += -DEMSCRIPTEN_AUDIO_EXTERNAL_BLOCK + ifeq ($(MIN_ASYNC), 1) + DEFINES += -DEMSCRIPTEN_AUDIO_ASYNC_BLOCK + else + DEFINES += -DEMSCRIPTEN_AUDIO_FAKE_BLOCK + endif + ifneq ($(ALLOW_AUDIO_BUSYWAIT), 1) + DEFINES += -DEMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK + endif + endif +endif + +ifeq ($(ALLOW_AUDIO_BUSYWAIT), 1) + DEFINES += -DEMSCRIPTEN_AUDIO_BUSYWAIT +endif + +# explanation of some of these defines: +# EMSCRIPTEN_AUDIO_EXTERNAL_BLOCK: audio blocking occurs in the main loop instead of in the audio driver functions. +# EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK: along with above, enables external blocking in the write function. +# ALLOW_AUDIO_BUSYWAIT: write function will busywait. init function may still use an external block. +# EMSCRIPTEN_AUDIO_ASYNC_BLOCK: external block uses emscripten_sleep (requires MIN_ASYNC). +# EMSCRIPTEN_AUDIO_FAKE_BLOCK: external block uses main loop timing (doesn't require asyncify). +# when building with either PROXY_TO_PTHREAD or ASYNC (full asyncify), none of the above are required. + +ifeq ($(HAVE_AL), 1) + LDFLAGS += -lopenal + DEFINES += -DHAVE_AL +endif + +ifeq ($(HAVE_THREADS), 1) + LDFLAGS += -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD_POOL_SIZE) + CFLAGS += -pthread -s SHARED_MEMORY +endif + +ifeq ($(WASM_WORKERS), 1) + LDFLAGS += -s WASM_WORKERS=2 +endif + +ifeq ($(ASYNC), 1) + DEFINES += -DEMSCRIPTEN_ASYNCIFY -DEMSCRIPTEN_FULL_ASYNCIFY + LDFLAGS += -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192 + ifeq ($(DEBUG), 1) + #LDFLAGS += -s ASYNCIFY_DEBUG=1 # broken? + endif +else ifeq ($(MIN_ASYNC), 1) + DEFINES += -DEMSCRIPTEN_ASYNCIFY -DEMSCRIPTEN_MIN_ASYNCIFY + LDFLAGS += -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192 -s ASYNCIFY_IGNORE_INDIRECT=1 -s ASYNCIFY_ADD='dynCall_*,emscripten_mainloop' -s ASYNCIFY_REMOVE='threaded_worker' + ifeq ($(DEBUG), 1) + LDFLAGS += -s ASYNCIFY_ADVISE #-s ASYNCIFY_DEBUG=1 + endif +endif + include Makefile.common CFLAGS += $(DEF_FLAGS) -Ideps -Ideps/stb -libretro := +libretro = +libretro_new = ifeq ($(HAVE_STATIC_DUMMY),1) DEFINES += -DHAVE_STATIC_DUMMY else - libretro += libretro_emscripten.bc + libretro = libretro_emscripten.bc + libretro_new = libretro_emscripten.a endif ifneq ($(V), 1) @@ -133,46 +276,55 @@ ifneq ($(V), 1) endif ifeq ($(DEBUG), 1) - LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1 - CFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s SAFE_HEAP_LOG=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1 + LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=2 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1 + # -O0 in cflags gives "too many locals" errors + CFLAGS += -O1 -g -gsource-map else - LDFLAGS += -O3 -s WASM=1 + LDFLAGS += -O3 # WARNING: some optimizations can break some cores (ex: LTO breaks tyrquake) - LDFLAGS += -s PRECISE_F32=$(PRECISE_F32) ifeq ($(LTO), 1) - LDFLAGS += --llvm-lto 3 + LDFLAGS += -flto endif CFLAGS += -O3 endif -# 128 * 1024, double the usual emscripten stack size -LDFLAGS += -s STACK_SIZE=131072 - -LDFLAGS += --extern-pre-js emscripten/pre.js - -CFLAGS += -Wall -I. -Ilibretro-common/include -std=gnu99 #\ -# -s EXPORTED_FUNCTIONS="['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_take_screenshot']" +CFLAGS += -Wall -I. -Ilibretro-common/include -Ideps/7zip -std=gnu99 RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ)) all: $(TARGET) -$(TARGET): $(RARCH_OBJ) $(libretro) - @$(if $(Q), $(shell echo echo LD $@),) - $(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro) $(LIBS) $(LDFLAGS) +$(libretro_new): ; + +mv_libretro: + mv -f $(libretro) $(libretro_new) || true + +# until emscripten adds something like WASM_WORKERS=2 but for audio worklets, DIY. +ifeq ($(HAVE_AUDIOWORKLET), 1) +$(TARGET): $(RARCH_OBJ) $(libretro_new) mv_libretro + @$(if $(Q), $(shell echo echo "LD $@ \ $(libretro_new) $(LIBS) $(LDFLAGS)"),) + $(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS) + $(Q)tr -d '\n' < "$(TARGET_BASE).aw.js" | sed -e "s/[\/&]/\\\\&/g" -e "s/'/\\\\\\\\&/g" > _audioworklet.js + $(Q)sed -i.bak -e "s/\"$(TARGET_BASE)\.aw\.js\"/URL.createObjectURL(new Blob(['$$(cat _audioworklet.js)'],{type:'text\/javascript'}))/" -- "$@" + $(Q)rm -f "$(TARGET_BASE).aw.js" _audioworklet.js "$@".bak +else +$(TARGET): $(RARCH_OBJ) $(libretro_new) mv_libretro + @$(if $(Q), $(shell echo echo "LD $@ \ $(libretro_new) $(LIBS) $(LDFLAGS)"),) + $(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS) +endif $(OBJDIR)/%.o: %.c @mkdir -p $(dir $@) @$(if $(Q), $(shell echo echo CC $<),) - $(Q)$(CC) $(CFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $< + $(Q)$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< $(OBJDIR)/%.o: %.cpp @mkdir -p $(dir $@) @$(if $(Q), $(shell echo echo CXX $<),) - $(Q)$(CXX) $(CXXFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $< + $(Q)$(CXX) $(CXXFLAGS) $(DEFINES) -c -o $@ $< clean: rm -rf $(OBJDIR) rm -f $(TARGET) -.PHONY: all clean +.PHONY: all clean mv_libretro diff --git a/Makefile.miyoo b/Makefile.miyoo index 2880af10ad..67c1b73d91 100644 --- a/Makefile.miyoo +++ b/Makefile.miyoo @@ -160,11 +160,35 @@ CXXFLAGS += $(DEF_FLAGS) HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h) -Q := @ +ifneq ($(V),1) + Q := @ +endif RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ)) -all: $(TARGET) +all: info $(TARGET) + +define INFO +ASFLAGS: $(ASFLAGS) +CC: $(CC) +CFLAGS: $(CFLAGS) +CPPFLAGS: $(CPPFLAGS) +CXX: $(CXX) +CXXFLAGS: $(CXXFLAGS) +DEFINES: $(DEFINES) +LDFLAGS: $(LDFLAGS) +LIBRARY_DIRS: $(LIBRARY_DIRS) +LIBS: $(LIBS) +LINK: $(LINK) +OBJCFLAGS: $(OBJCFLAGS) +RARCH_OBJ: $(RARCH_OBJ) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif -include $(RARCH_OBJ:.o=.d) @@ -199,9 +223,10 @@ $(OBJDIR)/%.o: %.S $(HEADERS) $(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $< clean: - rm -rf $(OBJDIR_BASE) - rm -f $(TARGET) - rm -f *.d + @$(if $(Q), echo $@,) + $(Q)rm -rf $(OBJDIR_BASE) + $(Q)rm -f $(TARGET) + $(Q)rm -f *.d .PHONY: all clean diff --git a/Makefile.ngc b/Makefile.ngc index 432ed36e8f..c733120fbf 100644 --- a/Makefile.ngc +++ b/Makefile.ngc @@ -233,34 +233,65 @@ else CFLAGS += -O3 endif +ifneq ($(V),1) + Q := @ +endif + OBJOUT = -o LINKOUT = -o LINK = $(CXX) -all: $(EXT_TARGET) +all: info $(EXT_TARGET) + +define INFO +CC: $(CC) +CFLAGS: $(CFLAGS) +CXX: $(CXX) +LD: $(LD) +LDFLAGS: $(LDFLAGS) +LIBDIRS: $(LIBDIRS) +LIBS: $(LIBS) +LINK: $(LINK) +LINKOUT: $(LINKOUT) +OBJ: $(OBJ) +OBJOUT: $(OBJOUT) +PLATEXTRA: $(PLATEXTRA) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif %.dol: %.elf $(ELF2DOL) $< $@ $(EXT_INTER_TARGET): $(OBJ) - $(LINK) $(LINKOUT)$@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) $(LIBS) + @$(if $(Q), $(shell echo echo LINK $@),) + $(Q)$(LINK) $(LINKOUT)$@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) $(LIBS) %.o: %.c - $(CC) $(CFLAGS) -c $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $< %.o: %.cpp - $(CXX) $(CFLAGS) -c $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) $(CFLAGS) -c $(OBJOUT)$@ $< %.o: %.S - $(CC) $(CFLAGS) -c $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $< %.binobj: %.bin - $(LD) -r -b binary $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo LD $@),) + $(Q)$(LD) -r -b binary $(OBJOUT)$@ $< clean: - rm -f $(EXT_TARGET) - rm -f $(EXT_INTER_TARGET) - rm -f $(OBJ) + @$(if $(Q), echo $@,) + $(Q)rm -f $(EXT_TARGET) + $(Q)rm -f $(EXT_INTER_TARGET) + $(Q)rm -f $(OBJ) .PHONY: clean diff --git a/Makefile.orbis b/Makefile.orbis index bbe9416b66..b598f715e0 100644 --- a/Makefile.orbis +++ b/Makefile.orbis @@ -176,38 +176,67 @@ else CXXFLAGS += -O3 endif +ifneq ($(V),1) + Q := @ +endif + TARGETS := $(TARGET).self -all: $(TARGETS) +all: info $(TARGETS) + +define INFO +CC: $(CC) +CFLAGS: $(CFLAGS) +CXX: $(CXX) +CXXFLAGS: $(CXXFLAGS) +LD: $(LD) +LDFLAGS: $(LDFLAGS) +LIBS: $(LIBS) +OBJ: $(OBJ) +OBJOUT: $(OBJOUT) +ORBISDEV: $(ORBISDEV) +TARGET: $(TARGET) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif OBJOUT = -o %.o: %.c - $(CC) $(CFLAGS) -c $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $< %.o: %.cpp - $(CXX) $(CXXFLAGS) -c $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) $(CXXFLAGS) -c $(OBJOUT)$@ $< %.o: %.S - $(CC) $(CFLAGS) -c $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $< %.o: %.s - $(CC) -c $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) -c $(OBJOUT)$@ $< $(TARGET).elf: $(OBJ) - $(LD) $(ORBISDEV)/usr/lib/crt0.o $(OBJ) $(LDFLAGS) $(LIBS) -o $(TARGET).elf + @$(if $(Q), $(shell echo echo LD $@),) + $(Q)$(LD) $(ORBISDEV)/usr/lib/crt0.o $(OBJ) $(LDFLAGS) $(LIBS) -o $(TARGET).elf $(TARGET).oelf: $(TARGET).elf - @orbis-elf-create $(TARGET).elf $(TARGET).oelf + orbis-elf-create $(TARGET).elf $(TARGET).oelf $(TARGET).self: $(TARGET).oelf python $(ORBISDEV)/bin/make_fself.py --auth-info $(AUTH_INFO) $(TARGET).oelf $(TARGET).self install: - @cp $(TARGET).self $(SELF_PATH_INSTALL)/homebrew.self + cp $(TARGET).self $(SELF_PATH_INSTALL)/homebrew.self @echo "Installed!" clean: - rm -f $(OBJ) $(TARGET).elf $(TARGET).oelf $(TARGET).self + $(Q)rm -f $(OBJ) $(TARGET).elf $(TARGET).oelf $(TARGET).self .PHONY: clean all diff --git a/Makefile.ps2 b/Makefile.ps2 index 78b7975211..1ffe0d1e95 100644 --- a/Makefile.ps2 +++ b/Makefile.ps2 @@ -83,6 +83,10 @@ ifeq ($(strip $(PS2SDK)),) $(error "Please set PS2SDK in your environment. export PS2SDK=ps2sdk") endif +ifneq ($(V),1) + Q := @ +endif + INCDIR = -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ports/include INCDIR += -Ilibretro-common/include -Ideps -Ideps/stb -Ideps/7zip @@ -104,10 +108,27 @@ EE_INCS = $(INCDIR) EE_BIN = $(TARGET).elf EE_GPVAL = $(GPVAL) -all: $(EE_BIN) +all: info $(EE_BIN) + +define INFO +EE_BIN: $(EE_BIN) +EE_CC: $(EE_CC) +EE_CFLAGS: $(EE_CFLAGS) +EE_CXX: $(EE_CXX) +EE_CXXFLAGS: $(EE_CXXFLAGS) +EE_INCS: $(EE_INCS) +EE_OBJS: $(EE_OBJS) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif clean: - rm -f $(EE_BIN) $(EE_OBJS) + @$(if $(Q), $(shell echo echo RM $<),) + $(Q)rm -f $(EE_BIN) $(EE_OBJS) prepare: ps2client -h $(PS2_IP) reset @@ -131,3 +152,15 @@ release: all #Include preferences include $(PS2SDK)/samples/Makefile.pref include $(PS2SDK)/samples/Makefile.eeglobal_cpp + +%.o: %.c + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c $< -o $@ + +%.o: %.cc + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(EE_CXX) $(EE_CXXFLAGS) $(EE_INCS) -c $< -o $@ + +%.o: %.cpp + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(EE_CXX) $(EE_CXXFLAGS) $(EE_INCS) -c $< -o $@ diff --git a/Makefile.psl1ght b/Makefile.psl1ght index ca570535c1..6350e07cb4 100644 --- a/Makefile.psl1ght +++ b/Makefile.psl1ght @@ -6,7 +6,7 @@ ifeq ($(strip $(PSL1GHT)),) $(error "Please set PSL1GHT in your environment. export PSL1GHT=") endif - + include $(PSL1GHT)/ppu_rules include version.all @@ -30,10 +30,17 @@ CORE_PATH = pkg/psl1ght/pkg/USRDIR/cores/CORE.SELF INCLUDE += -I. -Ideps -Ideps/stb -Ilibretro-common/include/compat/zlib -Ilibretro-common/include $(LIBPSL1GHT_INC) -Iinclude -Idefines -I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2 LIBDIRS += -L. -L$(PORTLIBS)/lib +ifeq ($(HAVE_STATIC_DUMMY),1) + DEFINES += -DHAVE_STATIC_DUMMY + LIBS := +else + LIBS := -lretro_psl1ght +endif + MACHDEP := -D__PSL1GHT__ -D__PS3__ -mcpu=cell -CFLAGS += -Wall $(MACHDEP) $(INCLUDE) +CFLAGS += -Wall $(DEFINES) $(MACHDEP) $(INCLUDE) LDFLAGS := $(MACHDEP) -LIBS := -lretro_psl1ght -lrt -laudio -lrsx -lgcm_sys -lnet -lio -lsysutil -lsysmodule -lm -ljpgdec -lpngdec -llv2 -lnet -lnetctl -lsysfs -lfreetype -lcamera -lgem -lspurs +LIBS += -lrt -laudio -lrsx -lgcm_sys -lnet -lio -lsysutil -lsysmodule -lm -ljpgdec -lpngdec -llv2 -lnet -lnetctl -lsysfs -lfreetype -lcamera -lgem -lspurs # system platform system_platform = unix @@ -119,13 +126,32 @@ else CXXFLAGS += -03 -g endif -all: $(SELF_TARGET) +ifneq ($(V),1) + Q := @ +endif + +all: info $(SELF_TARGET) + +define INFO +CXX: $(CXX) +LDFLAGS: $(LDFLAGS) +LIBDIRS: $(LIBDIRS) +LIBS: $(LIBS) +OBJ: $(OBJ) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif $(ELF_TARGET): $(OBJ) - $(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(LIBS) + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(LIBS) create-core: $(SELF_TARGET) - cp $(SELF_TARGET) $(CORE_PATH) + cp $(SELF_TARGET) $(CORE_PATH) pkg: create-core $(PKG) --contentid $(CONTENTID) pkg/psl1ght/pkg/ $(PACKAGE_BASENAME).pkg @@ -133,7 +159,11 @@ pkg: create-core # $(PACKAGE_FINALIZE) $(PACKAGE_BASENAME).gnpdrm.pkg clean: +ifneq ($(V),1) + @echo RM +else rm -f $(ELF_TARGET) rm -f $(OBJ) +endif .PHONY: clean diff --git a/Makefile.retrofw b/Makefile.retrofw index f03ba467a1..fc0a2ddffa 100644 --- a/Makefile.retrofw +++ b/Makefile.retrofw @@ -164,7 +164,9 @@ CXXFLAGS += $(DEF_FLAGS) HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h) -Q := @ +ifneq ($(V),1) + Q := @ +endif RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ)) @@ -182,8 +184,29 @@ X-OD-NeedsDownscaling=true endef export DESKTOP_ENTRY +all: info $(TARGET) opk -all: $(TARGET) opk +define INFO +ASFLAGS: $(ASFLAGS) +CC: $(CC) +CFLAGS: $(CFLAGS) +CPPFLAGS: $(CPPFLAGS) +CXX: $(CXX) +CXXFLAGS: $(CXXFLAGS) +DEFINES: $(DEFINES) +LDFLAGS: $(LDFLAGS) +LIBRARY_DIRS: $(LIBRARY_DIRS) +LIBS: $(LIBS) +LINK: $(LINK) +OBJCFLAGS: $(OBJCFLAGS) +RARCH_OBJ: $(RARCH_OBJ) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif -include $(RARCH_OBJ:.o=.d) @@ -214,10 +237,11 @@ $(OBJDIR)/%.o: %.S $(HEADERS) $(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $< clean: - rm -rf $(OBJDIR_BASE) - rm -f $(TARGET) - rm -f *.d - rm -rf $(OPK_NAME) + @$(if $(Q), echo $@,) + $(Q)rm -rf $(OBJDIR_BASE) + $(Q)rm -f $(TARGET) + $(Q)rm -f *.d + $(Q)rm -rf $(OPK_NAME) opk: $(TARGET) echo "$$DESKTOP_ENTRY" > default.retrofw.desktop diff --git a/Makefile.rs90 b/Makefile.rs90 index 3f58131d44..58492e5308 100644 --- a/Makefile.rs90 +++ b/Makefile.rs90 @@ -166,7 +166,9 @@ CXXFLAGS += $(DEF_FLAGS) HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h) -Q := @ +ifneq ($(V),1) + Q := @ +endif RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ)) @@ -184,7 +186,29 @@ X-OD-NeedsDownscaling=true endef export DESKTOP_ENTRY -all: $(TARGET) opk +all: info $(TARGET) opk + +define INFO +ASFLAGS: $(ASFLAGS) +CC: $(CC) +CFLAGS: $(CFLAGS) +CPPFLAGS: $(CPPFLAGS) +CXX: $(CXX) +CXXFLAGS: $(CXXFLAGS) +DEFINES: $(DEFINES) +LDFLAGS: $(LDFLAGS) +LIBRARY_DIRS: $(LIBRARY_DIRS) +LIBS: $(LIBS) +LINK: $(LINK) +OBJCFLAGS: $(OBJCFLAGS) +RARCH_OBJ: $(RARCH_OBJ) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif -include $(RARCH_OBJ:.o=.d) @@ -215,10 +239,11 @@ $(OBJDIR)/%.o: %.S $(HEADERS) $(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $< clean: - rm -rf $(OBJDIR_BASE) - rm -f $(TARGET) - rm -f *.d - rm -rf $(OPK_NAME) + @$(if $(Q), echo $@,) + $(Q)rm -rf $(OBJDIR_BASE) + $(Q)rm -f $(TARGET) + $(Q)rm -f *.d + $(Q)rm -rf $(OPK_NAME) opk: $(TARGET) echo "$$DESKTOP_ENTRY" > default.rs90.desktop diff --git a/Makefile.vita b/Makefile.vita index 9244f0d515..ec94f0cbca 100644 --- a/Makefile.vita +++ b/Makefile.vita @@ -138,7 +138,7 @@ ifeq ($(HAVE_VITAGLES), 1) ARCHFLAGS += -DSCE_LIBC_SIZE=$(SCE_LIBC_SIZE) endif -CFLAGS += $(ARCHFLAGS) -mword-relocations -fno-optimize-sibling-calls +CFLAGS += $(ARCHFLAGS) -mword-relocations ifeq ($(DEBUG), 1) CFLAGS += -g -Og @@ -147,7 +147,7 @@ else endif ASFLAGS := $(CFLAGS) -LDFLAGS := -Wl,-q +LDFLAGS := -Wl,-q,--pic-veneer CFLAGS += -Wall -ffast-math CFLAGS += -DRARCH_INTERNAL -DHAVE_SCREENSHOTS -DRARCH_CONSOLE @@ -190,6 +190,10 @@ else LIBS += -lretro_vita endif +ifneq ($(V),1) + Q := @ +endif + LIBS += $(WHOLE_END) $(VITA_LIBS) -lm -lc TARGETS := $(TARGET).vpk @@ -197,27 +201,53 @@ TARGETS := $(TARGET).vpk DEPFLAGS = -MT $@ -MMD -MP -MF $*.Tdepend POSTCOMPILE = mv -f $*.Tdepend $*.depend -all: $(TARGETS) +all: info $(TARGETS) + +define INFO +ASFLAGS: $(ASFLAGS) +CC: $(CC) +CFLAGS: $(CFLAGS) +CXX: $(CXX) +CXXFLAGS: $(CXXFLAGS) +DEPFLAGS: $(DEPFLAGS) +INCDIRS: $(INCDIRS) +LD: $(LD) +LDFLAGS: $(LDFLAGS) +LIBDIRS: $(LIBDIRS) +LIBS: $(LIBS) +OBJ: $(OBJ) +POSTCOMPILE: $(POSTCOMPILE) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif %.o: %.cpp %.o: %.cpp %.depend - $(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS) $(DEPFLAGS) - $(POSTCOMPILE) + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS) $(DEPFLAGS) + $(Q)$(POSTCOMPILE) %.o: %.c %.o: %.c %.depend - $(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS) $(DEPFLAGS) - $(POSTCOMPILE) + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS) $(DEPFLAGS) + $(Q)$(POSTCOMPILE) %.o: %.S %.o: %.S %.depend - $(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS) - $(POSTCOMPILE) + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS) + $(Q)$(POSTCOMPILE) %.o: %.s %.o: %.s %.depend - $(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS) - $(POSTCOMPILE) + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS) + $(Q)$(POSTCOMPILE) %.depend: ; @@ -228,7 +258,8 @@ liblibScePiglet_stub.a: cp deps/Pigs-In-A-Blanket/piglet_stub/libScePiglet/liblibScePiglet_stub.a . $(TARGET).elf: $(OBJ) liblibScePiglet_stub.a - $(LD) $(OBJ) $(LDFLAGS) $(LIBDIRS) $(LIBS) -o $@ + @$(if $(Q), $(shell echo echo LD $@),) + $(Q)$(LD) $(OBJ) $(LDFLAGS) $(LIBDIRS) $(LIBS) -o $@ %.velf: %.elf cp $< $<.unstripped.elf @@ -243,9 +274,11 @@ $(TARGET).elf: $(OBJ) liblibScePiglet_stub.a vita-pack-vpk -s param.sfo -b $< $@ clean: +ifneq ($(V),1) rm -f $(OBJ) $(TARGET).elf $(TARGET).elf.unstripped.elf $(TARGET).velf $(TARGET).self param.sfo $(TARGET).vpk rm -rf deps/Pigs-In-A-Blanket/piglet_stub/libScePiglet rm -f $(OBJ:.o=.depend) +endif # Useful for developers vpksend: $(TARGET).vpk diff --git a/Makefile.webos b/Makefile.webos index 6593ca35ea..4ca35b420c 100644 --- a/Makefile.webos +++ b/Makefile.webos @@ -183,7 +183,9 @@ CXXFLAGS += $(DEF_FLAGS) HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h) -Q := @ +ifneq ($(V),1) + Q := @ +endif RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ)) @@ -202,7 +204,29 @@ define APPINFO endef export APPINFO -all: $(TARGET) ipk +all: info $(TARGET) ipk + +define INFO +ASFLAGS: $(ASFLAGS) +CC: $(CC) +CFLAGS: $(CFLAGS) +CPPFLAGS: $(CPPFLAGS) +CXX: $(CXX) +CXXFLAGS: $(CXXFLAGS) +DEFINES: $(DEFINES) +LDFLAGS: $(LDFLAGS) +LIBRARY_DIRS: $(LIBRARY_DIRS) +LIBS: $(LIBS) +LINK: $(LINK) +OBJCFLAGS: $(OBJCFLAGS) +RARCH_OBJ: $(RARCH_OBJ) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif -include $(RARCH_OBJ:.o=.d) @@ -233,12 +257,13 @@ $(OBJDIR)/%.o: %.S $(HEADERS) $(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $< clean: - rm -rf $(OBJDIR_BASE) - rm -f $(TARGET) - rm -f *.d - rm -rf SDL - rm -rf webos/*.ipk - rm -rf webos/dist + @$(if $(Q), echo $@,) + $(Q)rm -rf $(OBJDIR_BASE) + $(Q)rm -f $(TARGET) + $(Q)rm -f *.d + $(Q)rm -rf SDL + $(Q)rm -rf webos/*.ipk + $(Q)rm -rf webos/dist sdl2: $(TARGET) ifeq ($(ADD_SDL2_LIB), 1) diff --git a/Makefile.wii b/Makefile.wii index 3f702da3df..f25ebff1a7 100644 --- a/Makefile.wii +++ b/Makefile.wii @@ -265,11 +265,27 @@ ifeq ($(LOAD_WITHOUT_CORE_INFO),1) CFLAGS += -DLOAD_WITHOUT_CORE_INFO endif +ifneq ($(V),1) + Q := @ +endif + OBJOUT = -o LINKOUT = -o LINK = $(CXX) -all: $(EXT_TARGET) +all: info $(EXT_TARGET) + +define INFO +CC: $(CC) +CFLAGS: $(CFLAGS) +OBJOUT: $(OBJOUT) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif %.dol: %.elf $(ELF2DOL) $< $@ @@ -278,13 +294,15 @@ $(EXT_INTER_TARGET): $(OBJ) $(LINK) $(LINKOUT)$@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) $(LIBS) %.o: %.c - $(CC) $(CFLAGS) -c $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $< %.o: %.cpp $(CXX) $(CFLAGS) -c $(OBJOUT)$@ $< %.o: %.S - $(CC) $(CFLAGS) -c $(OBJOUT)$@ $< + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $< %.binobj: %.bin $(LD) -r -b binary $(OBJOUT)$@ $< @@ -294,10 +312,11 @@ $(APP_BOOTER_DIR)/app_booter.bin: $(MAKE) -C $(APP_BOOTER_DIR) clean: - rm -f $(EXT_TARGET) - rm -f $(EXT_INTER_TARGET) - rm -f $(OBJ) - $(MAKE) -C $(APP_BOOTER_DIR) clean + @$(if $(Q), echo $@,) + $(Q)rm -f $(EXT_TARGET) + $(Q)rm -f $(EXT_INTER_TARGET) + $(Q)rm -f $(OBJ) + $(Q)$(MAKE) -C $(APP_BOOTER_DIR) clean .PHONY: clean diff --git a/Makefile.wiiu b/Makefile.wiiu index e1f96a04eb..ee66630887 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -302,7 +302,38 @@ endif DEPFLAGS = -MT $@ -MMD -MP -MF $(BUILD_DIR)/$*.depend -all: $(TARGETS) +all: info $(TARGETS) + +define INFO +AR: $(AR) +ASFLAGS: $(ASFLAGS) +BUILD_DIR: $(BUILD_DIR) +CC: $(CC) +CFLAGS: $(CFLAGS) +CXX: $(CXX) +CXXFLAGS: $(CXXFLAGS) +DEFINES: $(DEFINES) +DEPFLAGS: $(DEPFLAGS) +ELF2RPL: $(ELF2RPL) +HBL_ELF_LDFLAGS: $(HBL_ELF_LDFLAGS) +HBL_ELF_OBJ: $(HBL_ELF_OBJ) +INCDIRS: $(INCDIRS) +LD: $(LD) +LDFLAGS: $(LDFLAGS) +LIBDIRS: $(LIBDIRS) +LIBS: $(LIBS) +MAKE: $(MAKE) +OBJ: $(OBJ) +RPX_LDFLAGS: $(RPX_LDFLAGS) +RPX_OBJ: $(RPX_OBJ) +TARGET: $(TARGET) +endef +export INFO + +info: +ifneq ($(V),1) + @echo "$$INFO" +endif %: $(BUILD_DIR)/% cp $< $@ diff --git a/Makefile.win b/Makefile.win index 0e11d57934..b08980bcf5 100644 --- a/Makefile.win +++ b/Makefile.win @@ -89,6 +89,7 @@ AVUTIL_LIBS := -lavutil SWSCALE_LIBS := -lswscale AVFORMAT_LIBS := -lavformat SWRESAMPLE_LIBS := -lswresample +AVDEVICE_LIBS := -lavdevice FFMPEG_LIBS := -lws2_32 -lz endif diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..51ecbab70c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,26 @@ +# Security Policy + +## Reasonable expectations + +RetroArch is a frontend for the libretro API. The main functionality is fulfilled by invoking other binary libraries ("cores") which are not restricted by RetroArch in any way. Cores are able to read/write/delete files, spawn processes, communicate over the network. Also, source for cores is not necessarily in control by libretro team, and core binaries / RetroArch binaries are not signed. For this reason, it is a bad idea to use RetroArch or any other libretro frontend on security critical systems. + +Also, RetroArch and cores have been packaged in several ways. Content on the [official download site](https://buildbot.libretro.com/) is built from a direct mirror of the original RetroArch and core repositories, no binaries are reused. Note that source for the core repositories may be outside libretro team control. + +## Supported Versions + +For most delivery channels, libretro team does not have control over the version. The exceptions are: +- [official download site](https://buildbot.libretro.com/) +- Steam release +- Apple App Store release +- various Android app store releases +- note that Google Play Store version is years behind and can not be updated + +You may report vulnerability against any recent version, but be reasonable. + +## Reporting a Vulnerability + +Please report security vulnerabilities at libretro@gmail.com + +## Possible remediation + +Due to the variety of delivery channels, RetroArch team can not recall any given version universally. Security fixes are accepted for next release, and notice may be posted in the channels controlled by RetroArch team, depending on the severity assessed by RetroArch team. diff --git a/ai/game_ai.c b/ai/game_ai.c new file mode 100644 index 0000000000..6a029a8d4d --- /dev/null +++ b/ai/game_ai.c @@ -0,0 +1,216 @@ +#include "game_ai.h" +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include +#include + +#include "../deps/game_ai_lib/GameAI.h" + +#define GAME_AI_MAX_PLAYERS 2 + +void * ga = NULL; +volatile void * g_ram_ptr = NULL; +volatile int g_ram_size = 0; +volatile signed short int g_buttons_bits[GAME_AI_MAX_PLAYERS] = {0}; +volatile int g_frameCount = 0; +volatile char game_ai_lib_path[1024] = {0}; +volatile char g_game_name[1024] = {0}; +retro_log_printf_t g_log = NULL; + +#ifdef _WIN32 +HINSTANCE g_lib_handle = NULL; +#else +void * g_lib_handle = NULL; +#endif + +/* GameAI Lib API*/ +create_game_ai_t create_game_ai = NULL; +destroy_game_ai_t destroy_game_ai = NULL; +game_ai_lib_init_t game_ai_lib_init = NULL; +game_ai_lib_think_t game_ai_lib_think = NULL; +game_ai_lib_set_show_debug_t game_ai_lib_set_show_debug = NULL; +game_ai_lib_set_debug_log_t game_ai_lib_set_debug_log = NULL; + +/* Helper functions */ +void game_ai_debug_log(int level, const char *fmt, ...) +{ + va_list vp; + va_start(vp, fmt); + + if (g_log) + g_log((enum retro_log_level)level, fmt, vp); + + va_end(vp); +} + +void array_to_bits_16(volatile signed short *result, const bool b[16]) +{ + for (int bit = 0; bit <= 15; bit++) + *result |= b[bit] ? (1 << bit) : 0; +} + +/* Interface to RA */ + +signed short int game_ai_input(unsigned int port, unsigned int device, + unsigned int idx, unsigned int id, signed short int result) +{ + if (ga && (port < GAME_AI_MAX_PLAYERS)) + return g_buttons_bits[port]; + return 0; +} + +void game_ai_init(void) +{ + if (!create_game_ai) + { +#ifdef _WIN32 + BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; + + g_lib_handle = LoadLibrary(TEXT("game_ai.dll")); + retro_assert(hinstLib); + + char full_module_path[MAX_PATH]; + DWORD dwLen = GetModuleFileNameA(g_lib_handle, static_cast(&full_module_path), MAX_PATH); + + if (hinstLib) + { + create_game_ai = (create_game_ai_t) GetProcAddress(hinstLib, "create_game_ai"); + retro_assert(create_game_ai); + + destroy_game_ai = (destroy_game_ai_t) GetProcAddress(hinstLib, "destroy_game_ai"); + retro_assert(destroy_game_ai); + + game_ai_lib_init = (game_ai_lib_init_t) GetProcAddress(hinstLib, "game_ai_lib_init"); + retro_assert(game_ai_lib_init); + + game_ai_lib_think = (game_ai_lib_think_t) GetProcAddress(hinstLib, "game_ai_lib_think"); + retro_assert(game_ai_lib_think); + + game_ai_lib_set_show_debug = (game_ai_lib_set_show_debug_t) GetProcAddress(hinstLib, "game_ai_lib_set_show_debug"); + retro_assert(game_ai_lib_set_show_debug); + + game_ai_lib_set_debug_log = (game_ai_lib_set_debug_log_t) GetProcAddress(hinstLib, "game_ai_lib_set_debug_log"); + retro_assert(game_ai_lib_set_debug_log); + } +#else + g_lib_handle = dlopen("./libgame_ai.so", RTLD_NOW); + retro_assert(g_lib_handle); + + if (g_lib_handle) + { + dlinfo(g_lib_handle, RTLD_DI_ORIGIN, (void *) &game_ai_lib_path); + + create_game_ai = (create_game_ai_t)(dlsym(g_lib_handle, "create_game_ai")); + retro_assert(create_game_ai); + + destroy_game_ai = (destroy_game_ai_t)(dlsym(g_lib_handle, "destroy_game_ai")); + retro_assert(destroy_game_ai); + + game_ai_lib_init = (game_ai_lib_init_t)(dlsym(g_lib_handle, "game_ai_lib_init")); + retro_assert(game_ai_lib_init); + + game_ai_lib_think = (game_ai_lib_think_t)(dlsym(g_lib_handle, "game_ai_lib_think")); + retro_assert(game_ai_lib_think); + + game_ai_lib_set_show_debug = (game_ai_lib_set_show_debug_t)(dlsym(g_lib_handle, "game_ai_lib_set_show_debug")); + retro_assert(game_ai_lib_set_show_debug); + + game_ai_lib_set_debug_log = (game_ai_lib_set_debug_log_t)(dlsym(g_lib_handle, "game_ai_lib_set_debug_log")); + retro_assert(game_ai_lib_set_debug_log); + } +#endif + } +} + +void game_ai_shutdown(void) +{ + if (g_lib_handle) + { + if (ga) + { + destroy_game_ai(ga); + ga = NULL; + } +#ifdef _WIN32 + FreeLibrary(g_lib_handle); +#else + dlclose(g_lib_handle); +#endif + } +} + +void game_ai_load(const char * name, void * ram_ptr, int ram_size, retro_log_printf_t log) +{ + strcpy((char *) &g_game_name[0], name); + + g_ram_ptr = ram_ptr; + g_ram_size = ram_size; + + g_log = log; + + if (ga) + { + destroy_game_ai(ga); + ga = NULL; + } +} + +void game_ai_think(bool override_p1, bool override_p2, bool show_debug, + const void *frame_data, unsigned int frame_width, unsigned int frame_height, + unsigned int frame_pitch, unsigned int pixel_format) +{ + if (ga) + game_ai_lib_set_show_debug(ga, show_debug); + + if (!ga && g_ram_ptr) + { + ga = create_game_ai((char *) &g_game_name[0]); + retro_assert(ga); + + if (ga) + { + char data_path[1024] = {0}; + strcpy(&data_path[0], (char *)game_ai_lib_path); + strcat(&data_path[0], "/data/"); + strcat(&data_path[0], (char *)g_game_name); + + game_ai_lib_init(ga, (void *) g_ram_ptr, g_ram_size); + game_ai_lib_set_debug_log(ga, game_ai_debug_log); + } + } + + if (g_frameCount >= (GAMEAI_SKIPFRAMES - 1)) + { + if (ga) + { + bool b[GAMEAI_MAX_BUTTONS] = {0}; + + g_buttons_bits[0]=0; + g_buttons_bits[1]=0; + + if (override_p1) + { + game_ai_lib_think(ga, b, 0, frame_data, frame_width, frame_height, frame_pitch, pixel_format); + array_to_bits_16(&g_buttons_bits[0], b); + } + + if (override_p2) + { + game_ai_lib_think(ga, b, 1, frame_data, frame_width, frame_height, frame_pitch, pixel_format); + array_to_bits_16(&g_buttons_bits[1], b); + } + } + g_frameCount=0; + } + else + g_frameCount++; +} diff --git a/ai/game_ai.h b/ai/game_ai.h new file mode 100644 index 0000000000..725e8f77be --- /dev/null +++ b/ai/game_ai.h @@ -0,0 +1,44 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2016 - Daniel De Matteis + * Copyright (C) 2021 - David G.F. + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef RARCH_GAME_AI_H__ +#define RARCH_GAME_AI_H__ + +#include +#include + +#include + +RETRO_BEGIN_DECLS + +signed short int game_ai_input(unsigned int port, unsigned int device, + unsigned int idx, unsigned int id, signed short int result); + +void game_ai_init(void); + +void game_ai_shutdown(void); + +void game_ai_load(const char * name, void * ram_ptr, + int ram_size, retro_log_printf_t log); + +void game_ai_think(bool override_p1, bool override_p2, bool show_debug, + const void *frame_data, unsigned int frame_w, unsigned int frame_h, + unsigned int frame_pitch, unsigned int pixel_format); + +RETRO_END_DECLS + +#endif diff --git a/audio/audio_defines.h b/audio/audio_defines.h index 18de5f0338..ca2a8e162a 100644 --- a/audio/audio_defines.h +++ b/audio/audio_defines.h @@ -161,7 +161,13 @@ enum audio_driver_state_flags * @see audio_driver_t::write_avail * @see audio_driver_t::buffer_size */ - AUDIO_FLAG_CONTROL = (1 << 5) + AUDIO_FLAG_CONTROL = (1 << 5), + + /** + * Indicates that the audio driver is forcing gain to 0. + * Used for temporary rewind and fast-forward muting. + */ + AUDIO_FLAG_MUTED = (1 << 6) }; typedef struct audio_statistics diff --git a/audio/audio_driver.c b/audio/audio_driver.c index 01a727eb95..f6448633d6 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c @@ -147,9 +147,12 @@ audio_driver_t *audio_drivers[] = { #ifdef WIIU &audio_ax, #endif -#if defined(EMSCRIPTEN) && defined(HAVE_RWEBAUDIO) +#if defined(HAVE_RWEBAUDIO) &audio_rwebaudio, #endif +#if defined(HAVE_AUDIOWORKLET) + &audio_audioworklet, +#endif #if defined(PSP) || defined(VITA) || defined(ORBIS) &audio_psp, #endif @@ -216,14 +219,6 @@ bool audio_driver_is_ai_service_speech_running(void) } #endif -static enum resampler_quality audio_driver_get_resampler_quality( - settings_t *settings) -{ - if (settings) - return (enum resampler_quality)settings->uints.audio_resampler_quality; - return RESAMPLER_QUALITY_DONTCARE; -} - static bool audio_driver_free_devices_list(void) { audio_driver_state_t *audio_st = &audio_driver_st; @@ -344,24 +339,17 @@ static void audio_driver_mixer_deinit(void) bool audio_driver_deinit(void) { - settings_t *settings = config_get_ptr(); #ifdef HAVE_AUDIOMIXER audio_driver_mixer_deinit(); #endif audio_driver_free_devices_list(); - return audio_driver_deinit_internal( - settings->bools.audio_enable); + return audio_driver_deinit_internal(config_get_ptr()->bools.audio_enable); } -bool audio_driver_find_driver( - void *settings_data, - const char *prefix, - bool verbosity_enabled) +bool audio_driver_find_driver(const char *audio_drv, + const char *prefix, bool verbosity_enabled) { - settings_t *settings = (settings_t*)settings_data; - int i = (int)driver_find_index( - "audio_driver", - settings->arrays.audio_driver); + int i = (int)driver_find_index("audio_driver", audio_drv); if (i >= 0) audio_driver_st.current_audio = (const audio_driver_t*) @@ -372,8 +360,7 @@ bool audio_driver_find_driver( if (verbosity_enabled) { unsigned d; - RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix, - settings->arrays.audio_driver); + RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix, audio_drv); RARCH_LOG_OUTPUT("Available %ss are:\n", prefix); for (d = 0; audio_drivers[d]; d++) { @@ -400,22 +387,20 @@ bool audio_driver_find_driver( * @param audio_st The overall state of the audio driver. * @param slowmotion_ratio The factor by which slow motion extends the core's runtime * (e.g. a value of 2 means the core is running at half speed). - * @param audio_fastforward_mute True if no audio should be output while the game is in fast-forward. * @param data Audio output data that was most recently provided by the core. * @param samples The size of \c data, in samples. - * @param is_slowmotion True if the player is currently running the game in slow motion. - * @param is_fastmotion True if the player is currently running the game in fast-forward. + * @param is_slowmotion True if the core is currently running in slow motion. + * @param is_fastmotion True if the core is currently running in fast-forward. **/ static void audio_driver_flush( audio_driver_state_t *audio_st, float slowmotion_ratio, - bool audio_fastforward_mute, const int16_t *data, size_t samples, bool is_slowmotion, bool is_fastforward) { struct resampler_data src_data; - float audio_volume_gain = (audio_st->mute_enable || - (audio_fastforward_mute && is_fastforward)) + float audio_volume_gain = + (audio_st->mute_enable || audio_st->flags & AUDIO_FLAG_MUTED) ? 0.0f : audio_st->volume_gain; @@ -481,19 +466,19 @@ static void audio_driver_flush( = avail; audio_st->source_ratio_current = audio_st->source_ratio_original * adjust; - } #if 0 - if (verbosity_is_enabled()) - { - RARCH_LOG_OUTPUT("[Audio]: Audio buffer is %u%% full\n", - (unsigned)(100 - (avail * 100) / - audio_st->buffer_size)); - RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n", - audio_st->source_ratio_current, - audio_st->source_ratio_original); - } + if (verbosity_is_enabled()) + { + RARCH_LOG_OUTPUT("[Audio]: Audio buffer is %u%% full\n", + (unsigned)(100 - (avail * 100) / + audio_st->buffer_size)); + RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n", + audio_st->source_ratio_current, + audio_st->source_ratio_original); + } #endif + } } src_data.ratio = audio_st->source_ratio_current; @@ -598,9 +583,7 @@ const char *audio_driver_mixer_get_stream_name(unsigned i) #endif -bool audio_driver_init_internal( - void *settings_data, - bool audio_cb_inited) +bool audio_driver_init_internal(void *settings_data, bool audio_cb_inited) { unsigned new_rate = 0; float *out_samples_buf = NULL; @@ -612,8 +595,8 @@ bool audio_driver_init_internal( float slowmotion_ratio = settings->floats.slowmotion_ratio; unsigned setting_audio_latency = settings->uints.audio_latency; unsigned runloop_audio_latency = runloop_state_get_ptr()->audio_latency; - unsigned audio_latency = (runloop_audio_latency > setting_audio_latency) ? - runloop_audio_latency : setting_audio_latency; + unsigned audio_latency = (runloop_audio_latency > setting_audio_latency) + ? runloop_audio_latency : setting_audio_latency; #ifdef HAVE_REWIND int16_t *rewind_buf = NULL; #endif @@ -658,7 +641,7 @@ bool audio_driver_init_internal( else audio_driver_st.flags |= AUDIO_FLAG_ACTIVE; - if (!(audio_driver_find_driver(settings, + if (!(audio_driver_find_driver(settings->arrays.audio_driver, "audio driver", verbosity_enabled))) { RARCH_ERR("Failed to initialize audio driver.\n"); @@ -679,7 +662,7 @@ bool audio_driver_init_internal( if (!audio_init_thread( &audio_driver_st.current_audio, &audio_driver_st.context_audio_data, - *settings->arrays.audio_device + *settings->arrays.audio_device ? settings->arrays.audio_device : NULL, settings->uints.audio_output_sample_rate, &new_rate, audio_latency, @@ -694,8 +677,8 @@ bool audio_driver_init_internal( #endif { audio_driver_st.context_audio_data = - audio_driver_st.current_audio->init(*settings->arrays.audio_device ? - settings->arrays.audio_device : NULL, + audio_driver_st.current_audio->init(*settings->arrays.audio_device + ? settings->arrays.audio_device : NULL, settings->uints.audio_output_sample_rate, audio_latency, settings->uints.audio_block_frames, @@ -704,7 +687,8 @@ bool audio_driver_init_internal( } if (new_rate != 0) - configuration_set_int(settings, settings->uints.audio_output_sample_rate, new_rate); + configuration_set_int(settings, + settings->uints.audio_output_sample_rate, new_rate); if (!audio_driver_st.context_audio_data) { @@ -735,7 +719,8 @@ bool audio_driver_init_internal( /* Should never happen. */ RARCH_WARN("[Audio]: Input rate is invalid (%.3f Hz)." " Using output rate (%u Hz).\n", - audio_driver_st.input, settings->uints.audio_output_sample_rate); + audio_driver_st.input, + settings->uints.audio_output_sample_rate); audio_driver_st.input = settings->uints.audio_output_sample_rate; } @@ -751,8 +736,7 @@ bool audio_driver_init_internal( else audio_driver_st.resampler_ident[0] = '\0'; - audio_driver_st.resampler_quality = - audio_driver_get_resampler_quality(settings); + audio_driver_st.resampler_quality = (enum resampler_quality)settings->uints.audio_resampler_quality; if (!retro_resampler_realloc( &audio_driver_st.resampler_data, @@ -850,7 +834,6 @@ void audio_driver_sample(int16_t left, int16_t right) || !(audio_st->output_samples_buf))) audio_driver_flush(audio_st, config_get_ptr()->floats.slowmotion_ratio, - config_get_ptr()->bools.audio_fastforward_mute, audio_st->output_samples_conv_buf, audio_st->data_ptr, (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false, @@ -900,7 +883,6 @@ size_t audio_driver_sample_batch(const int16_t *data, size_t frames) || !(audio_st->output_samples_buf))) audio_driver_flush(audio_st, config_get_ptr()->floats.slowmotion_ratio, - config_get_ptr()->bools.audio_fastforward_mute, data, frames_to_write << 1, (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false, @@ -1487,7 +1469,8 @@ void audio_driver_mixer_play_scroll_sound(bool direction_up) bool audio_enable_menu = settings->bools.audio_enable_menu; bool audio_enable_menu_scroll = settings->bools.audio_enable_menu_scroll; if (audio_enable_menu && audio_enable_menu_scroll) - audio_driver_mixer_play_menu_sound(direction_up ? AUDIO_MIXER_SYSTEM_SLOT_UP : AUDIO_MIXER_SYSTEM_SLOT_DOWN); + audio_driver_mixer_play_menu_sound(direction_up + ? AUDIO_MIXER_SYSTEM_SLOT_UP : AUDIO_MIXER_SYSTEM_SLOT_DOWN); } void audio_driver_mixer_play_stream_looped(unsigned i) @@ -1615,18 +1598,18 @@ bool audio_driver_disable_callback(void) bool audio_driver_callback(void) { - settings_t *settings = config_get_ptr(); + bool menu_pause_libretro = config_get_ptr()->bools.menu_pause_libretro; uint32_t runloop_flags = runloop_get_flags(); bool runloop_paused = (runloop_flags & RUNLOOP_FLAG_PAUSED) ? true : false; #ifdef HAVE_MENU #ifdef HAVE_NETWORKING bool core_paused = runloop_paused - || (settings->bools.menu_pause_libretro + || (menu_pause_libretro && (menu_state_get_ptr()->flags & MENU_ST_FLAG_ALIVE) && netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL)); #else bool core_paused = runloop_paused - || (settings->bools.menu_pause_libretro + || (menu_pause_libretro && (menu_state_get_ptr()->flags & MENU_ST_FLAG_ALIVE)); #endif #else @@ -1737,18 +1720,14 @@ void audio_driver_frame_is_reverse(void) || !(audio_st->flags & AUDIO_FLAG_ACTIVE) || !(audio_st->output_samples_buf))) if (!(audio_st->flags & AUDIO_FLAG_SUSPENDED)) - { - settings_t *settings = config_get_ptr(); audio_driver_flush(audio_st, - settings->floats.slowmotion_ratio, - settings->bools.audio_fastforward_mute, + config_get_ptr()->floats.slowmotion_ratio, audio_st->rewind_buf + audio_st->rewind_ptr, audio_st->rewind_size - audio_st->rewind_ptr, (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false, (runloop_flags & RUNLOOP_FLAG_FASTMOTION) ? true : false); - } } #endif @@ -1880,6 +1859,7 @@ void audio_driver_menu_sample(void) { static int16_t samples_buf[1024] = {0}; settings_t *settings = config_get_ptr(); + float slowmotion_ratio = settings->floats.slowmotion_ratio; video_driver_state_t *video_st = video_state_get_ptr(); uint32_t runloop_flags = runloop_get_flags(); recording_state_t *recording_st = recording_state_get_ptr(); @@ -1910,17 +1890,16 @@ void audio_driver_menu_sample(void) } if (check_flush) audio_driver_flush(audio_st, - settings->floats.slowmotion_ratio, - settings->bools.audio_fastforward_mute, + slowmotion_ratio, samples_buf, 1024, (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false, (runloop_flags & RUNLOOP_FLAG_FASTMOTION) ? true : false); sample_count -= 1024; } - if ( recording_st->data && - recording_st->driver && - recording_st->driver->push_audio) + if ( recording_st->data + && recording_st->driver + && recording_st->driver->push_audio) { struct record_audio_data ffemu_data; @@ -1932,10 +1911,7 @@ void audio_driver_menu_sample(void) } if (check_flush) audio_driver_flush(audio_st, - settings->floats.slowmotion_ratio, - settings->bools.audio_fastforward_mute, - samples_buf, - sample_count, + slowmotion_ratio, samples_buf, sample_count, (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false, (runloop_flags & RUNLOOP_FLAG_FASTMOTION) ? true : false); } diff --git a/audio/audio_driver.h b/audio/audio_driver.h index 4dcb6a6593..676744798a 100644 --- a/audio/audio_driver.h +++ b/audio/audio_driver.h @@ -110,7 +110,7 @@ typedef struct audio_driver * Unless said otherwise with set_nonblock_state(), all writes * are blocking, and it should block till it has written all frames. */ - ssize_t (*write)(void *data, const void *buf, size_t size); + ssize_t (*write)(void *data, const void *s, size_t len); /** * Temporarily pauses the audio driver. @@ -350,10 +350,8 @@ bool audio_driver_init_internal( bool audio_driver_deinit(void); -bool audio_driver_find_driver( - void *settings_data, - const char *prefix, - bool verbosity_enabled); +bool audio_driver_find_driver(const char *audio_drv, + const char *prefix, bool verbosity_enabled); /** * audio_driver_sample: @@ -441,6 +439,7 @@ extern audio_driver_t audio_switch_thread; extern audio_driver_t audio_switch_libnx_audren; extern audio_driver_t audio_switch_libnx_audren_thread; extern audio_driver_t audio_rwebaudio; +extern audio_driver_t audio_audioworklet; audio_driver_state_t *audio_state_get_ptr(void); diff --git a/audio/audio_thread_wrapper.c b/audio/audio_thread_wrapper.c index f52feefc7b..07fb068c6f 100644 --- a/audio/audio_thread_wrapper.c +++ b/audio/audio_thread_wrapper.c @@ -99,7 +99,7 @@ static void audio_thread_loop(void *data) thr->driver->stop(thr->driver_data); while (thr->stopped) { - /* If we stop right after start, + /* If we stop right after start, * we might not be able to properly ack. * Signal in the loop instead. */ thr->stopped_ack = true; @@ -249,7 +249,7 @@ static bool audio_thread_use_float(void *data) return thr->use_float; } -static ssize_t audio_thread_write(void *data, const void *buf, size_t size) +static ssize_t audio_thread_write(void *data, const void *s, size_t len) { ssize_t ret; audio_thread_t *thr = (audio_thread_t*)data; @@ -257,7 +257,7 @@ static ssize_t audio_thread_write(void *data, const void *buf, size_t size) if (!thr) return 0; - ret = thr->driver->write(thr->driver_data, buf, size); + ret = thr->driver->write(thr->driver_data, s, len); if (ret < 0) { diff --git a/audio/common/mmdevice_common_inline.h b/audio/common/mmdevice_common_inline.h index 255fdf5c9d..4ac8176c88 100644 --- a/audio/common/mmdevice_common_inline.h +++ b/audio/common/mmdevice_common_inline.h @@ -20,10 +20,6 @@ /* Fix for MSYS2 increasing _WIN32_WINNT to 0x0603*/ #if defined(__MINGW32__) || defined(__MINGW64__) -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0600 #define WIN32_LEAN_AND_MEAN #else typedef enum EDataFlow EDataFlow; diff --git a/audio/common/pipewire.c b/audio/common/pipewire.c index be05b221bf..4a3c970bbd 100644 --- a/audio/common/pipewire.c +++ b/audio/common/pipewire.c @@ -16,12 +16,11 @@ #include "pipewire.h" #include - #include #include -#include "verbosity.h" +#include "../../verbosity.h" static void core_error_cb(void *data, uint32_t id, int seq, int res, const char *message) @@ -31,7 +30,6 @@ static void core_error_cb(void *data, uint32_t id, int seq, int res, const char RARCH_ERR("[PipeWire]: error id:%u seq:%d res:%d (%s): %s\n", id, seq, res, spa_strerror(res), message); - /* stop and exit the thread loop */ pw_thread_loop_stop(pw->thread_loop); } @@ -42,11 +40,9 @@ static void core_done_cb(void *data, uint32_t id, int seq) retro_assert(id == PW_ID_CORE); pw->last_seq = seq; + if (pw->pending_seq == seq) - { - /* stop and exit the thread loop */ pw_thread_loop_signal(pw->thread_loop, false); - } } static const struct pw_core_events core_events = { @@ -55,7 +51,7 @@ static const struct pw_core_events core_events = { .error = core_error_cb, }; -size_t calc_frame_size(enum spa_audio_format fmt, uint32_t nchannels) +size_t pipewire_calc_frame_size(enum spa_audio_format fmt, uint32_t nchannels) { uint32_t sample_size = 1; switch (fmt) @@ -85,7 +81,7 @@ size_t calc_frame_size(enum spa_audio_format fmt, uint32_t nchannels) return sample_size * nchannels; } -void set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS]) +void pipewire_set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS]) { memcpy(position, (uint32_t[SPA_AUDIO_MAX_CHANNELS]) { SPA_AUDIO_CHANNEL_UNKNOWN, }, sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS); @@ -114,7 +110,7 @@ void set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS]) } } -void pipewire_wait_resync(pipewire_core_t *pw) +void pipewire_core_wait_resync(pipewire_core_t *pw) { retro_assert(pw); pw->pending_seq = pw_core_sync(pw->core, PW_ID_CORE, pw->pending_seq); @@ -127,7 +123,7 @@ void pipewire_wait_resync(pipewire_core_t *pw) } } -bool pipewire_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, bool active) +bool pipewire_stream_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, bool active) { enum pw_stream_state st; const char *error; @@ -144,31 +140,89 @@ bool pipewire_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, return active ? st == PW_STREAM_STATE_STREAMING : st == PW_STREAM_STATE_PAUSED; } -bool pipewire_core_init(pipewire_core_t *pw, const char *loop_name) +bool pipewire_core_init(pipewire_core_t **pw, const char *loop_name, const struct pw_registry_events *events) { - retro_assert(pw); + retro_assert(!*pw); - pw->thread_loop = pw_thread_loop_new(loop_name, NULL); - if (!pw->thread_loop) + *pw = (pipewire_core_t*)calloc(1, sizeof(pipewire_core_t)); + if (!*pw) return false; - pw->ctx = pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0); - if (!pw->ctx) + (*pw)->devicelist = string_list_new(); + if (!(*pw)->devicelist) + { + free(*pw); + *pw = NULL; + return false; + } + + pw_init(NULL, NULL); + + (*pw)->thread_loop = pw_thread_loop_new(loop_name, NULL); + if (!(*pw)->thread_loop) return false; - if (pw_thread_loop_start(pw->thread_loop) < 0) + (*pw)->ctx = pw_context_new(pw_thread_loop_get_loop((*pw)->thread_loop), NULL, 0); + if (!(*pw)->ctx) return false; - pw_thread_loop_lock(pw->thread_loop); - - pw->core = pw_context_connect(pw->ctx, NULL, 0); - if(!pw->core) + if (pw_thread_loop_start((*pw)->thread_loop) < 0) return false; - if (pw_core_add_listener(pw->core, - &pw->core_listener, - &core_events, pw) < 0) - return false; + pw_thread_loop_lock((*pw)->thread_loop); + + (*pw)->core = pw_context_connect((*pw)->ctx, NULL, 0); + if (!(*pw)->core) + goto unlock; + + if (pw_core_add_listener((*pw)->core, + &(*pw)->core_listener, + &core_events, *pw) < 0) + goto unlock; + + if (events) + { + (*pw)->registry = pw_core_get_registry((*pw)->core, PW_VERSION_REGISTRY, 0); + spa_zero((*pw)->registry_listener); + pw_registry_add_listener((*pw)->registry, &(*pw)->registry_listener, events, *pw); + } return true; + +unlock: + pw_thread_loop_unlock((*pw)->thread_loop); + return false; +} + +void pipewire_core_deinit(pipewire_core_t *pw) +{ + if (!pw) + return pw_deinit(); + + if (pw->thread_loop) + pw_thread_loop_stop(pw->thread_loop); + + if (pw->registry) + { + spa_hook_remove(&pw->registry_listener); + pw_proxy_destroy((struct pw_proxy*)pw->registry); + } + + if (pw->core) + { + spa_hook_remove(&pw->core_listener); + pw_core_disconnect(pw->core); + } + + if (pw->ctx) + pw_context_destroy(pw->ctx); + + if (pw->thread_loop) + pw_thread_loop_destroy(pw->thread_loop); + + if (pw->devicelist) + string_list_free(pw->devicelist); + + free(pw); + pw_deinit(); } diff --git a/audio/common/pipewire.h b/audio/common/pipewire.h index 7e9627128a..ee57ffb22f 100644 --- a/audio/common/pipewire.h +++ b/audio/common/pipewire.h @@ -21,9 +21,11 @@ #include #include - #include +#include + + #define PW_RARCH_APPNAME "RetroArch" /* String literals are part of the PipeWire specification */ @@ -31,34 +33,35 @@ #define PW_RARCH_MEDIA_TYPE_VIDEO "Video" #define PW_RARCH_MEDIA_TYPE_MIDI "Midi" #define PW_RARCH_MEDIA_CATEGORY_PLAYBACK "Playback" -#define PW_RARCH_MEDIA_CATEGORY_RECORD "Capture" +#define PW_RARCH_MEDIA_CATEGORY_RECORD "Capture" #define PW_RARCH_MEDIA_ROLE "Game" typedef struct pipewire_core { struct pw_thread_loop *thread_loop; struct pw_context *ctx; + struct pw_core *core; struct spa_hook core_listener; int last_seq, pending_seq; struct pw_registry *registry; struct spa_hook registry_listener; - struct pw_client *client; - struct spa_hook client_listener; - bool nonblock; struct string_list *devicelist; + bool nonblock; } pipewire_core_t; -size_t calc_frame_size(enum spa_audio_format fmt, uint32_t nchannels); +size_t pipewire_calc_frame_size(enum spa_audio_format fmt, uint32_t nchannels); -void set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS]); +void pipewire_set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS]); -void pipewire_wait_resync(pipewire_core_t *pipewire); +bool pipewire_core_init(pipewire_core_t **pw, const char *loop_name, const struct pw_registry_events *events); -bool pipewire_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, bool active); +void pipewire_core_deinit(pipewire_core_t *pw); -bool pipewire_core_init(pipewire_core_t *pipewire, const char *loop_name); +void pipewire_core_wait_resync(pipewire_core_t *pw); + +bool pipewire_stream_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, bool active); #endif /* _RETROARCH_PIPEWIRE */ diff --git a/audio/drivers/alsa.c b/audio/drivers/alsa.c index 9200d70e1f..9748c20e25 100644 --- a/audio/drivers/alsa.c +++ b/audio/drivers/alsa.c @@ -73,14 +73,36 @@ error: #define BYTES_TO_FRAMES(bytes, frame_bits) ((bytes) * 8 / frame_bits) #define FRAMES_TO_BYTES(frames, frame_bits) ((frames) * frame_bits / 8) -static bool alsa_start(void *data, bool is_shutdown); -static ssize_t alsa_write(void *data, const void *buf_, size_t size_) +static bool alsa_start(void *data, bool is_shutdown) { - alsa_t *alsa = (alsa_t*)data; - const uint8_t *buf = (const uint8_t*)buf_; - snd_pcm_sframes_t written = 0; - snd_pcm_sframes_t size = BYTES_TO_FRAMES(size_, alsa->stream_info.frame_bits); - size_t frames_size = alsa->stream_info.has_float ? sizeof(float) : sizeof(int16_t); + alsa_t *alsa = (alsa_t*)data; + if (!alsa->is_paused) + return true; + + if ( alsa->stream_info.can_pause + && alsa->is_paused) + { + int ret = snd_pcm_pause(alsa->pcm, 0); + + if (ret < 0) + { + RARCH_ERR("[ALSA]: Failed to unpause: %s.\n", + snd_strerror(ret)); + return false; + } + + alsa->is_paused = false; + } + return true; +} + +static ssize_t alsa_write(void *data, const void *buf_, size_t len) +{ + ssize_t written = 0; + alsa_t *alsa = (alsa_t*)data; + const uint8_t *buf = (const uint8_t*)buf_; + snd_pcm_sframes_t size = BYTES_TO_FRAMES(len, alsa->stream_info.frame_bits); + size_t frames_size = alsa->stream_info.has_float ? sizeof(float) : sizeof(int16_t); /* Workaround buggy menu code. * If a write happens while we're paused, we might never progress. */ @@ -192,29 +214,6 @@ static void alsa_set_nonblock_state(void *data, bool state) alsa->nonblock = state; } -static bool alsa_start(void *data, bool is_shutdown) -{ - alsa_t *alsa = (alsa_t*)data; - if (!alsa->is_paused) - return true; - - if (alsa->stream_info.can_pause - && alsa->is_paused) - { - int ret = snd_pcm_pause(alsa->pcm, 0); - - if (ret < 0) - { - RARCH_ERR("[ALSA]: Failed to unpause: %s.\n", - snd_strerror(ret)); - return false; - } - - alsa->is_paused = false; - } - return true; -} - static void alsa_free(void *data) { alsa_t *alsa = (alsa_t*)data; diff --git a/audio/drivers/alsa_qsa.c b/audio/drivers/alsa_qsa.c index f78c490d6e..73cab726fe 100644 --- a/audio/drivers/alsa_qsa.c +++ b/audio/drivers/alsa_qsa.c @@ -219,14 +219,14 @@ static int check_pcm_status(void *data, int channel_type) return ret; } -static ssize_t alsa_qsa_write(void *data, const void *buf, size_t size) +static ssize_t alsa_qsa_write(void *data, const void *buf, size_t len) { - alsa_qsa_t *alsa = (alsa_qsa_t*)data; - snd_pcm_sframes_t written = 0; + alsa_qsa_t *alsa = (alsa_qsa_t*)data; + ssize_t written = 0; while (size) { - size_t avail_write = MIN(alsa->buf_size - alsa->buffer_ptr, size); + size_t avail_write = MIN(alsa->buf_size - alsa->buffer_ptr, len); if (avail_write) { @@ -235,7 +235,7 @@ static ssize_t alsa_qsa_write(void *data, const void *buf, size_t size) alsa->buffer_ptr += avail_write; buf = (void*)((uint8_t*)buf + avail_write); - size -= avail_write; + len -= avail_write; written += avail_write; } @@ -260,7 +260,6 @@ static ssize_t alsa_qsa_write(void *data, const void *buf, size_t size) return -1; } } - } return written; diff --git a/audio/drivers/alsathread.c b/audio/drivers/alsathread.c index 030f23dad0..c9c13d21c7 100644 --- a/audio/drivers/alsathread.c +++ b/audio/drivers/alsathread.c @@ -157,8 +157,9 @@ error: return NULL; } -static ssize_t alsa_thread_write(void *data, const void *buf, size_t size) +static ssize_t alsa_thread_write(void *data, const void *s, size_t len) { + ssize_t written = 0; alsa_thread_t *alsa = (alsa_thread_t*)data; if (alsa->info.thread_dead) @@ -167,21 +168,17 @@ static ssize_t alsa_thread_write(void *data, const void *buf, size_t size) if (alsa->nonblock) { size_t avail; - size_t write_amt; slock_lock(alsa->info.fifo_lock); avail = FIFO_WRITE_AVAIL(alsa->info.buffer); - write_amt = MIN(avail, size); + written = MIN(avail, len); - fifo_write(alsa->info.buffer, buf, write_amt); + fifo_write(alsa->info.buffer, s, written); slock_unlock(alsa->info.fifo_lock); - - return write_amt; } else { - size_t written = 0; - while (written < size && !alsa->info.thread_dead) + while (written < (ssize_t)len && !alsa->info.thread_dead) { size_t avail; slock_lock(alsa->info.fifo_lock); @@ -197,15 +194,15 @@ static ssize_t alsa_thread_write(void *data, const void *buf, size_t size) } else { - size_t write_amt = MIN(size - written, avail); + size_t write_amt = MIN(len - written, avail); fifo_write(alsa->info.buffer, - (const char*)buf + written, write_amt); + (const char*)s + written, write_amt); slock_unlock(alsa->info.fifo_lock); written += write_amt; } } - return written; } + return written; } static bool alsa_thread_alive(void *data) diff --git a/audio/drivers/audioio.c b/audio/drivers/audioio.c index 8176a0d7b4..910b5c6a24 100644 --- a/audio/drivers/audioio.c +++ b/audio/drivers/audioio.c @@ -82,15 +82,15 @@ error: return NULL; } -static ssize_t audioio_write(void *data, const void *buf, size_t size) +static ssize_t audioio_write(void *data, const void *s, size_t len) { - ssize_t ret; + ssize_t written; int *fd = (int*)data; - if (size == 0) + if (len == 0) return 0; - if ((ret = write(*fd, buf, size)) < 0) + if ((written = write(*fd, s, len)) < 0) { if (errno == EAGAIN && (fcntl(*fd, F_GETFL) & O_NONBLOCK)) return 0; @@ -98,7 +98,7 @@ static ssize_t audioio_write(void *data, const void *buf, size_t size) return -1; } - return ret; + return written; } static bool audioio_stop(void *data) diff --git a/audio/drivers/audioworklet.c b/audio/drivers/audioworklet.c new file mode 100644 index 0000000000..d5425ff88a --- /dev/null +++ b/audio/drivers/audioworklet.c @@ -0,0 +1,521 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2025 - OlyB + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include "../../frontend/drivers/platform_emscripten.h" + +#include +#include + +#include "../audio_driver.h" +#include "../../verbosity.h" + +#define WORKLET_STACK_SIZE 4096 + +/* additional buffer size (for EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK only) */ +/* if this is too small, frames may be dropped and content could run too fast. */ +/* very large slow-motion rate values may be too large for this; avoid anything higher than 6 or 7. */ +#define EXTERNAL_BLOCK_BUFFER_MS 128 + +typedef struct audioworklet_data +{ + uint8_t *worklet_stack; + uint32_t write_avail_bytes; /* atomic */ + size_t visible_buffer_size; +#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK + size_t write_avail_diff; +#endif +#ifdef PROXY_TO_PTHREAD + emscripten_lock_t trywrite_lock; + emscripten_condvar_t trywrite_cond; +#endif + emscripten_lock_t buffer_lock; + EMSCRIPTEN_WEBAUDIO_T context; + float *tmpbuf; + fifo_buffer_t *buffer; + unsigned rate; + unsigned latency; + bool nonblock; + bool initing; +#ifdef EMSCRIPTEN_AUDIO_FAKE_BLOCK + bool block_requested; +#endif + volatile bool running; /* currently only used by RetroArch */ + volatile bool driver_running; /* whether the driver is running (buffer allocated) */ + volatile bool context_running; /* whether the AudioContext is running */ + volatile bool init_done; + volatile bool init_error; +} audioworklet_data_t; + +/* We only ever want to create 1 worklet, so we need to keep its data even if the driver is inactive. */ +static audioworklet_data_t *audioworklet_static_data = NULL; + +/* Note that we cannot allocate any heap in here. */ +static bool audioworklet_process_cb(int numInputs, const AudioSampleFrame *inputs, + int numOutputs, AudioSampleFrame *outputs, + int numParams, const AudioParamFrame *params, + void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + size_t avail; + size_t max_read; + unsigned writing_frames = 0; + int i; + + /* TODO: do we need to pay attention to audioworklet->running here too? */ + if (audioworklet->driver_running) + { + /* can't use Atomics.wait in AudioWorklet */ + /* busyspin is safe as of emscripten 4.0.4 */ + if (!emscripten_lock_busyspin_wait_acquire(&audioworklet->buffer_lock, 2.5)) + { + printf("[WARN] [AudioWorklet] Worklet: could not acquire lock\n"); + return true; + } + + avail = FIFO_READ_AVAIL(audioworklet->buffer); + max_read = MIN(avail, outputs[0].samplesPerChannel * 2 * sizeof(float)); + + if (max_read) + { + fifo_read(audioworklet->buffer, audioworklet->tmpbuf, max_read); + emscripten_atomic_add_u32(&audioworklet->write_avail_bytes, max_read); + } + emscripten_lock_release(&audioworklet->buffer_lock); +#ifdef PROXY_TO_PTHREAD + emscripten_condvar_signal(&audioworklet->trywrite_cond, 1); +#endif + + writing_frames = max_read / 2 / sizeof(float); + for (i = 0; i < writing_frames; i++) + { + outputs[0].data[i] = audioworklet->tmpbuf[i * 2]; + outputs[0].data[outputs[0].samplesPerChannel + i] = audioworklet->tmpbuf[i * 2 + 1]; + } + } + + if (writing_frames < outputs[0].samplesPerChannel) + { + int zero_frames = outputs[0].samplesPerChannel - writing_frames; + memset(outputs[0].data + writing_frames, 0, zero_frames * sizeof(float)); + memset(outputs[0].data + writing_frames + outputs[0].samplesPerChannel, 0, zero_frames * sizeof(float)); + } + + return true; +} + +static void audioworklet_processor_inited_cb(EMSCRIPTEN_WEBAUDIO_T context, bool success, void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + int outputChannelCounts[1] = { 2 }; + EmscriptenAudioWorkletNodeCreateOptions opts = { 0, 1, outputChannelCounts }; + EMSCRIPTEN_AUDIO_WORKLET_NODE_T worklet_node; + + if (!success) + { + RARCH_ERR("[AudioWorklet] Failed to init AudioWorkletProcessor!\n"); + audioworklet->init_error = true; + audioworklet->init_done = true; + return; + } + + worklet_node = emscripten_create_wasm_audio_worklet_node(context, "retroarch", &opts, audioworklet_process_cb, audioworklet); + emscripten_audio_node_connect(worklet_node, context, 0, 0); + + audioworklet->init_done = true; +} + +static void audioworklet_thread_inited_cb(EMSCRIPTEN_WEBAUDIO_T context, bool success, void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + WebAudioWorkletProcessorCreateOptions opts = { "retroarch", 0 }; + + if (!success) + { + RARCH_ERR("[AudioWorklet] Failed to init worklet thread! Is the worklet file in the right place?\n"); + audioworklet->init_error = true; + audioworklet->init_done = true; + return; + } + + emscripten_create_wasm_audio_worklet_processor_async(context, &opts, audioworklet_processor_inited_cb, audioworklet); +} + +static void audioworklet_ctx_statechange_cb(void *data, bool state) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + audioworklet->context_running = state; +} + +static void audioworklet_ctx_create(void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + + audioworklet->context = emscripten_create_audio_context(0); + + audioworklet->tmpbuf = memalign(16, emscripten_audio_context_quantum_size(audioworklet->context) * 2 * sizeof(float)); + audioworklet->rate = EM_ASM_INT({ + return emscriptenGetAudioObject($0).sampleRate; + }, audioworklet->context); + audioworklet->context_running = EM_ASM_INT({ + let ac = emscriptenGetAudioObject($0); + ac.addEventListener("statechange", function() { + getWasmTableEntry($2)($1, ac.state == "running"); + }); + return ac.state == "running"; + }, audioworklet->context, audioworklet, audioworklet_ctx_statechange_cb); + + emscripten_start_wasm_audio_worklet_thread_async(audioworklet->context, + audioworklet->worklet_stack, WORKLET_STACK_SIZE, audioworklet_thread_inited_cb, audioworklet); +} + +static void audioworklet_alloc_buffer(void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + + size_t buffer_size; + audioworklet->visible_buffer_size = (audioworklet->latency * audioworklet->rate * 2 * sizeof(float)) / 1000; + buffer_size = audioworklet->visible_buffer_size; +#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK + audioworklet->write_avail_diff = (EXTERNAL_BLOCK_BUFFER_MS * audioworklet->rate * 2 * sizeof(float)) / 1000; + buffer_size += audioworklet->write_avail_diff; +#endif + audioworklet->buffer = fifo_new(buffer_size); + emscripten_atomic_store_u32(&audioworklet->write_avail_bytes, buffer_size); + RARCH_LOG("[AudioWorklet] Buffer size: %lu bytes.\n", audioworklet->visible_buffer_size); +} + +static void audioworklet_init_error(void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + + RARCH_ERR("[AudioWorklet] Failed to initialize driver!\n"); + free(audioworklet->worklet_stack); + free(audioworklet->tmpbuf); + free(audioworklet); +} + +static bool audioworklet_resume_ctx(void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + + if (!audioworklet->context_running) + { + MAIN_THREAD_ASYNC_EM_ASM({ + emscriptenGetAudioObject($0).resume(); + }, audioworklet->context); + } + return audioworklet->context_running; +} + +static void *audioworklet_init(const char *device, unsigned rate, + unsigned latency, unsigned block_frames, unsigned *new_rate) +{ + audioworklet_data_t *audioworklet; + if (audioworklet_static_data) + { + if (audioworklet_static_data->driver_running || audioworklet_static_data->initing) + { + RARCH_ERR("[AudioWorklet] Tried to start already running driver!\n"); + return NULL; + } + RARCH_LOG("[AudioWorklet] Reusing old context.\n"); + audioworklet = audioworklet_static_data; + audioworklet->latency = latency; + *new_rate = audioworklet->rate; + RARCH_LOG("[AudioWorklet] Device rate: %d Hz.\n", *new_rate); + audioworklet_alloc_buffer(audioworklet); + audioworklet_resume_ctx(audioworklet); + audioworklet->driver_running = true; + return audioworklet; + } + + audioworklet = (audioworklet_data_t*)calloc(1, sizeof(audioworklet_data_t)); + if (!audioworklet) + return NULL; + audioworklet->worklet_stack = memalign(16, WORKLET_STACK_SIZE); + if (!audioworklet->worklet_stack) + return NULL; + audioworklet_static_data = audioworklet; + + audioworklet->latency = latency; + platform_emscripten_run_on_browser_thread_sync(audioworklet_ctx_create, audioworklet); + *new_rate = audioworklet->rate; + RARCH_LOG("[AudioWorklet] Device rate: %d Hz.\n", *new_rate); + audioworklet->initing = true; + audioworklet_alloc_buffer(audioworklet); + emscripten_lock_init(&audioworklet->buffer_lock); +#ifdef PROXY_TO_PTHREAD + emscripten_lock_init(&audioworklet->trywrite_lock); + emscripten_condvar_init(&audioworklet->trywrite_cond); +#endif + +#ifndef EMSCRIPTEN_AUDIO_EXTERNAL_BLOCK + /* TODO: can MIN_ASYNCIFY block here too? */ + while (!audioworklet->init_done) + retro_sleep(1); + audioworklet->initing = false; + if (audioworklet->init_error) + { + audioworklet_init_error(audioworklet); + return NULL; + } + audioworklet->driver_running = true; +#elif defined(EMSCRIPTEN_AUDIO_FAKE_BLOCK) + audioworklet->block_requested = true; + platform_emscripten_enter_fake_block(1); +#endif + /* external block: will be handled later */ + + return audioworklet; +} + +static ssize_t audioworklet_write(void *data, const void *s, size_t ss) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + const float *samples = (const float*)s; + size_t num_frames = ss / 2 / sizeof(float); + size_t written = 0; + size_t to_write_frames; + size_t to_write_bytes; + size_t avail; + size_t max_write; + + /* too early! might happen with external blocking */ + if (!audioworklet->driver_running) + return 0; + + /* don't write audio if the context isn't running, just try to start it */ + if (!audioworklet_resume_ctx(audioworklet)) + return 0; + + while (num_frames) + { +#ifdef PROXY_TO_PTHREAD + if (!emscripten_lock_wait_acquire(&audioworklet->buffer_lock, 2500000)) +#else + if (!emscripten_lock_busyspin_wait_acquire(&audioworklet->buffer_lock, 2.5)) +#endif + { + RARCH_WARN("[AudioWorklet] Main thread: could not acquire lock\n"); + break; + } + + avail = FIFO_WRITE_AVAIL(audioworklet->buffer); + max_write = avail; +#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK + /* make sure we don't write into the blocking buffer for nonblock */ + if (audioworklet->nonblock) + { + if (max_write > audioworklet->write_avail_diff) + max_write -= audioworklet->write_avail_diff; + else + max_write = 0; + } +#endif + to_write_frames = MIN(num_frames, max_write / 2 / sizeof(float)); + if (to_write_frames) + { + to_write_bytes = to_write_frames * 2 * sizeof(float); + avail -= to_write_bytes; + fifo_write(audioworklet->buffer, samples, to_write_bytes); + emscripten_atomic_store_u32(&audioworklet->write_avail_bytes, (uint32_t)avail); + num_frames -= to_write_frames; + samples += (to_write_frames * 2); + written += to_write_frames; + } + + emscripten_lock_release(&audioworklet->buffer_lock); + +#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK +#ifdef EMSCRIPTEN_AUDIO_FAKE_BLOCK + /* see if we're over the threshold to go to fake block */ + if (avail < audioworklet->write_avail_diff) + { + audioworklet->block_requested = true; + platform_emscripten_enter_fake_block(1); + } +#endif + if (num_frames && !audioworklet->nonblock) + RARCH_WARN("[AudioWorklet] Dropping %lu frames.\n", num_frames); + break; +#endif + if (audioworklet->nonblock || !num_frames) + break; +#if defined(PROXY_TO_PTHREAD) + emscripten_condvar_wait(&audioworklet->trywrite_cond, &audioworklet->trywrite_lock, 3000000); +#elif defined(EMSCRIPTEN_FULL_ASYNCIFY) + retro_sleep(1); +#else /* equivalent to defined(EMSCRIPTEN_AUDIO_BUSYWAIT) */ + while (emscripten_atomic_load_u32(&audioworklet->write_avail_bytes) < 2 * sizeof(float)) + audioworklet_resume_ctx(audioworklet); +#endif + /* try resuming, on the off chance that the context was interrupted while blocking */ + audioworklet_resume_ctx(audioworklet); + } + + return written; +} + +#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_BLOCK +/* returns true if fake block should continue */ +bool audioworklet_external_block(void) +{ + audioworklet_data_t *audioworklet = audioworklet_static_data; + +#ifdef EMSCRIPTEN_AUDIO_FAKE_BLOCK + if (!audioworklet->block_requested) + return false; +#endif + + while (audioworklet->initing && !audioworklet->init_done) +#ifdef EMSCRIPTEN_AUDIO_ASYNC_BLOCK + retro_sleep(1); +#else + return true; +#endif + if (audioworklet->init_done && !audioworklet->driver_running) + { + audioworklet->initing = false; + if (audioworklet->init_error) + { + audioworklet_init_error(audioworklet); + abort(); + return false; + } + audioworklet->driver_running = true; + } +#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK + if (!audioworklet->driver_running) + return false; + + while (emscripten_atomic_load_u32(&audioworklet->write_avail_bytes) < audioworklet->write_avail_diff) + { + audioworklet_resume_ctx(audioworklet); +#ifdef EMSCRIPTEN_AUDIO_ASYNC_BLOCK + retro_sleep(1); +#else + return true; +#endif + } +#endif + +#ifdef EMSCRIPTEN_AUDIO_FAKE_BLOCK + audioworklet->block_requested = false; + platform_emscripten_exit_fake_block(); + return true; /* return to RAF if needed */ +#endif + return false; +} +#endif + +static bool audioworklet_stop(void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + audioworklet->running = false; + return true; +} + +static bool audioworklet_start(void *data, bool is_shutdown) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + audioworklet->running = true; + return true; +} + +static bool audioworklet_alive(void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + return audioworklet->running; +} + +static void audioworklet_set_nonblock_state(void *data, bool state) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + audioworklet->nonblock = state; +} + +static void audioworklet_free(void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + + /* that's not good... this shouldn't happen? */ + if (!audioworklet->driver_running) + { + RARCH_ERR("[AudioWorklet] Tried to free before done initing!\n"); + return; + } + +#ifdef PROXY_TO_PTHREAD + if (!emscripten_lock_wait_acquire(&audioworklet->buffer_lock, 10000000)) +#else + if (!emscripten_lock_busyspin_wait_acquire(&audioworklet->buffer_lock, 10)) +#endif + { + RARCH_ERR("[AudioWorklet] Main thread: could not acquire lock to free buffer!\n"); + return; + } + audioworklet->driver_running = false; + fifo_free(audioworklet->buffer); + emscripten_lock_release(&audioworklet->buffer_lock); + MAIN_THREAD_ASYNC_EM_ASM({ + emscriptenGetAudioObject($0).suspend(); + }, audioworklet->context); +} + +static size_t audioworklet_write_avail(void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + +#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK + size_t avail = emscripten_atomic_load_u32(&audioworklet->write_avail_bytes); + if (avail > audioworklet->write_avail_diff) + return avail - audioworklet->write_avail_diff; + return 0; +#else + return emscripten_atomic_load_u32(&audioworklet->write_avail_bytes); +#endif +} + +static size_t audioworklet_buffer_size(void *data) +{ + audioworklet_data_t *audioworklet = (audioworklet_data_t*)data; + return audioworklet->visible_buffer_size; +} + +static bool audioworklet_use_float(void *data) { return true; } + +audio_driver_t audio_audioworklet = { + audioworklet_init, + audioworklet_write, + audioworklet_stop, + audioworklet_start, + audioworklet_alive, + audioworklet_set_nonblock_state, + audioworklet_free, + audioworklet_use_float, + "audioworklet", + NULL, + NULL, + audioworklet_write_avail, + audioworklet_buffer_size +}; diff --git a/audio/drivers/coreaudio.c b/audio/drivers/coreaudio.c index b950937f7d..3d84a13fd8 100644 --- a/audio/drivers/coreaudio.c +++ b/audio/drivers/coreaudio.c @@ -312,26 +312,26 @@ error: return NULL; } -static ssize_t coreaudio_write(void *data, const void *buf_, size_t size) +static ssize_t coreaudio_write(void *data, const void *buf_, size_t len) { coreaudio_t *dev = (coreaudio_t*)data; const uint8_t *buf = (const uint8_t*)buf_; size_t written = 0; - while (!dev->is_paused && size > 0) + while (!dev->is_paused && len > 0) { size_t write_avail; slock_lock(dev->lock); write_avail = FIFO_WRITE_AVAIL(dev->buffer); - if (write_avail > size) - write_avail = size; + if (write_avail > len) + write_avail = len; fifo_write(dev->buffer, buf, write_avail); buf += write_avail; written += write_avail; - size -= write_avail; + len -= write_avail; if (dev->nonblock) { @@ -409,16 +409,9 @@ static size_t coreaudio_buffer_size(void *data) return dev->buffer_size; } -static void *coreaudio_device_list_new(void *data) -{ - /* TODO/FIXME */ - return NULL; -} - -static void coreaudio_device_list_free(void *data, void *array_list_data) -{ - /* TODO/FIXME */ -} +/* TODO/FIXME - implement */ +static void *coreaudio_device_list_new(void *data) { return NULL; } +static void coreaudio_device_list_free(void *data, void *array_list_data) { } audio_driver_t audio_coreaudio = { coreaudio_init, diff --git a/audio/drivers/coreaudio3.m b/audio/drivers/coreaudio3.m index 3b28e5f61d..c8838d9e90 100644 --- a/audio/drivers/coreaudio3.m +++ b/audio/drivers/coreaudio3.m @@ -307,12 +307,11 @@ static void *coreaudio3_init(const char *device, return (__bridge_retained void *)dev; } -static ssize_t coreaudio3_write(void *data, - const void *buf_, size_t size) +static ssize_t coreaudio3_write(void *data, const void *buf_, size_t len) { CoreAudio3 *dev = (__bridge CoreAudio3 *)data; return [dev writeFloat:(const float *) - buf_ samples:size/sizeof(float)] * sizeof(float); + buf_ samples:len / sizeof(float)] * sizeof(float); } static void coreaudio3_set_nonblock_state(void *data, bool state) diff --git a/audio/drivers/ctr_csnd_audio.c b/audio/drivers/ctr_csnd_audio.c index e751be3052..46bdd3ca8b 100644 --- a/audio/drivers/ctr_csnd_audio.c +++ b/audio/drivers/ctr_csnd_audio.c @@ -162,19 +162,19 @@ static void ctr_csnd_audio_free(void *data) free(ctr); } -static ssize_t ctr_csnd_audio_write(void *data, const void *buf, size_t size) +static ssize_t ctr_csnd_audio_write(void *data, const void *buf, size_t len) { - int i; - uint32_t samples_played = 0; - uint64_t current_tick = 0; - const uint16_t *src = buf; - ctr_csnd_audio_t *ctr = (ctr_csnd_audio_t*)data; + unsigned int i; + uint32_t samples_played = 0; + uint64_t current_tick = 0; + const uint16_t *src = buf; + ctr_csnd_audio_t *ctr = (ctr_csnd_audio_t*)data; ctr_csnd_audio_update_playpos(ctr); - if ((((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 2)) || - (((ctr->pos - ctr->playpos ) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 4)) || - (((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (size >> 2))) + if ( (((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 2)) + || (((ctr->pos - ctr->playpos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 4)) + || (((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (len >> 2))) { if (ctr->nonblock) ctr->pos = (ctr->playpos + (CTR_CSND_AUDIO_COUNT >> 1)) & CTR_CSND_AUDIO_COUNT_MASK; @@ -189,7 +189,7 @@ static ssize_t ctr_csnd_audio_write(void *data, const void *buf, size_t size) } } - for (i = 0; i < (size >> 1); i += 2) + for (i = 0; i < (len >> 1); i += 2) { ctr->l[ctr->pos] = src[i]; ctr->r[ctr->pos] = src[i + 1]; @@ -200,7 +200,7 @@ static ssize_t ctr_csnd_audio_write(void *data, const void *buf, size_t size) GSPGPU_FlushDataCache(ctr->l, CTR_CSND_AUDIO_SIZE); GSPGPU_FlushDataCache(ctr->r, CTR_CSND_AUDIO_SIZE); - return size; + return len; } static bool ctr_csnd_audio_stop(void *data) @@ -264,11 +264,7 @@ static void ctr_csnd_audio_set_nonblock_state(void *data, bool state) ctr->nonblock = state; } -static bool ctr_csnd_audio_use_float(void *data) -{ - (void)data; - return false; -} +static bool ctr_csnd_audio_use_float(void *data) { return false; } static size_t ctr_csnd_audio_write_avail(void *data) { diff --git a/audio/drivers/ctr_dsp_audio.c b/audio/drivers/ctr_dsp_audio.c index 9cc165be92..3cf8a42f45 100644 --- a/audio/drivers/ctr_dsp_audio.c +++ b/audio/drivers/ctr_dsp_audio.c @@ -19,6 +19,8 @@ #include "../audio_driver.h" #include "../../ctr/ctr_debug.h" +#include "../../retroarch.h" +#include "../../verbosity.h" typedef struct { @@ -91,15 +93,15 @@ static void ctr_dsp_audio_free(void *data) ndspExit(); } -static ssize_t ctr_dsp_audio_write(void *data, const void *buf, size_t size) +static ssize_t ctr_dsp_audio_write(void *data, const void *buf, size_t len) { u32 pos; - ctr_dsp_audio_t * ctr = (ctr_dsp_audio_t*)data; - uint32_t sample_pos = ndspChnGetSamplePos(ctr->channel); + ctr_dsp_audio_t *ctr = (ctr_dsp_audio_t*)data; + uint32_t sample_pos = ndspChnGetSamplePos(ctr->channel); - if ((((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 2)) || - (((ctr->pos - sample_pos ) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 4)) || - (((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (size >> 2))) + if ( (((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 2)) + || (((ctr->pos - sample_pos) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 4)) + || (((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (len >> 2))) { if (ctr->nonblock) ctr->pos = (sample_pos + (CTR_DSP_AUDIO_COUNT >> 1)) & CTR_DSP_AUDIO_COUNT_MASK; @@ -113,38 +115,38 @@ static ssize_t ctr_dsp_audio_write(void *data, const void *buf, size_t size) * changed, this prevents a hang on sleep. */ if (!aptMainLoop()) { - command_event(CMD_EVENT_QUIT, NULL); + retroarch_main_quit(); return true; } sample_pos = ndspChnGetSamplePos(ctr->channel); - }while ( ((sample_pos - (ctr->pos + (size >>2))) & CTR_DSP_AUDIO_COUNT_MASK) > (CTR_DSP_AUDIO_COUNT >> 1) + }while ( ((sample_pos - (ctr->pos + (len >>2))) & CTR_DSP_AUDIO_COUNT_MASK) > (CTR_DSP_AUDIO_COUNT >> 1) || (((ctr->pos - (CTR_DSP_AUDIO_COUNT >> 4) - sample_pos) & CTR_DSP_AUDIO_COUNT_MASK) > (CTR_DSP_AUDIO_COUNT >> 1))); } } pos = ctr->pos << 2; - if ((pos + size) > CTR_DSP_AUDIO_SIZE) + if ((pos + len) > CTR_DSP_AUDIO_SIZE) { memcpy(ctr->dsp_buf.data_pcm8 + pos, buf, (CTR_DSP_AUDIO_SIZE - pos)); DSP_FlushDataCache(ctr->dsp_buf.data_pcm8 + pos, (CTR_DSP_AUDIO_SIZE - pos)); memcpy(ctr->dsp_buf.data_pcm8, (uint8_t*) buf + (CTR_DSP_AUDIO_SIZE - pos), - (pos + size - CTR_DSP_AUDIO_SIZE)); - DSP_FlushDataCache(ctr->dsp_buf.data_pcm8, (pos + size - CTR_DSP_AUDIO_SIZE)); + (pos + len - CTR_DSP_AUDIO_SIZE)); + DSP_FlushDataCache(ctr->dsp_buf.data_pcm8, (pos + len - CTR_DSP_AUDIO_SIZE)); } else { - memcpy(ctr->dsp_buf.data_pcm8 + pos, buf, size); - DSP_FlushDataCache(ctr->dsp_buf.data_pcm8 + pos, size); + memcpy(ctr->dsp_buf.data_pcm8 + pos, buf, len); + DSP_FlushDataCache(ctr->dsp_buf.data_pcm8 + pos, len); } - ctr->pos += size >> 2; + ctr->pos += len >> 2; ctr->pos &= CTR_DSP_AUDIO_COUNT_MASK; - return size; + return len; } static bool ctr_dsp_audio_stop(void *data) @@ -185,11 +187,7 @@ static void ctr_dsp_audio_set_nonblock_state(void *data, bool state) ctr->nonblock = state; } -static bool ctr_dsp_audio_use_float(void *data) -{ - (void)data; - return false; -} +static bool ctr_dsp_audio_use_float(void *data) { return false; } static size_t ctr_dsp_audio_write_avail(void *data) { diff --git a/audio/drivers/ctr_dsp_thread_audio.c b/audio/drivers/ctr_dsp_thread_audio.c index 458695113a..2871d1b38d 100644 --- a/audio/drivers/ctr_dsp_thread_audio.c +++ b/audio/drivers/ctr_dsp_thread_audio.c @@ -16,11 +16,13 @@ #include <3ds.h> #include #include +#include #include #include #include "../audio_driver.h" #include "../../ctr/ctr_debug.h" +#include "../../verbosity.h" typedef struct { @@ -198,7 +200,7 @@ static void ctr_dsp_thread_audio_free(void *data) ctr = NULL; } -static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t size) +static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t len) { size_t avail, written; ctr_dsp_thread_audio_t * ctr = (ctr_dsp_thread_audio_t*)data; @@ -210,7 +212,7 @@ static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t si { slock_lock(ctr->fifo_lock); avail = FIFO_WRITE_AVAIL(ctr->fifo); - written = MIN(avail, size); + written = MIN(avail, len); if (written > 0) { fifo_write(ctr->fifo, buf, written); @@ -221,7 +223,7 @@ static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t si else { written = 0; - while (written < size && ctr->running) + while (written < len && ctr->running) { slock_lock(ctr->fifo_lock); avail = FIFO_WRITE_AVAIL(ctr->fifo); @@ -240,7 +242,7 @@ static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t si } else { - size_t write_amt = MIN(size - written, avail); + size_t write_amt = MIN(len - written, avail); fifo_write(ctr->fifo, (const char*)buf + written, write_amt); scond_signal(ctr->fifo_avail); slock_unlock(ctr->fifo_lock); diff --git a/audio/drivers/dsound.c b/audio/drivers/dsound.c index 000540540f..f61335ba87 100644 --- a/audio/drivers/dsound.c +++ b/audio/drivers/dsound.c @@ -205,7 +205,7 @@ static DWORD CALLBACK dsound_thread(PVOID data) IDirectSoundBuffer_Unlock(ds->dsb, region.chunk1, region.size1, region.chunk2, region.size2); - write_ptr = (write_ptr + region.size1 + region.size2) + write_ptr = (write_ptr + region.size1 + region.size2) % ds->buffer_size; if (is_pull) @@ -501,7 +501,7 @@ static void dsound_set_nonblock_state(void *data, bool state) ds->nonblock = state; } -static ssize_t dsound_write(void *data, const void *buf_, size_t size) +static ssize_t dsound_write(void *data, const void *buf_, size_t len) { size_t written = 0; dsound_t *ds = (dsound_t*)data; @@ -512,39 +512,39 @@ static ssize_t dsound_write(void *data, const void *buf_, size_t size) if (ds->nonblock) { - if (size > 0) + if (len > 0) { size_t avail; EnterCriticalSection(&ds->crit); avail = FIFO_WRITE_AVAIL(ds->buffer); - if (avail > size) - avail = size; + if (avail > len) + avail = len; fifo_write(ds->buffer, buf, avail); LeaveCriticalSection(&ds->crit); buf += avail; - size -= avail; + len -= avail; written += avail; } } else { - while (size > 0) + while (len > 0) { size_t avail; EnterCriticalSection(&ds->crit); avail = FIFO_WRITE_AVAIL(ds->buffer); - if (avail > size) - avail = size; + if (avail > len) + avail = len; fifo_write(ds->buffer, buf, avail); LeaveCriticalSection(&ds->crit); buf += avail; - size -= avail; + len -= avail; written += avail; if (!ds->thread_alive) diff --git a/audio/drivers/gx_audio.c b/audio/drivers/gx_audio.c index f594863b98..cf51de77fe 100644 --- a/audio/drivers/gx_audio.c +++ b/audio/drivers/gx_audio.c @@ -16,6 +16,7 @@ #include #include +#include #ifdef GEKKO #include @@ -79,7 +80,7 @@ static void *gx_audio_init(const char *device, AIInit(NULL); AIRegisterDMACallback(dma_callback); - /* Ranges 0-32000 (default low) and 40000-47999 + /* Ranges 0-32000 (default low) and 40000-47999 (in settings going down from 48000) -> set to 32000 hz */ if (rate <= 32000 || (rate >= 40000 && rate < 48000)) { @@ -103,18 +104,18 @@ static void *gx_audio_init(const char *device, /* Wii uses silly R, L, R, L interleaving. */ static INLINE void copy_swapped(uint32_t * restrict dst, - const uint32_t * restrict src, size_t size) + const uint32_t * restrict src, size_t len) { do { uint32_t s = *src++; *dst++ = (s >> 16) | (s << 16); - } while (--size); + } while (--len); } -static ssize_t gx_audio_write(void *data, const void *buf_, size_t size) +static ssize_t gx_audio_write(void *data, const void *buf_, size_t len) { - size_t frames = size >> 2; + size_t frames = len >> 2; const uint32_t *buf = buf_; gx_audio_t *wa = data; @@ -142,8 +143,7 @@ static ssize_t gx_audio_write(void *data, const void *buf_, size_t size) wa->dma_write = (wa->dma_write + 1) & (BLOCKS - 1); } } - - return size; + return len; } static bool gx_audio_stop(void *data) @@ -209,18 +209,9 @@ static size_t gx_audio_write_avail(void *data) & (BLOCKS - 1)) * CHUNK_SIZE; } -static size_t gx_audio_buffer_size(void *data) -{ - (void)data; - return BLOCKS * CHUNK_SIZE; -} - -static bool gx_audio_use_float(void *data) -{ - /* TODO/FIXME - verify */ - (void)data; - return false; -} +static size_t gx_audio_buffer_size(void *data) { return BLOCKS * CHUNK_SIZE; } +/* TODO/FIXME - implement/verify? */ +static bool gx_audio_use_float(void *data) { return false; } audio_driver_t audio_gx = { gx_audio_init, diff --git a/audio/drivers/jack.c b/audio/drivers/jack.c index 6d199067e2..c581cb7268 100644 --- a/audio/drivers/jack.c +++ b/audio/drivers/jack.c @@ -252,13 +252,13 @@ error: return NULL; } -static ssize_t ja_write(void *data, const void *buf_, size_t size) +static ssize_t ja_write(void *data, const void *buf_, size_t len) { jack_t *jd = (jack_t*)data; const char *buf = (const char *)buf_; size_t written = 0; - while (size > 0) + while (len > 0) { size_t avail, to_write; @@ -267,7 +267,7 @@ static ssize_t ja_write(void *data, const void *buf_, size_t size) avail = jack_ringbuffer_write_space(jd->buffer); - to_write = size < avail ? size : avail; + to_write = (len < avail) ? len : avail; /* make sure to only write multiples of the sample size */ to_write = (to_write / sizeof(float)) * sizeof(float); @@ -275,7 +275,7 @@ static ssize_t ja_write(void *data, const void *buf_, size_t size) { jack_ringbuffer_write(jd->buffer, buf, to_write); buf += to_write; - size -= to_write; + len -= to_write; written += to_write; } else if (!jd->nonblock) @@ -350,11 +350,7 @@ static void ja_free(void *data) free(jd); } -static bool ja_use_float(void *data) -{ - (void)data; - return true; -} +static bool ja_use_float(void *data) { return true; } static size_t ja_write_avail(void *data) { diff --git a/audio/drivers/openal.c b/audio/drivers/openal.c index e08e69778e..cb69929bbd 100644 --- a/audio/drivers/openal.c +++ b/audio/drivers/openal.c @@ -163,29 +163,29 @@ static bool al_get_buffer(al_t *al, ALuint *buffer) return true; } -static size_t al_fill_internal_buf(al_t *al, const void *buf, size_t size) +static size_t al_fill_internal_buf(al_t *al, const void *s, size_t len) { - size_t read_size = MIN(OPENAL_BUFSIZE - al->tmpbuf_ptr, size); - memcpy(al->tmpbuf + al->tmpbuf_ptr, buf, read_size); + size_t read_size = MIN(OPENAL_BUFSIZE - al->tmpbuf_ptr, len); + memcpy(al->tmpbuf + al->tmpbuf_ptr, s, read_size); al->tmpbuf_ptr += read_size; return read_size; } -static ssize_t al_write(void *data, const void *buf_, size_t size) +static ssize_t al_write(void *data, const void *s, size_t len) { al_t *al = (al_t*)data; - const uint8_t *buf = (const uint8_t*)buf_; + const uint8_t *buf = (const uint8_t*)s; size_t written = 0; - while (size) + while (len) { ALint val; ALuint buffer; - size_t rc = al_fill_internal_buf(al, buf, size); + size_t rc = al_fill_internal_buf(al, buf, len); written += rc; buf += rc; - size -= rc; + len -= rc; if (al->tmpbuf_ptr != OPENAL_BUFSIZE) break; @@ -254,11 +254,7 @@ static size_t al_buffer_size(void *data) return (al->num_buffers + 1) * OPENAL_BUFSIZE; /* Also got tmpbuf. */ } -static bool al_use_float(void *data) -{ - (void)data; - return false; -} +static bool al_use_float(void *data) { return false; } audio_driver_t audio_openal = { al_init, diff --git a/audio/drivers/opensl.c b/audio/drivers/opensl.c index 70f5846538..4cd884034d 100644 --- a/audio/drivers/opensl.c +++ b/audio/drivers/opensl.c @@ -232,13 +232,13 @@ static bool sl_start(void *data, bool is_shutdown) return sl->is_paused ? false : true; } -static ssize_t sl_write(void *data, const void *buf_, size_t size) +static ssize_t sl_write(void *data, const void *s, size_t len) { sl_t *sl = (sl_t*)data; size_t written = 0; - const uint8_t *buf = (const uint8_t*)buf_; + const uint8_t *buf = (const uint8_t*)s; - while (size) + while (len) { size_t avail_write; @@ -255,14 +255,14 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size) slock_unlock(sl->lock); } - avail_write = MIN(sl->buf_size - sl->buffer_ptr, size); + avail_write = MIN(sl->buf_size - sl->buffer_ptr, len); if (avail_write) { memcpy(sl->buffer[sl->buffer_index] + sl->buffer_ptr, buf, avail_write); sl->buffer_ptr += avail_write; buf += avail_write; - size -= avail_write; + len -= avail_write; written += avail_write; } @@ -287,8 +287,7 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size) static size_t sl_write_avail(void *data) { sl_t *sl = (sl_t*)data; - size_t avail = (sl->buf_count - (int)sl->buffered_blocks - 1) * sl->buf_size + (sl->buf_size - (int)sl->buffer_ptr); - return avail; + return ((sl->buf_count - (int)sl->buffered_blocks - 1) * sl->buf_size + (sl->buf_size - (int)sl->buffer_ptr)); } static size_t sl_buffer_size(void *data) @@ -297,11 +296,7 @@ static size_t sl_buffer_size(void *data) return sl->buf_size * sl->buf_count; } -static bool sl_use_float(void *data) -{ - (void)data; - return false; -} +static bool sl_use_float(void *data) { return false; } audio_driver_t audio_opensl = { sl_init, diff --git a/audio/drivers/oss.c b/audio/drivers/oss.c index 52b525ac34..1bda5b63fe 100644 --- a/audio/drivers/oss.c +++ b/audio/drivers/oss.c @@ -103,15 +103,15 @@ error: return NULL; } -static ssize_t oss_write(void *data, const void *buf, size_t size) +static ssize_t oss_write(void *data, const void *s, size_t len) { ssize_t ret; oss_audio_t *ossaudio = (oss_audio_t*)data; - if (size == 0) + if (len == 0) return 0; - if ((ret = write(ossaudio->fd, buf, size)) < 0) + if ((ret = write(ossaudio->fd, s, len)) < 0) { if (errno == EAGAIN && (fcntl(ossaudio->fd, F_GETFL) & O_NONBLOCK)) return 0; @@ -169,7 +169,7 @@ static void oss_free(void *data) { oss_audio_t *ossaudio = (oss_audio_t*)data; -/*RETROFW IOCTL always returns EINVAL*/ +/*RETROFW IOCTL always returns EINVAL*/ #if !defined(RETROFW) if (ioctl(ossaudio->fd, SNDCTL_DSP_RESET, 0) < 0) return; @@ -209,7 +209,6 @@ static size_t oss_buffer_size(void *data) static bool oss_use_float(void *data) { - (void)data; return false; } diff --git a/audio/drivers/pipewire.c b/audio/drivers/pipewire.c index 872c24930f..e35548d736 100644 --- a/audio/drivers/pipewire.c +++ b/audio/drivers/pipewire.c @@ -1,5 +1,5 @@ /* RetroArch - A frontend for libretro. - * Copyright (C) 2024 - Viachaslau Khalikin + * Copyright (C) 2024-2025 - Viachaslau Khalikin * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -13,48 +13,38 @@ * If not, see . */ -#include -#include - -#include -#include - #include #include #include #include - #include #include +#include #include #include -#include "audio/common/pipewire.h" -#include "audio/audio_driver.h" -#include "verbosity.h" +#include "../common/pipewire.h" +#include "../audio_driver.h" +#include "../../verbosity.h" #define DEFAULT_CHANNELS 2 -#define QUANTUM 1024 /* TODO: detect */ #define RINGBUFFER_SIZE (1u << 22) #define RINGBUFFER_MASK (RINGBUFFER_SIZE - 1) typedef struct pipewire_audio { pipewire_core_t *pw; - struct pw_stream *stream; struct spa_hook stream_listener; struct spa_audio_info_raw info; uint32_t highwater_mark; uint32_t frame_size; - uint32_t req; struct spa_ringbuffer ring; uint8_t buffer[RINGBUFFER_SIZE]; } pipewire_audio_t; - static void stream_destroy_cb(void *data) { pipewire_audio_t *audio = (pipewire_audio_t*)data; @@ -68,32 +58,28 @@ static void playback_process_cb(void *data) void *p; struct pw_buffer *b; struct spa_buffer *buf; - uint32_t req, index, n_bytes; + uint32_t req, idx, n_bytes; int32_t avail; + retro_assert(audio); retro_assert(audio->stream); if ((b = pw_stream_dequeue_buffer(audio->stream)) == NULL) { - RARCH_WARN("[PipeWire]: Out of buffers: %s\n", strerror(errno)); - return; + RARCH_WARN("[Audio] [PipeWire]: Out of buffers: %s\n", strerror(errno)); + return pw_thread_loop_signal(audio->pw->thread_loop, false); } buf = b->buffer; - p = buf->datas[0].data; - if (p == NULL) - return; + if ((p = buf->datas[0].data) == NULL) + return pw_thread_loop_signal(audio->pw->thread_loop, false); /* calculate the total no of bytes to read data from buffer */ - req = b->requested * audio->frame_size; + n_bytes = buf->datas[0].maxsize; + if (b->requested) + n_bytes = MIN(b->requested * audio->frame_size, n_bytes); - if (req == 0) - req = audio->req; - - n_bytes = SPA_MIN(req, buf->datas[0].maxsize); - - /* get no of available bytes to read data from buffer */ - avail = spa_ringbuffer_get_read_index(&audio->ring, &index); + avail = spa_ringbuffer_get_read_index(&audio->ring, &idx); if (avail <= 0) /* fill rest buffer with silence */ @@ -105,18 +91,18 @@ static void playback_process_cb(void *data) spa_ringbuffer_read_data(&audio->ring, audio->buffer, RINGBUFFER_SIZE, - index & RINGBUFFER_MASK, p, n_bytes); + idx & RINGBUFFER_MASK, p, n_bytes); - index += n_bytes; - spa_ringbuffer_read_update(&audio->ring, index); + idx += n_bytes; + spa_ringbuffer_read_update(&audio->ring, idx); } buf->datas[0].chunk->offset = 0; buf->datas[0].chunk->stride = audio->frame_size; buf->datas[0].chunk->size = n_bytes; - /* queue the buffer for playback */ pw_stream_queue_buffer(audio->stream, b); + pw_thread_loop_signal(audio->pw->thread_loop, false); } static void pipewire_free(void *data); @@ -126,27 +112,11 @@ static void stream_state_changed_cb(void *data, { pipewire_audio_t *audio = (pipewire_audio_t*)data; - RARCH_DBG("[PipeWire]: New state for Sink Node %d : %s\n", - pw_stream_get_node_id(audio->stream), + RARCH_DBG("[Audio] [PipeWire]: Stream state changed %s -> %s\n", + pw_stream_state_as_string(old), pw_stream_state_as_string(state)); - switch(state) - { - case PW_STREAM_STATE_ERROR: - RARCH_ERR("[PipeWire]: Stream error\n"); - pw_thread_loop_signal(audio->pw->thread_loop, false); - break; - case PW_STREAM_STATE_UNCONNECTED: - RARCH_WARN("[PipeWire]: Stream unconnected\n"); - pw_thread_loop_stop(audio->pw->thread_loop); - break; - case PW_STREAM_STATE_STREAMING: - case PW_STREAM_STATE_PAUSED: - pw_thread_loop_signal(audio->pw->thread_loop, false); - break; - default: - break; - } + pw_thread_loop_signal(audio->pw->thread_loop, false); } static const struct pw_stream_events playback_stream_events = { @@ -156,60 +126,30 @@ static const struct pw_stream_events playback_stream_events = { .state_changed = stream_state_changed_cb, }; -static void client_info_cb(void *data, const struct pw_client_info *info) -{ - const struct spa_dict_item *item; - pipewire_core_t *pw = (pipewire_core_t*)data; - - RARCH_DBG("[PipeWire]: client: id:%u\n", info->id); - RARCH_DBG("[PipeWire]: \tprops:\n"); - spa_dict_for_each(item, info->props) - RARCH_DBG("[PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value); - - pw_thread_loop_signal(pw->thread_loop, false); -} - -static const struct pw_client_events client_events = { - PW_VERSION_CLIENT_EVENTS, - .info = client_info_cb, -}; - static void registry_event_global(void *data, uint32_t id, uint32_t permissions, const char *type, uint32_t version, const struct spa_dict *props) { union string_list_elem_attr attr; + const struct spa_dict_item *item; pipewire_core_t *pw = (pipewire_core_t*)data; - const char *media = NULL; const char *sink = NULL; - if (!pw->client && spa_streq(type, PW_TYPE_INTERFACE_Client)) + if (spa_streq(type, PW_TYPE_INTERFACE_Node) + && spa_streq("Audio/Sink", spa_dict_lookup(props, PW_KEY_MEDIA_CLASS))) { - pw->client = pw_registry_bind(pw->registry, - id, type, PW_VERSION_CLIENT, 0); - pw_client_add_listener(pw->client, - &pw->client_listener, - &client_events, pw); - } - else if (spa_streq(type, PW_TYPE_INTERFACE_Node)) - { - media = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS); - if (media && strcmp(media, "Audio/Sink") == 0) + sink = spa_dict_lookup(props, PW_KEY_NODE_NAME); + if (sink && pw->devicelist) { - sink = spa_dict_lookup(props, PW_KEY_NODE_NAME); - if (sink && pw->devicelist) - { - attr.i = id; - string_list_append(pw->devicelist, sink, attr); - RARCH_LOG("[PipeWire]: Found Sink Node: %s\n", sink); - } + attr.i = id; + string_list_append(pw->devicelist, sink, attr); + RARCH_LOG("[Audio] [PipeWire]: Found Sink Node: %s\n", sink); } - } - const struct spa_dict_item *item; - RARCH_DBG("[PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version); - spa_dict_for_each(item, props) - RARCH_DBG("[PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value); + RARCH_DBG("[Audio] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version); + spa_dict_for_each(item, props) + RARCH_DBG("[Audio] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value); + } } static const struct pw_registry_events registry_events = { @@ -229,26 +169,22 @@ static void *pipewire_init(const char *device, unsigned rate, struct pw_properties *props = NULL; const char *error = NULL; pipewire_audio_t *audio = (pipewire_audio_t*)calloc(1, sizeof(*audio)); - pipewire_core_t *pw = NULL; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - pw_init(NULL, NULL); - if (!audio) goto error; - pw = audio->pw = (pipewire_core_t*)calloc(1, sizeof(*audio->pw)); - pw->devicelist = string_list_new(); - - if (!pipewire_core_init(pw, "audio_driver")) + if (!pipewire_core_init(&audio->pw, "audio_driver", ®istry_events)) goto error; + /* unlock, run the loop and wait, this will trigger the callbacks */ + pipewire_core_wait_resync(audio->pw); + audio->info.format = is_little_endian() ? SPA_AUDIO_FORMAT_F32_LE : SPA_AUDIO_FORMAT_F32_BE; audio->info.channels = DEFAULT_CHANNELS; - set_position(DEFAULT_CHANNELS, audio->info.position); + pipewire_set_position(DEFAULT_CHANNELS, audio->info.position); audio->info.rate = rate; - audio->frame_size = calc_frame_size(audio->info.format, DEFAULT_CHANNELS); - audio->req = QUANTUM * rate * 1 / 2 / 100000 * audio->frame_size; + audio->frame_size = pipewire_calc_frame_size(audio->info.format, DEFAULT_CHANNELS); props = pw_properties_new(PW_KEY_MEDIA_TYPE, PW_RARCH_MEDIA_TYPE_AUDIO, PW_KEY_MEDIA_CATEGORY, PW_RARCH_MEDIA_CATEGORY_PLAYBACK, @@ -260,22 +196,18 @@ static void *pipewire_init(const char *device, unsigned rate, PW_KEY_APP_ICON_NAME, PW_RARCH_APPNAME, NULL); if (!props) - goto error; + goto unlock_error; if (device) pw_properties_set(props, PW_KEY_TARGET_OBJECT, device); - buf_samples = QUANTUM * rate * 3 / 4 / 100000; - - pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%" PRIu64 "/%u", - buf_samples, rate); - + buf_samples = latency * rate / 1000; + pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%" PRIu64 "/%u", buf_samples, rate); pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", rate); - - audio->stream = pw_stream_new(pw->core, PW_RARCH_APPNAME, props); + audio->stream = pw_stream_new(audio->pw->core, PW_RARCH_APPNAME, props); if (!audio->stream) - goto error; + goto unlock_error; pw_stream_add_listener(audio->stream, &audio->stream_listener, &playback_stream_events, audio); @@ -290,99 +222,149 @@ static void *pipewire_init(const char *device, unsigned rate, PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS, params, 1); - if (res < 0) - goto error; + goto unlock_error; audio->highwater_mark = MIN(RINGBUFFER_SIZE, - latency? (latency * 1000): 46440 * (uint64_t)rate / 1000000 * audio->frame_size); - RARCH_DBG("[PipeWire]: Bufer size: %u, RingBuffer size: %u\n", audio->highwater_mark, RINGBUFFER_SIZE); + latency * (uint64_t)rate / 1000 * audio->frame_size); - pw->registry = pw_core_get_registry(pw->core, PW_VERSION_REGISTRY, 0); + pw_thread_loop_wait(audio->pw->thread_loop); + pw_thread_loop_unlock(audio->pw->thread_loop); - spa_zero(pw->registry_listener); - pw_registry_add_listener(pw->registry, &pw->registry_listener, ®istry_events, pw); - - /* unlock, run the loop and wait, this will trigger the callbacks */ - pipewire_wait_resync(pw); - pw_thread_loop_unlock(pw->thread_loop); + *new_rate = audio->info.rate; return audio; +unlock_error: + pw_thread_loop_unlock(audio->pw->thread_loop); error: - RARCH_ERR("[PipeWire]: Failed to initialize audio\n"); + RARCH_ERR("[Audio] [PipeWire]: Failed to initialize audio\n"); pipewire_free(audio); return NULL; } -static ssize_t pipewire_write(void *data, const void *buf_, size_t size) +static ssize_t pipewire_write(void *data, const void *buf_, size_t len) { - int32_t writable; - int32_t avail; - uint32_t index; + int32_t filled, avail; + uint32_t idx; pipewire_audio_t *audio = (pipewire_audio_t*)data; const char *error = NULL; if (pw_stream_get_state(audio->stream, &error) != PW_STREAM_STATE_STREAMING) return 0; /* wait for stream to become ready */ + if (len > audio->highwater_mark) + { + RARCH_ERR("[Audio] [PipeWire]: Buffer too small! Please try increasing the latency.\n"); + return 0; + } + pw_thread_loop_lock(audio->pw->thread_loop); - writable = spa_ringbuffer_get_write_index(&audio->ring, &index); - avail = audio->highwater_mark - writable; + + for (;;) + { + filled = spa_ringbuffer_get_write_index(&audio->ring, &idx); + avail = audio->highwater_mark - filled; #if 0 /* Useful for tracing */ - RARCH_DBG("[PipeWire]: Playback progress: written %d, avail %d, index %d, size %d\n", - writable, avail, index, size); + RARCH_DBG("[Audio] [PipeWire]: Ringbuffer utilization: filled %d, avail %d, index %d, size %d\n", + filled, avail, idx, len); #endif - if (size > (size_t)avail) - size = avail; + /* in non-blocking mode we play as much as we can + * in blocking mode we expect a freed buffer of at least the given size */ + if (len > (size_t)avail) + { + if (audio->pw->nonblock) + { + len = avail; + break; + } - if (writable < 0) - RARCH_ERR("%p: underrun write:%u filled:%d\n", audio, index, writable); + pw_thread_loop_wait(audio->pw->thread_loop); + if (pw_stream_get_state(audio->stream, &error) != PW_STREAM_STATE_STREAMING) + { + pw_thread_loop_unlock(audio->pw->thread_loop); + return -1; + } + } + else + break; + } + + if (filled < 0) + RARCH_ERR("[Audio] [Pipewire]: %p: underrun write:%u filled:%d\n", audio, idx, filled); else { - if ((uint32_t) writable + size > RINGBUFFER_SIZE) + if ((uint32_t) filled + len > RINGBUFFER_SIZE) { - RARCH_ERR("%p: overrun write:%u filled:%d + size:%zu > max:%u\n", - audio, index, writable, size, RINGBUFFER_SIZE); + RARCH_ERR("[Audio] [PipeWire]: %p: overrun write:%u filled:%d + size:%zu > max:%u\n", + audio, idx, filled, len, RINGBUFFER_SIZE); } } spa_ringbuffer_write_data(&audio->ring, audio->buffer, RINGBUFFER_SIZE, - index & RINGBUFFER_MASK, buf_, size); - index += size; - spa_ringbuffer_write_update(&audio->ring, index); + idx & RINGBUFFER_MASK, buf_, len); + idx += len; + spa_ringbuffer_write_update(&audio->ring, idx); pw_thread_loop_unlock(audio->pw->thread_loop); - return size; + return len; } static bool pipewire_stop(void *data) { pipewire_audio_t *audio = (pipewire_audio_t*)data; const char *error = NULL; - if (pw_stream_get_state(audio->stream, &error) == PW_STREAM_STATE_PAUSED) - return true; + bool res = false; - return pipewire_set_active(audio->pw->thread_loop, audio->stream, false); + if (!audio || !audio->pw) + return false; + + if (pw_stream_get_state(audio->stream, &error) == PW_STREAM_STATE_STREAMING) + res = pipewire_stream_set_active(audio->pw->thread_loop, audio->stream, false); + else + /* For other states we assume that the stream is inactive */ + res = true; + + spa_ringbuffer_read_update(&audio->ring, 0); + spa_ringbuffer_write_update(&audio->ring, 0); + + return res; } static bool pipewire_start(void *data, bool is_shutdown) { + enum pw_stream_state st; pipewire_audio_t *audio = (pipewire_audio_t*)data; const char *error = NULL; - if (pw_stream_get_state(audio->stream, &error) == PW_STREAM_STATE_STREAMING) - return true; + bool res = false; - return pipewire_set_active(audio->pw->thread_loop, audio->stream, true); + if (!audio || !audio->pw) + return false; + + st = pw_stream_get_state(audio->stream, &error); + switch (st) + { + case PW_STREAM_STATE_STREAMING: + res = true; + break; + case PW_STREAM_STATE_PAUSED: + res = pipewire_stream_set_active(audio->pw->thread_loop, audio->stream, true); + break; + default: + break; + } + + return res; } static bool pipewire_alive(void *data) { pipewire_audio_t *audio = (pipewire_audio_t*)data; const char *error = NULL; + if (!audio) return false; @@ -401,48 +383,20 @@ static void pipewire_free(void *data) pipewire_audio_t *audio = (pipewire_audio_t*)data; if (!audio) - return pw_deinit(); - - if (audio->pw->thread_loop) - pw_thread_loop_stop(audio->pw->thread_loop); + return; if (audio->stream) { + pw_thread_loop_lock(audio->pw->thread_loop); pw_stream_destroy(audio->stream); audio->stream = NULL; + pw_thread_loop_unlock(audio->pw->thread_loop); } - - if (audio->pw->client) - pw_proxy_destroy((struct pw_proxy *)audio->pw->client); - - if (audio->pw->registry) - pw_proxy_destroy((struct pw_proxy*)audio->pw->registry); - - if (audio->pw->core) - { - spa_hook_remove(&audio->pw->core_listener); - spa_zero(audio->pw->core_listener); - pw_core_disconnect(audio->pw->core); - } - - if (audio->pw->ctx) - pw_context_destroy(audio->pw->ctx); - - pw_thread_loop_destroy(audio->pw->thread_loop); - - if (audio->pw->devicelist) - string_list_free(audio->pw->devicelist); - - free(audio->pw); + pipewire_core_deinit(audio->pw); free(audio); - pw_deinit(); } -static bool pipewire_use_float(void *data) -{ - (void)data; - return true; -} +static bool pipewire_use_float(void *data) { return true; } static void *pipewire_device_list_new(void *data) { @@ -464,7 +418,7 @@ static void pipewire_device_list_free(void *data, void *array_list_data) static size_t pipewire_write_avail(void *data) { - uint32_t index, written, length; + uint32_t idx, written, length; pipewire_audio_t *audio = (pipewire_audio_t*)data; const char *error = NULL; @@ -475,7 +429,7 @@ static size_t pipewire_write_avail(void *data) return 0; /* wait for stream to become ready */ pw_thread_loop_lock(audio->pw->thread_loop); - written = spa_ringbuffer_get_write_index(&audio->ring, &index); + written = spa_ringbuffer_get_write_index(&audio->ring, &idx); length = audio->highwater_mark - written; pw_thread_loop_unlock(audio->pw->thread_loop); diff --git a/audio/drivers/ps2_audio.c b/audio/drivers/ps2_audio.c index 786b2a49b4..4c841b09fe 100644 --- a/audio/drivers/ps2_audio.c +++ b/audio/drivers/ps2_audio.c @@ -71,14 +71,12 @@ static void ps2_audio_free(void *data) free(ps2); } -static ssize_t ps2_audio_write(void *data, const void *buf, size_t size) +static ssize_t ps2_audio_write(void *data, const void *s, size_t len) { ps2_audio_t* ps2 = (ps2_audio_t*)data; - if (!ps2->running) return -1; - - return audsrv_play_audio(buf, size); + return audsrv_play_audio(s, len); } static bool ps2_audio_alive(void *data) diff --git a/audio/drivers/ps3_audio.c b/audio/drivers/ps3_audio.c index da7a82345b..9168629a68 100644 --- a/audio/drivers/ps3_audio.c +++ b/audio/drivers/ps3_audio.c @@ -142,24 +142,23 @@ static void *ps3_audio_init(const char *device, return data; } -static ssize_t ps3_audio_write(void *data, const void *buf, size_t size) +static ssize_t ps3_audio_write(void *data, const void *s, size_t len) { ps3_audio_t *aud = data; if (aud->nonblock) { - if (FIFO_WRITE_AVAIL(aud->buffer) < size) + if (FIFO_WRITE_AVAIL(aud->buffer) < len) return 0; } - while (FIFO_WRITE_AVAIL(aud->buffer) < size) + while (FIFO_WRITE_AVAIL(aud->buffer) < len) sysLwCondWait(&aud->cond, 0); sysLwMutexLock(&aud->lock, PS3_SYS_NO_TIMEOUT); - fifo_write(aud->buffer, buf, size); + fifo_write(aud->buffer, s, len); sysLwMutexUnlock(&aud->lock); - - return size; + return len; } static bool ps3_audio_stop(void *data) @@ -220,10 +219,7 @@ static void ps3_audio_free(void *data) free(data); } -static bool ps3_audio_use_float(void *data) -{ - return true; -} +static bool ps3_audio_use_float(void *data) { return true; } static size_t ps3_audio_write_avail(void *data) { diff --git a/audio/drivers/psp_audio.c b/audio/drivers/psp_audio.c index e6f8e2c174..9bd2089d7b 100644 --- a/audio/drivers/psp_audio.c +++ b/audio/drivers/psp_audio.c @@ -202,11 +202,11 @@ static void psp_audio_free(void *data) } -static ssize_t psp_audio_write(void *data, const void *buf, size_t size) +static ssize_t psp_audio_write(void *data, const void *s, size_t len) { psp_audio_t* psp = (psp_audio_t*)data; uint16_t write_pos = psp->write_pos; - uint16_t sampleCount = size / sizeof(uint32_t); + uint16_t sampleCount = len / sizeof(uint32_t); if (!psp->running) return -1; @@ -214,35 +214,34 @@ static ssize_t psp_audio_write(void *data, const void *buf, size_t size) if (psp->nonblock) { if (AUDIO_BUFFER_SIZE - ((uint16_t) - (psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < size) + (psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < len) return 0; } slock_lock(psp->cond_lock); while (AUDIO_BUFFER_SIZE - ((uint16_t) - (psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < size) + (psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < len) scond_wait(psp->cond, psp->cond_lock); slock_unlock(psp->cond_lock); slock_lock(psp->fifo_lock); if ((write_pos + sampleCount) > AUDIO_BUFFER_SIZE) { - memcpy(psp->buffer + write_pos, buf, + memcpy(psp->buffer + write_pos, s, (AUDIO_BUFFER_SIZE - write_pos) * sizeof(uint32_t)); - memcpy(psp->buffer, (uint32_t*) buf + + memcpy(psp->buffer, (uint32_t*)s + (AUDIO_BUFFER_SIZE - write_pos), (write_pos + sampleCount - AUDIO_BUFFER_SIZE) * sizeof(uint32_t)); } else - memcpy(psp->buffer + write_pos, buf, size); + memcpy(psp->buffer + write_pos, s, len); write_pos += sampleCount; write_pos &= AUDIO_BUFFER_SIZE_MASK; psp->write_pos = write_pos; slock_unlock(psp->fifo_lock); - return size; - + return len; } static bool psp_audio_alive(void *data) diff --git a/audio/drivers/pulse.c b/audio/drivers/pulse.c index b680f05a1d..db1b2b4fe1 100644 --- a/audio/drivers/pulse.c +++ b/audio/drivers/pulse.c @@ -142,7 +142,7 @@ static void stream_state_cb(pa_stream *s, void *data) } } -static void stream_request_cb(pa_stream *s, size_t length, void *data) +static void stream_request_cb(pa_stream *s, size_t len, void *data) { pa_t *pa = (pa_t*)data; pa_threaded_mainloop_signal(pa->mainloop, 0); @@ -276,11 +276,31 @@ error: return NULL; } -static bool pulse_start(void *data, bool is_shutdown); -static ssize_t pulse_write(void *data, const void *buf_, size_t size) +static bool pulse_start(void *data, bool is_shutdown) +{ + bool ret; + pa_t *pa = (pa_t*)data; + + if (!pa->is_ready) + return false; + if (!pa->is_paused) + return true; + + pa->success = true; /* In case of spurious wakeup. Not critical. */ + pa_threaded_mainloop_lock(pa->mainloop); + pa_stream_cork(pa->stream, false, stream_success_cb, pa); + pa_threaded_mainloop_wait(pa->mainloop); + ret = pa->success; + pa_threaded_mainloop_unlock(pa->mainloop); + pa->is_paused = false; + return ret; +} + + +static ssize_t pulse_write(void *data, const void *s, size_t len) { pa_t *pa = (pa_t*)data; - const uint8_t *buf = (const uint8_t*)buf_; + const uint8_t *buf = (const uint8_t*)s; size_t written = 0; /* Workaround buggy menu code. @@ -293,15 +313,15 @@ static ssize_t pulse_write(void *data, const void *buf_, size_t size) return 0; pa_threaded_mainloop_lock(pa->mainloop); - while (size) + while (len) { - size_t writable = MIN(size, pa_stream_writable_size(pa->stream)); + size_t writable = MIN(len, pa_stream_writable_size(pa->stream)); if (writable) { pa_stream_write(pa->stream, buf, writable, NULL, 0, PA_SEEK_RELATIVE); - buf += writable; - size -= writable; + buf += writable; + len -= writable; written += writable; } else if (!pa->nonblock) @@ -344,26 +364,6 @@ static bool pulse_alive(void *data) return !pa->is_paused; } -static bool pulse_start(void *data, bool is_shutdown) -{ - bool ret; - pa_t *pa = (pa_t*)data; - - if (!pa->is_ready) - return false; - if (!pa->is_paused) - return true; - - pa->success = true; /* In case of spurious wakeup. Not critical. */ - pa_threaded_mainloop_lock(pa->mainloop); - pa_stream_cork(pa->stream, false, stream_success_cb, pa); - pa_threaded_mainloop_wait(pa->mainloop); - ret = pa->success; - pa_threaded_mainloop_unlock(pa->mainloop); - pa->is_paused = false; - return ret; -} - static void pulse_set_nonblock_state(void *data, bool state) { pa_t *pa = (pa_t*)data; @@ -371,11 +371,7 @@ static void pulse_set_nonblock_state(void *data, bool state) pa->nonblock = state; } -static bool pulse_use_float(void *data) -{ - (void)data; - return true; -} +static bool pulse_use_float(void *data) { return true; } static size_t pulse_write_avail(void *data) { diff --git a/audio/drivers/roar.c b/audio/drivers/roar.c index 9110fdfb10..6e3a58bac9 100644 --- a/audio/drivers/roar.c +++ b/audio/drivers/roar.c @@ -56,19 +56,19 @@ static void *ra_init(const char *device, unsigned rate, unsigned latency, return roar; } -static ssize_t ra_write(void *data, const void *buf, size_t size) +static ssize_t ra_write(void *data, const void *buf, size_t len) { int err; size_t written = 0; roar_t *roar = (roar_t*)data; - if (size == 0) + if (len == 0) return 0; - while (written < size) + while (written < len) { ssize_t rc; - size_t write_amt = size - written; + size_t write_amt = len - written; if ((rc = roar_vs_write(roar->vss, (const char*)buf + written, write_amt, &err)) < (ssize_t)write_amt) @@ -81,7 +81,7 @@ static ssize_t ra_write(void *data, const void *buf, size_t size) written += rc; } - return size; + return len; } static bool ra_stop(void *data) diff --git a/audio/drivers/rsound.c b/audio/drivers/rsound.c index fbc6f749a7..4133d3d505 100644 --- a/audio/drivers/rsound.c +++ b/audio/drivers/rsound.c @@ -101,7 +101,7 @@ error: return NULL; } -static ssize_t rs_write(void *data, const void *buf, size_t size) +static ssize_t rs_write(void *data, const void *buf, size_t len) { rsd_t *rsd = (rsd_t*)data; @@ -115,7 +115,7 @@ static ssize_t rs_write(void *data, const void *buf, size_t size) rsd_callback_lock(rsd->rd); avail = FIFO_WRITE_AVAIL(rsd->buffer); - write_amt = avail > size ? size : avail; + write_amt = avail > len ? len : avail; fifo_write(rsd->buffer, buf, write_amt); rsd_callback_unlock(rsd->rd); @@ -124,7 +124,7 @@ static ssize_t rs_write(void *data, const void *buf, size_t size) else { size_t written = 0; - while (written < size && !rsd->has_error) + while (written < len && !rsd->has_error) { size_t avail; rsd_callback_lock(rsd->rd); @@ -143,7 +143,7 @@ static ssize_t rs_write(void *data, const void *buf, size_t size) } else { - size_t write_amt = size - written > avail ? avail : size - written; + size_t write_amt = len - written > avail ? avail : len - written; fifo_write(rsd->buffer, (const char*)buf + written, write_amt); rsd_callback_unlock(rsd->rd); written += write_amt; diff --git a/audio/drivers/rsound.h b/audio/drivers/rsound.h index 9da47155e1..e349093183 100644 --- a/audio/drivers/rsound.h +++ b/audio/drivers/rsound.h @@ -286,7 +286,7 @@ int rsd_stop (rsound_t *rd); or there was an unexpected error. This function will block until all data has been written to the buffer. This function will return the number of bytes written to the buffer, or 0 should it fail (disconnection from server). You will have to restart the stream again should this occur. */ -size_t rsd_write (rsound_t *rd, const void* buf, size_t size); +size_t rsd_write (rsound_t *rd, const void *s, size_t len); /* Gets the position of the buffer pointer. Not really interesting for normal applications. diff --git a/audio/drivers/rwebaudio.c b/audio/drivers/rwebaudio.c index 41cf2d1ea6..486398781b 100644 --- a/audio/drivers/rwebaudio.c +++ b/audio/drivers/rwebaudio.c @@ -23,7 +23,7 @@ /* forward declarations */ unsigned RWebAudioSampleRate(void); void *RWebAudioInit(unsigned latency); -ssize_t RWebAudioWrite(const void *buf, size_t size); +ssize_t RWebAudioWrite(const void *s, size_t len); bool RWebAudioStop(void); bool RWebAudioStart(void); void RWebAudioSetNonblockState(bool state); @@ -54,9 +54,9 @@ static void *rwebaudio_init(const char *device, unsigned rate, unsigned latency, return rwebaudio; } -static ssize_t rwebaudio_write(void *data, const void *buf, size_t size) +static ssize_t rwebaudio_write(void *data, const void *s, size_t len) { - return RWebAudioWrite(buf, size); + return RWebAudioWrite(s, len); } static bool rwebaudio_stop(void *data) diff --git a/audio/drivers/sdl_audio.c b/audio/drivers/sdl_audio.c index 998e9ff48f..708cfee409 100644 --- a/audio/drivers/sdl_audio.c +++ b/audio/drivers/sdl_audio.c @@ -82,30 +82,25 @@ static void sdl_audio_playback_cb(void *data, Uint8 *stream, int len) { sdl_audio_t *sdl = (sdl_audio_t*)data; size_t avail = FIFO_READ_AVAIL(sdl->speaker_buffer); - size_t write_size = (len > (int)avail) ? avail : (size_t)len; - - fifo_read(sdl->speaker_buffer, stream, write_size); + size_t _len = (len > (int)avail) ? avail : (size_t)len; + fifo_read(sdl->speaker_buffer, stream, _len); #ifdef HAVE_THREADS scond_signal(sdl->cond); #endif - /* If underrun, fill rest with silence. */ - memset(stream + write_size, 0, len - write_size); + memset(stream + _len, 0, len - _len); } static INLINE int sdl_audio_find_num_frames(int rate, int latency) { int frames = (rate * latency) / 1000; - /* SDL only likes 2^n sized buffers. */ - return next_pow2(frames); } static void *sdl_audio_init(const char *device, unsigned rate, unsigned latency, - unsigned block_frames, - unsigned *new_rate) + unsigned block_frames, unsigned *new_rate) { int frames; size_t bufsize; @@ -115,8 +110,6 @@ static void *sdl_audio_init(const char *device, sdl_audio_t *sdl = NULL; uint32_t sdl_subsystem_flags = SDL_WasInit(0); - (void)device; - /* Initialise audio subsystem, if required */ if (sdl_subsystem_flags == 0) { @@ -215,53 +208,53 @@ error: return NULL; } -static ssize_t sdl_audio_write(void *data, const void *buf, size_t size) +static ssize_t sdl_audio_write(void *data, const void *s, size_t len) { ssize_t ret = 0; sdl_audio_t *sdl = (sdl_audio_t*)data; + /* If we shouldn't wait for space in a full outgoing sample queue... */ if (sdl->nonblock) - { /* If we shouldn't wait for space in a full outgoing sample queue... */ + { size_t avail, write_amt; - SDL_LockAudioDevice(sdl->speaker_device); /* Stop the SDL speaker thread from running */ - avail = FIFO_WRITE_AVAIL(sdl->speaker_buffer); - write_amt = avail > size ? size : avail; /* Enqueue as much data as we can */ - fifo_write(sdl->speaker_buffer, buf, write_amt); + avail = FIFO_WRITE_AVAIL(sdl->speaker_buffer); + write_amt = (avail > len) ? len : avail; /* Enqueue as much data as we can */ + fifo_write(sdl->speaker_buffer, s, write_amt); SDL_UnlockAudioDevice(sdl->speaker_device); /* Let the speaker thread run again */ - ret = write_amt; /* If the queue was full...well, too bad. */ + ret = write_amt; /* If the queue was full...well, too bad. */ } else { size_t written = 0; - - while (written < size) - { /* Until we've written all the sample data we have available... */ + /* Until we've written all the sample data we have available... */ + while (written < len) + { size_t avail; - SDL_LockAudioDevice(sdl->speaker_device); /* Stop the SDL speaker thread from running */ + /* Stop the SDL speaker thread from running */ + SDL_LockAudioDevice(sdl->speaker_device); avail = FIFO_WRITE_AVAIL(sdl->speaker_buffer); + /* If the outgoing sample queue is full... */ if (avail == 0) - { /* If the outgoing sample queue is full... */ + { SDL_UnlockAudioDevice(sdl->speaker_device); /* Let the SDL speaker thread run so it can play the enqueued samples, * which will free up space for us to write new ones. */ #ifdef HAVE_THREADS slock_lock(sdl->lock); /* Let *only* the SDL speaker thread touch the outgoing sample queue */ - scond_wait(sdl->cond, sdl->lock); /* Block until SDL tells us that it's made room for new samples */ - slock_unlock(sdl->lock); /* Now let this thread use the outgoing sample queue (which we'll do next iteration) */ #endif } else { - size_t write_amt = size - written > avail ? avail : size - written; - fifo_write(sdl->speaker_buffer, (const char*)buf + written, write_amt); + size_t write_amt = len - written > avail ? avail : len - written; + fifo_write(sdl->speaker_buffer, (const char*)s + written, write_amt); /* Enqueue as many samples as we have available without overflowing the queue */ SDL_UnlockAudioDevice(sdl->speaker_device); /* Let the SDL speaker thread run again */ written += write_amt; @@ -276,9 +269,8 @@ static ssize_t sdl_audio_write(void *data, const void *buf, size_t size) static bool sdl_audio_stop(void *data) { sdl_audio_t *sdl = (sdl_audio_t*)data; - sdl->is_paused = true; + sdl->is_paused = true; SDL_PauseAudioDevice(sdl->speaker_device, true); - return true; } @@ -293,10 +285,8 @@ static bool sdl_audio_alive(void *data) static bool sdl_audio_start(void *data, bool is_shutdown) { sdl_audio_t *sdl = (sdl_audio_t*)data; - sdl->is_paused = false; - + sdl->is_paused = false; SDL_PauseAudioDevice(sdl->speaker_device, false); - return true; } @@ -319,9 +309,7 @@ static void sdl_audio_free(void *data) } if (sdl->speaker_buffer) - { fifo_free(sdl->speaker_buffer); - } #ifdef HAVE_THREADS slock_free(sdl->lock); @@ -333,18 +321,9 @@ static void sdl_audio_free(void *data) free(sdl); } -static bool sdl_audio_use_float(void *data) -{ - (void)data; - return false; -} - -static size_t sdl_audio_write_avail(void *data) -{ - /* stub */ - (void)data; - return 0; -} +/* TODO/FIXME - implement */ +static bool sdl_audio_use_float(void *data) { return false; } +static size_t sdl_audio_write_avail(void *data) { return 0; } audio_driver_t audio_sdl = { sdl_audio_init, diff --git a/audio/drivers/switch_audio.c b/audio/drivers/switch_audio.c index a2b6291ccb..7a91b5aa5a 100644 --- a/audio/drivers/switch_audio.c +++ b/audio/drivers/switch_audio.c @@ -73,10 +73,10 @@ static size_t switch_audio_buffer_size(void *data) #endif } -static ssize_t switch_audio_write(void *data, const void *buf, size_t size) +static ssize_t switch_audio_write(void *data, const void *s, size_t len) { - size_t to_write = size; - switch_audio_t *swa = (switch_audio_t*) data; + size_t to_write = len; + switch_audio_t *swa = (switch_audio_t*)data; if (!swa) return -1; @@ -125,9 +125,9 @@ static ssize_t switch_audio_write(void *data, const void *buf, size_t size) to_write = switch_audio_buffer_size(NULL) - swa->current_buffer->data_size; #ifndef HAVE_LIBNX - memcpy(((uint8_t*) swa->current_buffer->sample_data) + swa->current_buffer->data_size, buf, to_write); + memcpy(((uint8_t*) swa->current_buffer->sample_data) + swa->current_buffer->data_size, s, to_write); #else - memcpy(((uint8_t*) swa->current_buffer->buffer) + swa->current_buffer->data_size, buf, to_write); + memcpy(((uint8_t*) swa->current_buffer->buffer) + swa->current_buffer->data_size, s, to_write); #endif swa->current_buffer->data_size += to_write; swa->current_buffer->buffer_size = switch_audio_buffer_size(NULL); diff --git a/audio/drivers/switch_libnx_audren_audio.c b/audio/drivers/switch_libnx_audren_audio.c index 998a25a6a2..e638da66ee 100644 --- a/audio/drivers/switch_libnx_audren_audio.c +++ b/audio/drivers/switch_libnx_audren_audio.c @@ -186,7 +186,7 @@ static ssize_t libnx_audren_audio_get_free_wavebuf_idx(libnx_audren_t* aud) } static size_t libnx_audren_audio_append( - libnx_audren_t* aud, const void *buf, size_t size) + libnx_audren_t* aud, const void *s, size_t len) { void *dstbuf = NULL; ssize_t free_idx = -1; @@ -202,14 +202,14 @@ static size_t libnx_audren_audio_append( aud->current_size = 0; } - if (size > aud->buffer_size - aud->current_size) - size = aud->buffer_size - aud->current_size; + if (len > aud->buffer_size - aud->current_size) + len = aud->buffer_size - aud->current_size; dstbuf = aud->current_pool_ptr + aud->current_size; - memcpy(dstbuf, buf, size); - armDCacheFlush(dstbuf, size); + memcpy(dstbuf, s, len); + armDCacheFlush(dstbuf, len); - aud->current_size += size; + aud->current_size += len; if (aud->current_size == aud->buffer_size) { @@ -227,11 +227,11 @@ static size_t libnx_audren_audio_append( aud->current_wavebuf = NULL; } - return size; + return len; } static ssize_t libnx_audren_audio_write(void *data, - const void *buf, size_t size) + const void *s, size_t len) { libnx_audren_t *aud = (libnx_audren_t*)data; size_t written = 0; @@ -241,21 +241,21 @@ static ssize_t libnx_audren_audio_write(void *data, if (aud->nonblock) { - while (written < size) + while (written < len) { written += libnx_audren_audio_append( - aud, buf + written, size - written); - if (written != size) + aud, s + written, len - written); + if (written != len) break; } } else { - while (written < size) + while (written < len) { written += libnx_audren_audio_append( - aud, buf + written, size - written); - if (written != size) + aud, s + written, len - written); + if (written != len) { mutexLock(&aud->update_lock); audrvUpdate(&aud->drv); diff --git a/audio/drivers/switch_libnx_audren_thread_audio.c b/audio/drivers/switch_libnx_audren_thread_audio.c index 286dbd1dc6..721aae55a5 100644 --- a/audio/drivers/switch_libnx_audren_thread_audio.c +++ b/audio/drivers/switch_libnx_audren_thread_audio.c @@ -166,7 +166,7 @@ static void *libnx_audren_thread_audio_init(const char *device, unsigned rate, u aud->buffer_size = (real_latency * sample_rate / 1000); aud->samples = (aud->buffer_size / num_channels / sizeof(int16_t)); - mempool_size = (aud->buffer_size * BUFFER_COUNT + + mempool_size = (aud->buffer_size * BUFFER_COUNT + (AUDREN_MEMPOOL_ALIGNMENT-1)) &~ (AUDREN_MEMPOOL_ALIGNMENT-1); aud->mempool = memalign(AUDREN_MEMPOOL_ALIGNMENT, mempool_size); @@ -282,7 +282,7 @@ static size_t libnx_audren_thread_audio_buffer_size(void *data) } static ssize_t libnx_audren_thread_audio_write(void *data, - const void *buf, size_t size) + const void *s, size_t len) { libnx_audren_thread_t *aud = (libnx_audren_thread_t*)data; size_t available, written, written_tmp; @@ -297,22 +297,22 @@ static ssize_t libnx_audren_thread_audio_write(void *data, { mutexLock(&aud->fifo_lock); available = FIFO_WRITE_AVAIL(aud->fifo); - written = MIN(available, size); + written = MIN(available, len); if (written > 0) - fifo_write(aud->fifo, buf, written); + fifo_write(aud->fifo, s, written); mutexUnlock(&aud->fifo_lock); } else { written = 0; - while (written < size && aud->running) + while (written < len && aud->running) { mutexLock(&aud->fifo_lock); available = FIFO_WRITE_AVAIL(aud->fifo); if (available) { - written_tmp = MIN(size - written, available); - fifo_write(aud->fifo, (const char*)buf + written, written_tmp); + written_tmp = MIN(len - written, available); + fifo_write(aud->fifo, (const char*)s + written, written_tmp); mutexUnlock(&aud->fifo_lock); written += written_tmp; } diff --git a/audio/drivers/switch_thread_audio.c b/audio/drivers/switch_thread_audio.c index 3a530b24f0..b11edf976b 100644 --- a/audio/drivers/switch_thread_audio.c +++ b/audio/drivers/switch_thread_audio.c @@ -338,7 +338,7 @@ static void switch_thread_audio_free(void *data) swa = NULL; } -static ssize_t switch_thread_audio_write(void *data, const void *buf, size_t size) +static ssize_t switch_thread_audio_write(void *data, const void *s, size_t len) { size_t avail, written; switch_thread_audio_t *swa = (switch_thread_audio_t *)data; @@ -350,15 +350,15 @@ static ssize_t switch_thread_audio_write(void *data, const void *buf, size_t siz { compat_mutex_lock(&swa->fifoLock); avail = FIFO_WRITE_AVAIL(swa->fifo); - written = MIN(avail, size); + written = MIN(avail, len); if (written > 0) - fifo_write(swa->fifo, buf, written); + fifo_write(swa->fifo, s, written); compat_mutex_unlock(&swa->fifoLock); } else { written = 0; - while (written < size && swa->running) + while (written < len && swa->running) { compat_mutex_lock(&swa->fifoLock); avail = FIFO_WRITE_AVAIL(swa->fifo); @@ -372,8 +372,8 @@ static ssize_t switch_thread_audio_write(void *data, const void *buf, size_t siz } else { - size_t write_amt = MIN(size - written, avail); - fifo_write(swa->fifo, (const char*)buf + written, write_amt); + size_t write_amt = MIN(len - written, avail); + fifo_write(swa->fifo, (const char*)s + written, write_amt); compat_mutex_unlock(&swa->fifoLock); written += write_amt; } diff --git a/audio/drivers/tinyalsa.c b/audio/drivers/tinyalsa.c index e701cd9047..5f87dc696b 100644 --- a/audio/drivers/tinyalsa.c +++ b/audio/drivers/tinyalsa.c @@ -2275,12 +2275,12 @@ error: } static ssize_t -tinyalsa_write(void *data, const void *buf_, size_t size_) +tinyalsa_write(void *data, const void *buf_, size_t len) { tinyalsa_t *tinyalsa = (tinyalsa_t*)data; const uint8_t *buf = (const uint8_t*)buf_; snd_pcm_sframes_t written = 0; - snd_pcm_sframes_t size = BYTES_TO_FRAMES(size_, tinyalsa->frame_bits); + snd_pcm_sframes_t size = BYTES_TO_FRAMES(len, tinyalsa->frame_bits); size_t frames_size = tinyalsa->has_float ? sizeof(float) : sizeof(int16_t); if (tinyalsa->nonblock) diff --git a/audio/drivers/wasapi.c b/audio/drivers/wasapi.c index 924bdf111b..434640763f 100644 --- a/audio/drivers/wasapi.c +++ b/audio/drivers/wasapi.c @@ -59,6 +59,7 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency, settings_t *settings = config_get_ptr(); bool float_format = settings->bools.audio_wasapi_float_format; bool exclusive_mode = settings->bools.audio_wasapi_exclusive_mode; + bool audio_sync = settings->bools.audio_sync; unsigned sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length; wasapi_t *w = (wasapi_t*)calloc(1, sizeof(wasapi_t)); @@ -140,7 +141,7 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency, goto error; w->flags |= WASAPI_FLG_RUNNING; - if (settings->bools.audio_sync) + if (audio_sync) w->flags &= ~(WASAPI_FLG_NONBLOCK); else w->flags |= (WASAPI_FLG_NONBLOCK); @@ -163,7 +164,7 @@ error: return NULL; } -static ssize_t wasapi_write(void *wh, const void *data, size_t size) +static ssize_t wasapi_write(void *wh, const void *data, size_t len) { size_t written = 0; wasapi_t *w = (wasapi_t*)wh; @@ -193,16 +194,16 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size) return -1; write_avail = w->engine_buffer_size; } - written = (size < write_avail) ? size : write_avail; + written = (len < write_avail) ? len : write_avail; fifo_write(w->buffer, data, written); } else { ssize_t ir; - for (ir = -1; written < size; written += ir) + for (ir = -1; written < len; written += ir) { const void *_data = (char*)data + written; - size_t __size = size - written; + size_t __len = len - written; size_t write_avail = FIFO_WRITE_AVAIL(w->buffer); if (!write_avail) { @@ -222,7 +223,7 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size) write_avail = w->engine_buffer_size; } } - ir = (__size < write_avail) ? __size : write_avail; + ir = (__len < write_avail) ? __len : write_avail; fifo_write(w->buffer, _data, ir); } } @@ -257,7 +258,7 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size) } } write_avail = FIFO_WRITE_AVAIL(w->buffer); - written = size < write_avail ? size : write_avail; + written = len < write_avail ? len : write_avail; if (written) fifo_write(w->buffer, data, written); } @@ -267,7 +268,7 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size) return -1; if (!(write_avail = w->engine_buffer_size - padding * w->frame_size)) return 0; - written = size < write_avail ? size : write_avail; + written = (len < write_avail) ? len : write_avail; if (written) { BYTE *dest = NULL; @@ -285,10 +286,10 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size) else if (w->buffer) { ssize_t ir; - for (ir = -1; written < size; written += ir) + for (ir = -1; written < len; written += ir) { const void *_data = (char*)data + written; - size_t _size = size - written; + size_t _len = len - written; size_t write_avail = FIFO_WRITE_AVAIL(w->buffer); UINT32 padding = 0; if (!write_avail) @@ -315,7 +316,7 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size) } } write_avail = FIFO_WRITE_AVAIL(w->buffer); - ir = (_size < write_avail) ? _size : write_avail; + ir = (_len < write_avail) ? _len : write_avail; if (ir) fifo_write(w->buffer, _data, ir); } @@ -323,10 +324,10 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size) else { ssize_t ir; - for (ir = -1; written < size; written += ir) + for (ir = -1; written < len; written += ir) { const void *_data = (char*)data + written; - size_t _size = size - written; + size_t _len = len - written; size_t write_avail = 0; UINT32 padding = 0; if (!(WaitForSingleObject(w->write_event, WASAPI_TIMEOUT) == WAIT_OBJECT_0)) @@ -337,7 +338,7 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size) ir = 0; else { - ir = (_size < write_avail) ? _size : write_avail; + ir = (_len < write_avail) ? _len : write_avail; if (ir) { BYTE *dest = NULL; @@ -427,8 +428,7 @@ static void wasapi_free(void *wh) static bool wasapi_use_float(void *wh) { wasapi_t *w = (wasapi_t*)wh; - - return w->frame_size == 8; + return (w->frame_size == 8); } static void wasapi_device_list_free(void *u, void *slp) diff --git a/audio/drivers/wiiu_audio.c b/audio/drivers/wiiu_audio.c index de5d3d9353..6f8067dfa5 100644 --- a/audio/drivers/wiiu_audio.c +++ b/audio/drivers/wiiu_audio.c @@ -194,23 +194,23 @@ static bool ax_audio_start(void* data, bool is_shutdown) return true; } -static ssize_t ax_audio_write(void* data, const void* buf, size_t size) +static ssize_t ax_audio_write(void* data, const void* buf, size_t len) { uint32_t i; size_t count_avail = 0; ax_audio_t* ax = (ax_audio_t*)data; const uint16_t* src = buf; - size_t count = size >> 2; + size_t count = len >> 2; - if (!size || (size & 0x3)) + if (!len || (len & 0x3)) return 0; if (count > AX_AUDIO_MAX_FREE) count = AX_AUDIO_MAX_FREE; count_avail = ( - (ax->written > AX_AUDIO_MAX_FREE) - ? 0 + (ax->written > AX_AUDIO_MAX_FREE) + ? 0 : (AX_AUDIO_MAX_FREE - ax->written)); if (ax->nonblock) diff --git a/audio/drivers/xaudio.c b/audio/drivers/xaudio.c index 23d0b6d1b0..ac9f85e81a 100644 --- a/audio/drivers/xaudio.c +++ b/audio/drivers/xaudio.c @@ -192,7 +192,7 @@ static void xaudio2_free(xaudio2_t *handle) } static xaudio2_t *xaudio2_new(unsigned samplerate, unsigned channels, - size_t size, const char *device) + size_t len, const char *device) { int32_t idx_found = -1; WAVEFORMATEX wfx = {0}; @@ -292,7 +292,7 @@ static xaudio2_t *xaudio2_new(unsigned samplerate, unsigned channels, if (!handle->hEvent) goto error; - handle->bufsize = size / MAX_BUFFERS; + handle->bufsize = len / MAX_BUFFERS; handle->buf = (uint8_t*)calloc(1, handle->bufsize * MAX_BUFFERS); if (!handle->buf) goto error; @@ -341,12 +341,12 @@ static void *xa_init(const char *device, unsigned rate, unsigned latency, return xa; } -static ssize_t xa_write(void *data, const void *buf, size_t size) +static ssize_t xa_write(void *data, const void *s, size_t len) { - unsigned bytes = size; + unsigned bytes = len; xa_t *xa = (xa_t*)data; xaudio2_t *handle = xa->xa; - const uint8_t *buffer = (const uint8_t*)buf; + const uint8_t *buffer = (const uint8_t*)s; if (xa->flags & XA2_FLAG_NONBLOCK) { @@ -354,8 +354,8 @@ static ssize_t xa_write(void *data, const void *buf, size_t size) if (avail == 0) return 0; - if (avail < size) - bytes = size = avail; + if (avail < len) + bytes = len = avail; } while (bytes) @@ -391,7 +391,7 @@ static ssize_t xa_write(void *data, const void *buf, size_t size) if (FAILED(IXAudio2SourceVoice_SubmitSourceBuffer( handle->pSourceVoice, &xa2buffer, NULL))) { - if (size > 0) + if (len > 0) return -1; return 0; } @@ -402,7 +402,7 @@ static ssize_t xa_write(void *data, const void *buf, size_t size) } } - return size; + return len; } static bool xa_stop(void *data) diff --git a/audio/drivers/xenon360_audio.c b/audio/drivers/xenon360_audio.c index 98a71443f2..c6f38b8f4d 100644 --- a/audio/drivers/xenon360_audio.c +++ b/audio/drivers/xenon360_audio.c @@ -57,21 +57,21 @@ static INLINE uint32_t bswap_32(uint32_t val) ((val >> 8) & 0xff00) | ((val << 8) & 0xff0000); } -static ssize_t xenon360_audio_write(void *data, const void *buf, size_t size) +static ssize_t xenon360_audio_write(void *data, const void *s, size_t len) { size_t written = 0, i; - const uint32_t *in_buf = buf; - xenon_audio_t *xa = data; + const uint32_t *in_buf = s; + xenon_audio_t *xa = data; - for (i = 0; i < (size >> 2); i++) + for (i = 0; i < (len >> 2); i++) xa->buffer[i] = bswap_32(in_buf[i]); if (xa->nonblock) { if (xenon_sound_get_unplayed() < MAX_BUFFER) { - xenon_sound_submit(xa->buffer, size); - written = size; + xenon_sound_submit(xa->buffer, len); + written = len; } } else @@ -83,8 +83,8 @@ static ssize_t xenon360_audio_write(void *data, const void *buf, size_t size) udelay(50); } - xenon_sound_submit(xa->buffer, size); - written = size; + xenon_sound_submit(xa->buffer, len); + written = len; } return written; diff --git a/audio/drivers_microphone/alsa.c b/audio/drivers_microphone/alsa.c index 85de4ebe0e..139e3b09d5 100644 --- a/audio/drivers_microphone/alsa.c +++ b/audio/drivers_microphone/alsa.c @@ -21,7 +21,6 @@ #include "audio/microphone_driver.h" #include "verbosity.h" - #define BYTES_TO_FRAMES(bytes, frame_bits) ((bytes) * 8 / frame_bits) #define FRAMES_TO_BYTES(frames, frame_bits) ((frames) * frame_bits / 8) @@ -51,7 +50,7 @@ static void *alsa_microphone_init(void) return alsa; } -static void alsa_microphone_close_mic(void *driver_context, void *microphone_context); +static void alsa_microphone_close_mic(void *driver_context, void *mic_context); static void alsa_microphone_free(void *driver_context) { alsa_microphone_t *alsa = (alsa_microphone_t*)driver_context; @@ -64,36 +63,37 @@ static void alsa_microphone_free(void *driver_context) } } -static bool alsa_microphone_start_mic(void *driver_context, void *microphone_context); -static int alsa_microphone_read(void *driver_context, void *microphone_context, void *buf_, size_t size_) +static bool alsa_microphone_start_mic(void *driver_context, void *mic_context); + +static int alsa_microphone_read(void *driver_context, void *mic_context, void *s, size_t len) { - alsa_microphone_t *alsa = (alsa_microphone_t*)driver_context; - alsa_microphone_handle_t *microphone = (alsa_microphone_handle_t*)microphone_context; - uint8_t *buf = (uint8_t*)buf_; + size_t frames_size; + snd_pcm_sframes_t size; + snd_pcm_state_t state; + alsa_microphone_t *alsa = (alsa_microphone_t*)driver_context; + alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context; + uint8_t *buf = (uint8_t*)s; snd_pcm_sframes_t read = 0; int errnum = 0; - snd_pcm_sframes_t size; - size_t frames_size; - snd_pcm_state_t state; - if (!alsa || !microphone || !buf) + if (!alsa || !mic || !buf) return -1; - size = BYTES_TO_FRAMES(size_, microphone->stream_info.frame_bits); - frames_size = microphone->stream_info.has_float ? sizeof(float) : sizeof(int16_t); + size = BYTES_TO_FRAMES(len, mic->stream_info.frame_bits); + frames_size = mic->stream_info.has_float ? sizeof(float) : sizeof(int16_t); - state = snd_pcm_state(microphone->pcm); + state = snd_pcm_state(mic->pcm); if (state != SND_PCM_STATE_RUNNING) { RARCH_WARN("[ALSA]: Expected microphone \"%s\" to be in state RUNNING, was in state %s\n", - snd_pcm_name(microphone->pcm), + snd_pcm_name(mic->pcm), snd_pcm_state_name(state)); - errnum = snd_pcm_start(microphone->pcm); + errnum = snd_pcm_start(mic->pcm); if (errnum < 0) { RARCH_ERR("[ALSA]: Failed to start microphone \"%s\": %s\n", - snd_pcm_name(microphone->pcm), + snd_pcm_name(mic->pcm), snd_strerror(errnum)); return -1; @@ -104,11 +104,11 @@ static int alsa_microphone_read(void *driver_context, void *microphone_context, { while (size) { - snd_pcm_sframes_t frames = snd_pcm_readi(microphone->pcm, buf, size); + snd_pcm_sframes_t frames = snd_pcm_readi(mic->pcm, buf, size); if (frames == -EPIPE || frames == -EINTR || frames == -ESTRPIPE) { - errnum = snd_pcm_recover(microphone->pcm, frames, 0); + errnum = snd_pcm_recover(mic->pcm, frames, 0); if (errnum < 0) { RARCH_ERR("[ALSA]: Failed to read from microphone: %s\n", snd_strerror(frames)); @@ -135,20 +135,20 @@ static int alsa_microphone_read(void *driver_context, void *microphone_context, while (size) { snd_pcm_sframes_t frames; - int rc = snd_pcm_wait(microphone->pcm, -1); + int rc = snd_pcm_wait(mic->pcm, -1); if (rc == -EPIPE || rc == -ESTRPIPE || rc == -EINTR) { - if (snd_pcm_recover(microphone->pcm, rc, 1) < 0) + if (snd_pcm_recover(mic->pcm, rc, 1) < 0) return -1; continue; } - frames = snd_pcm_readi(microphone->pcm, buf, size); + frames = snd_pcm_readi(mic->pcm, buf, size); if (frames == -EPIPE || frames == -EINTR || frames == -ESTRPIPE) { - if (snd_pcm_recover(microphone->pcm, frames, 1) < 0) + if (snd_pcm_recover(mic->pcm, frames, 1) < 0) return -1; break; @@ -172,18 +172,18 @@ static int alsa_microphone_read(void *driver_context, void *microphone_context, } } - return FRAMES_TO_BYTES(read, microphone->stream_info.frame_bits); + return FRAMES_TO_BYTES(read, mic->stream_info.frame_bits); } -static bool alsa_microphone_mic_alive(const void *driver_context, const void *microphone_context) +static bool alsa_microphone_mic_alive(const void *driver_context, const void *mic_context) { - alsa_microphone_handle_t *microphone = (alsa_microphone_handle_t*)microphone_context; + alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context; (void)driver_context; - if (!microphone) + if (!mic) return false; - return snd_pcm_state(microphone->pcm) == SND_PCM_STATE_RUNNING; + return snd_pcm_state(mic->pcm) == SND_PCM_STATE_RUNNING; } static void alsa_microphone_set_nonblock_state(void *driver_context, bool nonblock) @@ -194,7 +194,6 @@ static void alsa_microphone_set_nonblock_state(void *driver_context, bool nonblo static struct string_list *alsa_microphone_device_list_new(const void *data) { - (void)data; return alsa_device_list_type_new("Input"); } @@ -211,73 +210,64 @@ static void *alsa_microphone_open_mic(void *driver_context, unsigned latency, unsigned *new_rate) { - alsa_microphone_t *alsa = (alsa_microphone_t*)driver_context; - alsa_microphone_handle_t *microphone = NULL; + alsa_microphone_t *alsa = (alsa_microphone_t*)driver_context; + alsa_microphone_handle_t *mic = NULL; if (!alsa) /* If we weren't given a valid ALSA context... */ return NULL; - microphone = calloc(1, sizeof(alsa_microphone_handle_t)); - if (!microphone) /* If the microphone context couldn't be allocated... */ + /* If the microphone context couldn't be allocated... */ + if (!(mic = calloc(1, sizeof(alsa_microphone_handle_t)))) return NULL; /* channels hardcoded to 1, because we only support mono mic input */ - if (alsa_init_pcm(µphone->pcm, device, SND_PCM_STREAM_CAPTURE, rate, latency, 1, µphone->stream_info, new_rate, SND_PCM_NONBLOCK) < 0) - { + if (alsa_init_pcm(&mic->pcm, device, SND_PCM_STREAM_CAPTURE, rate, latency, 1, + &mic->stream_info, new_rate, SND_PCM_NONBLOCK) < 0) goto error; - } - return microphone; + return mic; error: RARCH_ERR("[ALSA]: Failed to initialize microphone...\n"); - alsa_microphone_close_mic(alsa, microphone); + alsa_microphone_close_mic(alsa, mic); return NULL; } -static void alsa_microphone_close_mic(void *driver_context, void *microphone_context) +static void alsa_microphone_close_mic(void *driver_context, void *mic_context) { - alsa_microphone_handle_t *microphone = (alsa_microphone_handle_t*)microphone_context; + alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context; (void)driver_context; - if (microphone) + if (mic) { - alsa_free_pcm(microphone->pcm); - free(microphone); + alsa_free_pcm(mic->pcm); + free(mic); } } -static bool alsa_microphone_start_mic(void *driver_context, void *microphone_context) +static bool alsa_microphone_start_mic(void *driver_context, void *mic_context) { - alsa_microphone_handle_t *microphone = (alsa_microphone_handle_t*)microphone_context; - (void)driver_context; - - if (!microphone) + alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context; + if (!mic) return false; - - return alsa_start_pcm(microphone->pcm); + return alsa_start_pcm(mic->pcm); } -static bool alsa_microphone_stop_mic(void *driver_context, void *microphone_context) +static bool alsa_microphone_stop_mic(void *driver_context, void *mic_context) { - alsa_microphone_handle_t *microphone = (alsa_microphone_handle_t*)microphone_context; - (void)driver_context; - - if (!microphone) + alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context; + if (!mic) return false; - - return alsa_stop_pcm(microphone->pcm); + return alsa_stop_pcm(mic->pcm); } -static bool alsa_microphone_mic_use_float(const void *driver_context, const void *microphone_context) +static bool alsa_microphone_mic_use_float(const void *driver_context, const void *mic_context) { - alsa_microphone_handle_t *microphone = (alsa_microphone_handle_t*)microphone_context; - (void)driver_context; - - return microphone->stream_info.has_float; + alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context; + return mic->stream_info.has_float; } microphone_driver_t microphone_alsa = { diff --git a/audio/drivers_microphone/alsathread.c b/audio/drivers_microphone/alsathread.c index 772b5f1fd2..3b4e4f9397 100644 --- a/audio/drivers_microphone/alsathread.c +++ b/audio/drivers_microphone/alsathread.c @@ -49,27 +49,27 @@ static void *alsa_thread_microphone_init(void) return alsa; } -static void alsa_thread_microphone_close_mic(void *driver_context, void *microphone_context); +/* Forward declaration */ +static void alsa_thread_microphone_close_mic(void *driver_context, void *mic_context); + static void alsa_thread_microphone_free(void *driver_context) { alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)driver_context; if (alsa) - { free(alsa); - } } /** @see alsa_thread_read_microphone() */ -static void alsa_microphone_worker_thread(void *microphone_context) +static void alsa_microphone_worker_thread(void *mic_context) { - alsa_thread_microphone_handle_t *microphone = (alsa_thread_microphone_handle_t*)microphone_context; - uint8_t *buf = NULL; - uintptr_t thread_id = sthread_get_current_thread_id(); + alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context; + uint8_t *buf = NULL; + uintptr_t thread_id = sthread_get_current_thread_id(); - retro_assert(microphone != NULL); - buf = (uint8_t *)calloc(1, microphone->info.stream_info.period_size); - if (!buf) + retro_assert(mic != NULL); + + if (!(buf = (uint8_t *)calloc(1, mic->info.stream_info.period_size))) { RARCH_ERR("[ALSA] [capture thread %p]: Failed to allocate audio buffer\n", thread_id); goto end; @@ -78,34 +78,35 @@ static void alsa_microphone_worker_thread(void *microphone_context) RARCH_DBG("[ALSA] [capture thread %p]: Beginning microphone worker thread\n", thread_id); RARCH_DBG("[ALSA] [capture thread %p]: Microphone \"%s\" is in state %s\n", thread_id, - snd_pcm_name(microphone->info.pcm), - snd_pcm_state_name(snd_pcm_state(microphone->info.pcm))); + snd_pcm_name(mic->info.pcm), + snd_pcm_state_name(snd_pcm_state(mic->info.pcm))); - while (!microphone->info.thread_dead) - { /* Until we're told to stop... */ + /* Until we're told to stop... */ + while (!mic->info.thread_dead) + { size_t avail; size_t fifo_size; snd_pcm_sframes_t frames; int errnum = 0; /* Lock the incoming sample queue (the main thread may block) */ - slock_lock(microphone->info.fifo_lock); + slock_lock(mic->info.fifo_lock); /* Fill the incoming sample queue with whatever we recently read */ - avail = FIFO_WRITE_AVAIL(microphone->info.buffer); - fifo_size = MIN(microphone->info.stream_info.period_size, avail); - fifo_write(microphone->info.buffer, buf, fifo_size); + avail = FIFO_WRITE_AVAIL(mic->info.buffer); + fifo_size = MIN(mic->info.stream_info.period_size, avail); + fifo_write(mic->info.buffer, buf, fifo_size); /* Tell the main thread that it's okay to query the mic again */ - scond_signal(microphone->info.cond); + scond_signal(mic->info.cond); /* Unlock the incoming sample queue (the main thread may resume) */ - slock_unlock(microphone->info.fifo_lock); + slock_unlock(mic->info.fifo_lock); /* If underrun, fill rest with silence. */ - memset(buf + fifo_size, 0, microphone->info.stream_info.period_size - fifo_size); + memset(buf + fifo_size, 0, mic->info.stream_info.period_size - fifo_size); - errnum = snd_pcm_wait(microphone->info.pcm, 33); + errnum = snd_pcm_wait(mic->info.pcm, 33); if (errnum == 0) { @@ -118,7 +119,7 @@ static void alsa_microphone_worker_thread(void *microphone_context) thread_id, snd_strerror(errnum)); - if ((errnum = snd_pcm_recover(microphone->info.pcm, errnum, false)) < 0) + if ((errnum = snd_pcm_recover(mic->info.pcm, errnum, false)) < 0) { RARCH_ERR("[ALSA] [capture thread %p]: Failed to recover from prior wait error: %s\n", thread_id, @@ -130,7 +131,7 @@ static void alsa_microphone_worker_thread(void *microphone_context) continue; } - frames = snd_pcm_readi(microphone->info.pcm, buf, microphone->info.stream_info.period_frames); + frames = snd_pcm_readi(mic->info.pcm, buf, mic->info.stream_info.period_frames); if (frames == -EPIPE || frames == -EINTR || frames == -ESTRPIPE) { @@ -138,7 +139,7 @@ static void alsa_microphone_worker_thread(void *microphone_context) thread_id, snd_strerror(frames)); - if ((errnum = snd_pcm_recover(microphone->info.pcm, frames, false)) < 0) + if ((errnum = snd_pcm_recover(mic->info.pcm, frames, false)) < 0) { RARCH_ERR("[ALSA] [capture thread %p]: Failed to recover from prior read error: %s\n", thread_id, @@ -158,103 +159,104 @@ static void alsa_microphone_worker_thread(void *microphone_context) } end: - slock_lock(microphone->info.cond_lock); - microphone->info.thread_dead = true; - scond_signal(microphone->info.cond); - slock_unlock(microphone->info.cond_lock); + slock_lock(mic->info.cond_lock); + mic->info.thread_dead = true; + scond_signal(mic->info.cond); + slock_unlock(mic->info.cond_lock); free(buf); RARCH_DBG("[ALSA] [capture thread %p]: Ending microphone worker thread\n", thread_id); } -static int alsa_thread_microphone_read(void *driver_context, void *microphone_context, void *buf, size_t size) +static int alsa_thread_microphone_read(void *driver_context, void *mic_context, void *s, size_t len) { - alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)driver_context; - alsa_thread_microphone_handle_t *microphone = (alsa_thread_microphone_handle_t*)microphone_context; + alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)driver_context; + alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context; snd_pcm_state_t state; - if (!alsa || !microphone || !buf) /* If any of the parameters were invalid... */ + if (!alsa || !mic || !s) /* If any of the parameters were invalid... */ return -1; - if (microphone->info.thread_dead) /* If the mic thread is shutting down... */ + if (mic->info.thread_dead) /* If the mic thread is shutting down... */ return -1; - state = snd_pcm_state(microphone->info.pcm); + state = snd_pcm_state(mic->info.pcm); if (state != SND_PCM_STATE_RUNNING) { int errnum; RARCH_WARN("[ALSA]: Expected microphone \"%s\" to be in state RUNNING, was in state %s\n", - snd_pcm_name(microphone->info.pcm), - snd_pcm_state_name(state)); + snd_pcm_name(mic->info.pcm), snd_pcm_state_name(state)); - errnum = snd_pcm_start(microphone->info.pcm); + errnum = snd_pcm_start(mic->info.pcm); if (errnum < 0) { RARCH_ERR("[ALSA]: Failed to start microphone \"%s\": %s\n", - snd_pcm_name(microphone->info.pcm), - snd_strerror(errnum)); + snd_pcm_name(mic->info.pcm), snd_strerror(errnum)); return -1; } } + /* If driver interactions shouldn't block... */ if (alsa->nonblock) - { /* If driver interactions shouldn't block... */ + { size_t avail; size_t write_amt; /* "Hey, I'm gonna borrow the queue." */ - slock_lock(microphone->info.fifo_lock); + slock_lock(mic->info.fifo_lock); - avail = FIFO_READ_AVAIL(microphone->info.buffer); - write_amt = MIN(avail, size); + avail = FIFO_READ_AVAIL(mic->info.buffer); + write_amt = MIN(avail, len); /* "It's okay if you don't have any new samples, I'll just check in on you later." */ - fifo_read(microphone->info.buffer, buf, write_amt); + fifo_read(mic->info.buffer, s, write_amt); /* "Here, take this queue back." */ - slock_unlock(microphone->info.fifo_lock); + slock_unlock(mic->info.fifo_lock); return (int)write_amt; } else { size_t read = 0; - while (read < size && !microphone->info.thread_dead) - { /* Until we've read all requested samples (or we're told to stop)... */ + + /* Until we've read all requested samples (or we're told to stop)... */ + while (read < len && !mic->info.thread_dead) + { size_t avail; /* "Hey, I'm gonna borrow the queue." */ - slock_lock(microphone->info.fifo_lock); + slock_lock(mic->info.fifo_lock); - avail = FIFO_READ_AVAIL(microphone->info.buffer); + avail = FIFO_READ_AVAIL(mic->info.buffer); if (avail == 0) { /* "Oh, wait, it's empty." */ /* "Here, take it back..." */ - slock_unlock(microphone->info.fifo_lock); + slock_unlock(mic->info.fifo_lock); /* "...I'll just wait right here." */ - slock_lock(microphone->info.cond_lock); + slock_lock(mic->info.cond_lock); /* "Unless we're closing up shop..." */ - if (!microphone->info.thread_dead) + if (!mic->info.thread_dead) /* "...let me know when you've produced some samples." */ - scond_wait(microphone->info.cond, microphone->info.cond_lock); + scond_wait(mic->info.cond, mic->info.cond_lock); /* "Oh, you're ready? Okay, I'm gonna continue." */ - slock_unlock(microphone->info.cond_lock); + slock_unlock(mic->info.cond_lock); } else { - size_t read_amt = MIN(size - read, avail); + size_t read_amt = MIN(len - read, avail); /* "I'll just go ahead and consume all these samples..." - * (As many as will fit in buf, or as many as are available.) */ - fifo_read(microphone->info.buffer,buf + read, read_amt); + * (As many as will fit in s, or as many as are available.) */ + fifo_read(mic->info.buffer,s + read, read_amt); /* "I'm done, you can take the queue back now." */ - slock_unlock(microphone->info.fifo_lock); + slock_unlock(mic->info.fifo_lock); read += read_amt; } @@ -264,87 +266,75 @@ static int alsa_thread_microphone_read(void *driver_context, void *microphone_co } } -static bool alsa_thread_microphone_mic_alive(const void *driver_context, const void *microphone_context); +static bool alsa_thread_microphone_mic_alive(const void *driver_context, const void *mic_context); static void *alsa_thread_microphone_open_mic(void *driver_context, - const char *device, - unsigned rate, - unsigned latency, - unsigned *new_rate) + const char *device, unsigned rate, unsigned latency, unsigned *new_rate) { - alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)driver_context; - alsa_thread_microphone_handle_t *microphone = NULL; + alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)driver_context; + alsa_thread_microphone_handle_t *mic = NULL; if (!alsa) /* If we weren't given a valid ALSA context... */ return NULL; - microphone = calloc(1, sizeof(alsa_thread_microphone_handle_t)); - - if (!microphone) - { /* If the microphone context couldn't be allocated... */ + /* If the microphone context couldn't be allocated... */ + if (!(mic = calloc(1, sizeof(alsa_thread_microphone_handle_t)))) + { RARCH_ERR("[ALSA] Failed to allocate microphone context\n"); return NULL; } - if (alsa_init_pcm(µphone->info.pcm, device, SND_PCM_STREAM_CAPTURE, rate, latency, 1, µphone->info.stream_info, new_rate, 0) < 0) - { - goto error; - } - - microphone->info.fifo_lock = slock_new(); - microphone->info.cond_lock = slock_new(); - microphone->info.cond = scond_new(); - microphone->info.buffer = fifo_new(microphone->info.stream_info.buffer_size); - if (!microphone->info.fifo_lock || !microphone->info.cond_lock || !microphone->info.cond || !microphone->info.buffer || !microphone->info.pcm) + if (alsa_init_pcm(&mic->info.pcm, device, SND_PCM_STREAM_CAPTURE, rate, latency, + 1, &mic->info.stream_info, new_rate, 0) < 0) goto error; - microphone->info.worker_thread = sthread_create(alsa_microphone_worker_thread, microphone); - if (!microphone->info.worker_thread) + mic->info.fifo_lock = slock_new(); + mic->info.cond_lock = slock_new(); + mic->info.cond = scond_new(); + mic->info.buffer = fifo_new(mic->info.stream_info.buffer_size); + if (!mic->info.fifo_lock || !mic->info.cond_lock || !mic->info.cond || !mic->info.buffer || !mic->info.pcm) + goto error; + + mic->info.worker_thread = sthread_create(alsa_microphone_worker_thread, mic); + if (!mic->info.worker_thread) { RARCH_ERR("[ALSA]: Failed to initialize microphone worker thread\n"); goto error; } RARCH_DBG("[ALSA]: Initialized microphone worker thread\n"); - return microphone; + return mic; error: RARCH_ERR("[ALSA]: Failed to initialize microphone...\n"); - if (microphone) + if (mic) { - if (microphone->info.pcm) - { - snd_pcm_close(microphone->info.pcm); - } + if (mic->info.pcm) + snd_pcm_close(mic->info.pcm); - alsa_thread_microphone_close_mic(alsa, microphone); + alsa_thread_microphone_close_mic(alsa, mic); } return NULL; } -static void alsa_thread_microphone_close_mic(void *driver_context, void *microphone_context) +static void alsa_thread_microphone_close_mic(void *driver_context, void *mic_context) { - alsa_thread_microphone_handle_t *microphone = (alsa_thread_microphone_handle_t*)microphone_context; - (void)driver_context; - - if (microphone) + alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context; + if (mic) { - alsa_thread_free_info_members(µphone->info); - free(microphone); + alsa_thread_free_info_members(&mic->info); + free(mic); } } -static bool alsa_thread_microphone_mic_alive(const void *driver_context, const void *microphone_context) +static bool alsa_thread_microphone_mic_alive(const void *driver_context, const void *mic_context) { - alsa_thread_microphone_handle_t *microphone = (alsa_thread_microphone_handle_t *)microphone_context; - (void)driver_context; - - if (!microphone) + alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t *)mic_context; + if (!mic) return false; - - return snd_pcm_state(microphone->info.pcm) == SND_PCM_STATE_RUNNING; + return snd_pcm_state(mic->info.pcm) == SND_PCM_STATE_RUNNING; } static void alsa_thread_microphone_set_nonblock_state(void *driver_context, bool state) @@ -355,44 +345,35 @@ static void alsa_thread_microphone_set_nonblock_state(void *driver_context, bool static struct string_list *alsa_thread_microphone_device_list_new(const void *data) { - (void)data; return alsa_device_list_type_new("Input"); } static void alsa_thread_microphone_device_list_free(const void *driver_context, struct string_list *devices) { - (void)driver_context; string_list_free(devices); /* Does nothing if devices is NULL */ } -static bool alsa_thread_microphone_start_mic(void *driver_context, void *microphone_context) +static bool alsa_thread_microphone_start_mic(void *driver_context, void *mic_context) { - alsa_thread_microphone_handle_t *microphone = (alsa_thread_microphone_handle_t*)microphone_context; - (void)driver_context; - - if (!microphone) + alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context; + if (!mic) return false; - - return alsa_start_pcm(microphone->info.pcm); + return alsa_start_pcm(mic->info.pcm); } -static bool alsa_thread_microphone_stop_mic(void *driver_context, void *microphone_context) +static bool alsa_thread_microphone_stop_mic(void *driver_context, void *mic_context) { - alsa_thread_microphone_handle_t *microphone = (alsa_thread_microphone_handle_t*)microphone_context; - (void)driver_context; - - if (!microphone) + alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context; + if (!mic) return false; - - return alsa_stop_pcm(microphone->info.pcm); + return alsa_stop_pcm(mic->info.pcm); } -static bool alsa_thread_microphone_mic_use_float(const void *driver_context, const void *microphone_context) +static bool alsa_thread_microphone_mic_use_float(const void *driver_context, const void *mic_context) { - alsa_thread_microphone_handle_t *microphone = (alsa_thread_microphone_handle_t*)microphone_context; - - return microphone->info.stream_info.has_float; + alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context; + return mic->info.stream_info.has_float; } microphone_driver_t microphone_alsathread = { diff --git a/audio/drivers_microphone/pipewire.c b/audio/drivers_microphone/pipewire.c index f957ac6741..c6d2867905 100644 --- a/audio/drivers_microphone/pipewire.c +++ b/audio/drivers_microphone/pipewire.c @@ -13,119 +13,98 @@ * If not, see . */ -#include -#include - #include #include #include #include - #include #include +#include #include #include -#include "audio/common/pipewire.h" -#include "audio/microphone_driver.h" -#include "verbosity.h" +#include "../common/pipewire.h" +#include "../microphone_driver.h" +#include "../../verbosity.h" #define DEFAULT_CHANNELS 1 -#define QUANTUM 1024 /* TODO: detect */ #define RINGBUFFER_SIZE (1u << 22) #define RINGBUFFER_MASK (RINGBUFFER_SIZE - 1) typedef struct pipewire_microphone { pipewire_core_t *pw; - struct pw_stream *stream; struct spa_hook stream_listener; struct spa_audio_info_raw info; uint32_t frame_size; struct spa_ringbuffer ring; uint8_t buffer[RINGBUFFER_SIZE]; - - bool is_ready; } pipewire_microphone_t; static void stream_state_changed_cb(void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { - pipewire_microphone_t *microphone = (pipewire_microphone_t*)data; + pipewire_microphone_t *mic = (pipewire_microphone_t*)data; - RARCH_DBG("[PipeWire]: New state for Source Node %d : %s\n", - pw_stream_get_node_id(microphone->stream), + RARCH_DBG("[Microphone] [PipeWire]: Stream state changed %s -> %s\n", + pw_stream_state_as_string(old), pw_stream_state_as_string(state)); - switch(state) - { - case PW_STREAM_STATE_UNCONNECTED: - microphone->is_ready = false; - pw_thread_loop_stop(microphone->pw->thread_loop); - break; - case PW_STREAM_STATE_STREAMING: - case PW_STREAM_STATE_ERROR: - case PW_STREAM_STATE_PAUSED: - pw_thread_loop_signal(microphone->pw->thread_loop, false); - break; - default: - break; - } + pw_thread_loop_signal(mic->pw->thread_loop, false); } static void stream_destroy_cb(void *data) { - pipewire_microphone_t *microphone = (pipewire_microphone_t*)data; - spa_hook_remove(µphone->stream_listener); - microphone->stream = NULL; + pipewire_microphone_t *mic = (pipewire_microphone_t*)data; + spa_hook_remove(&mic->stream_listener); + mic->stream = NULL; } static void capture_process_cb(void *data) { - pipewire_microphone_t *microphone = (pipewire_microphone_t *)data; void *p; + int32_t filled; struct pw_buffer *b; struct spa_buffer *buf; - int32_t filled; - uint32_t index, offs, n_bytes; + uint32_t idx, offs, n_bytes; + pipewire_microphone_t *mic = (pipewire_microphone_t*)data; - assert(microphone->stream); + retro_assert(mic); + retro_assert(mic->stream); - b = pw_stream_dequeue_buffer(microphone->stream); - if (b == NULL) + if (!(b = pw_stream_dequeue_buffer(mic->stream))) { - RARCH_ERR("[PipeWire]: out of buffers: %s\n", strerror(errno)); - return; + RARCH_ERR("[Microphone] [PipeWire]: Out of buffers: %s\n", strerror(errno)); + return pw_thread_loop_signal(mic->pw->thread_loop, false); } buf = b->buffer; - p = buf->datas[0].data; - if (p == NULL) - return; + if ((p = buf->datas[0].data) == NULL) + return pw_thread_loop_signal(mic->pw->thread_loop, false); - offs = SPA_MIN(buf->datas[0].chunk->offset, buf->datas[0].maxsize); - n_bytes = SPA_MIN(buf->datas[0].chunk->size, buf->datas[0].maxsize - offs); + offs = MIN(buf->datas[0].chunk->offset, buf->datas[0].maxsize); + n_bytes = MIN(buf->datas[0].chunk->size, buf->datas[0].maxsize - offs); - filled = spa_ringbuffer_get_write_index(µphone->ring, &index); - if (filled < 0) - RARCH_ERR("[PipeWire]: %p: underrun write:%u filled:%d\n", p, index, filled); + if ((filled = spa_ringbuffer_get_write_index(&mic->ring, &idx)) < 0) + RARCH_ERR("[Microphone] [PipeWire]: %p: underrun write:%u filled:%d\n", p, idx, filled); else { if ((uint32_t)filled + n_bytes > RINGBUFFER_SIZE) - RARCH_ERR("[PipeWire]: %p: overrun write:%u filled:%d + size:%u > max:%u\n", - p, index, filled, n_bytes, RINGBUFFER_SIZE); + RARCH_ERR("[Microphone] [PipeWire]: %p: overrun write:%u filled:%d + size:%u > max:%u\n", + p, idx, filled, n_bytes, RINGBUFFER_SIZE); } - spa_ringbuffer_write_data(µphone->ring, - microphone->buffer, RINGBUFFER_SIZE, - index & RINGBUFFER_MASK, - SPA_PTROFF(p, offs, void), n_bytes); - index += n_bytes; - spa_ringbuffer_write_update(µphone->ring, index); + spa_ringbuffer_write_data(&mic->ring, + mic->buffer, RINGBUFFER_SIZE, + idx & RINGBUFFER_MASK, + SPA_PTROFF(p, offs, void), n_bytes); + idx += n_bytes; + spa_ringbuffer_write_update(&mic->ring, idx); - pw_stream_queue_buffer(microphone->stream, b); + pw_stream_queue_buffer(mic->stream, b); + pw_thread_loop_signal(mic->pw->thread_loop, false); } static const struct pw_stream_events capture_stream_events = { @@ -136,29 +115,31 @@ static const struct pw_stream_events capture_stream_events = { }; static void registry_event_global(void *data, uint32_t id, - uint32_t permissions, const char *type, uint32_t version, - const struct spa_dict *props) + uint32_t permissions, const char *type, uint32_t version, + const struct spa_dict *props) { union string_list_elem_attr attr; + const struct spa_dict_item *item; pipewire_core_t *pw = (pipewire_core_t*)data; - const char *media = NULL; const char *sink = NULL; if (!pw) return; - if (spa_streq(type, PW_TYPE_INTERFACE_Node)) + if ( spa_streq(type, PW_TYPE_INTERFACE_Node) + && spa_streq("Audio/Source", spa_dict_lookup(props, PW_KEY_MEDIA_CLASS))) { - media = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS); - if (media && strcmp(media, "Audio/Source") == 0) + sink = spa_dict_lookup(props, PW_KEY_NODE_NAME); + if (sink && pw->devicelist) { - if ((sink = spa_dict_lookup(props, PW_KEY_NODE_NAME)) != NULL) - { - attr.i = id; - string_list_append(pw->devicelist, sink, attr); - RARCH_LOG("[PipeWire]: Found Source Node: %s\n", sink); - } + attr.i = id; + string_list_append(pw->devicelist, sink, attr); + RARCH_LOG("[Microphone] [PipeWire]: Found Source Node: %s\n", sink); } + + RARCH_DBG("[Microphone] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version); + spa_dict_for_each(item, props) + RARCH_DBG("[Microphone] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value); } } @@ -167,121 +148,105 @@ static const struct pw_registry_events registry_events = { .global = registry_event_global, }; -static void pipewire_microphone_free(void *driver_context); +static void pipewire_microphone_free(void *driver_context) +{ + pipewire_core_deinit((pipewire_core_t*)driver_context); +} static void *pipewire_microphone_init(void) { - int res; - uint64_t buf_samples; + int res; + uint8_t buffer[1024]; + uint64_t buf_samples; const struct spa_pod *params[1]; - uint8_t buffer[1024]; struct pw_properties *props = NULL; const char *error = NULL; - pipewire_core_t *pw = (pipewire_core_t*)calloc(1, sizeof(*pw)); + pipewire_core_t *pw = NULL; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - if (!pw) + if (!pipewire_core_init(&pw, "microphone_driver", ®istry_events)) goto error; - pw_init(NULL, NULL); - - pw->devicelist = string_list_new(); - if (!pw->devicelist) - goto error; - - if (!pipewire_core_init(pw, "microphone_driver")) - goto error; - - pw->registry = pw_core_get_registry(pw->core, PW_VERSION_REGISTRY, 0); - - spa_zero(pw->registry_listener); - pw_registry_add_listener(pw->registry, &pw->registry_listener, ®istry_events, pw); - - pipewire_wait_resync(pw); + pipewire_core_wait_resync(pw); pw_thread_loop_unlock(pw->thread_loop); return pw; error: - RARCH_ERR("[PipeWire]: Failed to initialize microphone\n"); + RARCH_ERR("[Microphone] [PipeWire]: Failed to initialize microphone\n"); pipewire_microphone_free(pw); return NULL; } -static void pipewire_microphone_close_mic(void *driver_context, void *microphone_context); -static void pipewire_microphone_free(void *driver_context) +static void pipewire_microphone_close_mic(void *driver_context, void *mic_context) { - pipewire_core_t *pw = (pipewire_core_t*)driver_context; + pipewire_core_t *pw = (pipewire_core_t*)driver_context; + pipewire_microphone_t *mic = (pipewire_microphone_t*)mic_context; - if (!pw) - return pw_deinit(); - - if (pw->thread_loop) - pw_thread_loop_stop(pw->thread_loop); - - if (pw->client) - pw_proxy_destroy((struct pw_proxy *)pw->client); - - if (pw->registry) - pw_proxy_destroy((struct pw_proxy*)pw->registry); - - if (pw->core) + if (pw && mic) { - spa_hook_remove(&pw->core_listener); - spa_zero(pw->core_listener); - pw_core_disconnect(pw->core); + pw_thread_loop_lock(pw->thread_loop); + pw_stream_destroy(mic->stream); + mic->stream = NULL; + pw_thread_loop_unlock(pw->thread_loop); + free(mic); } - - if (pw->ctx) - pw_context_destroy(pw->ctx); - - pw_thread_loop_destroy(pw->thread_loop); - - if (pw->devicelist) - string_list_free(pw->devicelist); - - free(pw); - pw_deinit(); } -static int pipewire_microphone_read(void *driver_context, void *microphone_context, void *buf_, size_t size_) +static int pipewire_microphone_read(void *driver_context, void *mic_context, void *s, size_t len) { - int32_t readable; - uint32_t index; - const char *error = NULL; - pipewire_core_t *pw = (pipewire_core_t*)driver_context; - pipewire_microphone_t *microphone = (pipewire_microphone_t*)microphone_context; + uint32_t idx; + int32_t readable; + const char *error = NULL; + pipewire_core_t *pw = (pipewire_core_t*)driver_context; + pipewire_microphone_t *mic = (pipewire_microphone_t*)mic_context; - if (!microphone->is_ready || pw_stream_get_state(microphone->stream, &error) != PW_STREAM_STATE_STREAMING) + if (pw_stream_get_state(mic->stream, &error) != PW_STREAM_STATE_STREAMING) return -1; pw_thread_loop_lock(pw->thread_loop); - /* get no of available bytes to read data from buffer */ - readable = spa_ringbuffer_get_read_index(µphone->ring, &index); - if (readable < (int32_t)size_) - size_ = readable; + for (;;) + { + /* get no of available bytes to read data from buffer */ + readable = spa_ringbuffer_get_read_index(&mic->ring, &idx); - spa_ringbuffer_read_data(µphone->ring, - microphone->buffer, RINGBUFFER_SIZE, - index & RINGBUFFER_MASK, buf_, size_); - index += size_; - spa_ringbuffer_read_update(µphone->ring, index); + if (readable < (int32_t)len) + { + if (pw->nonblock) + { + len = readable; + break; + } + + pw_thread_loop_wait(pw->thread_loop); + if (pw_stream_get_state(mic->stream, &error) != PW_STREAM_STATE_STREAMING) + { + pw_thread_loop_unlock(mic->pw->thread_loop); + return -1; + } + } + else + break; + } + + spa_ringbuffer_read_data(&mic->ring, + mic->buffer, RINGBUFFER_SIZE, + idx & RINGBUFFER_MASK, s, len); + idx += len; + spa_ringbuffer_read_update(&mic->ring, idx); pw_thread_loop_unlock(pw->thread_loop); - return size_; + return len; } -static bool pipewire_microphone_mic_alive(const void *driver_context, const void *microphone_context) +static bool pipewire_microphone_mic_alive(const void *driver_context, const void *mic_context) { - const char *error = NULL; - pipewire_microphone_t *microphone = (pipewire_microphone_t*)microphone_context; - (void)driver_context; - - if (!microphone) + const char *error = NULL; + pipewire_microphone_t *mic = (pipewire_microphone_t*)mic_context; + if (!mic) return false; - - return pw_stream_get_state(microphone->stream, &error) == PW_STREAM_STATE_STREAMING; + return pw_stream_get_state(mic->stream, &error) == PW_STREAM_STATE_STREAMING; } static void pipewire_microphone_set_nonblock_state(void *driver_context, bool nonblock) @@ -303,40 +268,35 @@ static struct string_list *pipewire_microphone_device_list_new(const void *drive static void pipewire_microphone_device_list_free(const void *driver_context, struct string_list *devices) { - (void)driver_context; if (devices) string_list_free(devices); } static void *pipewire_microphone_open_mic(void *driver_context, - const char *device, - unsigned rate, - unsigned latency, + const char *device, unsigned rate, unsigned latency, unsigned *new_rate) { - int res; - uint64_t buf_samples; - const struct spa_pod *params[1]; - uint8_t buffer[1024]; - struct pw_properties *props = NULL; - const char *error = NULL; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - pipewire_microphone_t *microphone = calloc(1, sizeof(pipewire_microphone_t)); + int res; + uint64_t buf_samples; + uint8_t buffer[1024]; + const struct spa_pod *params[1]; + struct pw_properties *props = NULL; + const char *error = NULL; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + pipewire_microphone_t *mic = NULL; - retro_assert(driver_context); - - if (!microphone) + if (!driver_context || (mic = calloc(1, sizeof(pipewire_microphone_t))) == NULL) goto error; - microphone->pw = (pipewire_core_t*)driver_context; + mic->pw = (pipewire_core_t*)driver_context; - pw_thread_loop_lock(microphone->pw->thread_loop); + pw_thread_loop_lock(mic->pw->thread_loop); - microphone->info.format = is_little_endian() ? SPA_AUDIO_FORMAT_F32_LE : SPA_AUDIO_FORMAT_F32_BE; - microphone->info.channels = DEFAULT_CHANNELS; - set_position(DEFAULT_CHANNELS, microphone->info.position); - microphone->info.rate = rate; - microphone->frame_size = calc_frame_size(microphone->info.format, DEFAULT_CHANNELS); + mic->info.format = is_little_endian() ? SPA_AUDIO_FORMAT_F32_LE : SPA_AUDIO_FORMAT_F32_BE; + mic->info.channels = DEFAULT_CHANNELS; + pipewire_set_position(DEFAULT_CHANNELS, mic->info.position); + mic->info.rate = rate; + mic->frame_size = pipewire_calc_frame_size(mic->info.format, DEFAULT_CHANNELS); props = pw_properties_new(PW_KEY_MEDIA_TYPE, PW_RARCH_MEDIA_TYPE_AUDIO, PW_KEY_MEDIA_CATEGORY, PW_RARCH_MEDIA_CATEGORY_RECORD, @@ -353,98 +313,95 @@ static void *pipewire_microphone_open_mic(void *driver_context, if (device) pw_properties_set(props, PW_KEY_TARGET_OBJECT, device); - buf_samples = QUANTUM * rate * 3 / 4 / 100000; - - pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%" PRIu64 "/%u", - buf_samples, rate); - + buf_samples = latency * rate / 1000; + pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%" PRIu64 "/%u", buf_samples, rate); pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", rate); - microphone->stream = pw_stream_new(microphone->pw->core, PW_RARCH_APPNAME, props); - - if (!microphone->stream) + if (!(mic->stream = pw_stream_new(mic->pw->core, PW_RARCH_APPNAME, props))) goto unlock_error; - pw_stream_add_listener(microphone->stream, µphone->stream_listener, &capture_stream_events, microphone); + pw_stream_add_listener(mic->stream, &mic->stream_listener, &capture_stream_events, mic); - params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, µphone->info); + params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &mic->info); /* Now connect this stream. We ask that our process function is * called in a realtime thread. */ - res = pw_stream_connect(microphone->stream, - PW_DIRECTION_INPUT, - PW_ID_ANY, - PW_STREAM_FLAG_AUTOCONNECT | - PW_STREAM_FLAG_MAP_BUFFERS | - PW_STREAM_FLAG_RT_PROCESS, - params, 1); + res = pw_stream_connect(mic->stream, PW_DIRECTION_INPUT, PW_ID_ANY, + PW_STREAM_FLAG_AUTOCONNECT + | PW_STREAM_FLAG_INACTIVE + | PW_STREAM_FLAG_MAP_BUFFERS + | PW_STREAM_FLAG_RT_PROCESS, + params, 1); if (res < 0) goto unlock_error; - pw_thread_loop_wait(microphone->pw->thread_loop); + pw_thread_loop_wait(mic->pw->thread_loop); + pw_thread_loop_unlock(mic->pw->thread_loop); - pw_thread_loop_unlock(microphone->pw->thread_loop); - *new_rate = microphone->info.rate; - microphone->is_ready = true; + *new_rate = mic->info.rate; - return microphone; + return mic; unlock_error: - pw_thread_loop_unlock(microphone->pw->thread_loop); + pw_thread_loop_unlock(mic->pw->thread_loop); error: - RARCH_ERR("[PipeWire]: Failed to initialize microphone...\n"); - pipewire_microphone_close_mic(microphone->pw, microphone); + RARCH_ERR("[Microphone] [PipeWire]: Failed to initialize microphone...\n"); + pipewire_microphone_close_mic(mic->pw, mic); return NULL; } -static void pipewire_microphone_close_mic(void *driver_context, void *microphone_context) +static bool pipewire_microphone_start_mic(void *driver_context, void *mic_context) { - pipewire_core_t *pw = (pipewire_core_t*)driver_context; - pipewire_microphone_t *microphone = (pipewire_microphone_t*)microphone_context; + enum pw_stream_state st; + pipewire_core_t *pw = (pipewire_core_t*)driver_context; + pipewire_microphone_t *mic = (pipewire_microphone_t*)mic_context; + const char *error = NULL; + bool res = false; - if (pw && microphone) + if (!pw || !mic) + return false; + + st = pw_stream_get_state(mic->stream, &error); + switch (st) { - pw_thread_loop_lock(pw->thread_loop); - pw_stream_destroy(microphone->stream); - microphone->stream = NULL; - pw_thread_loop_unlock(pw->thread_loop); - free(microphone); + case PW_STREAM_STATE_STREAMING: + res = true; + break; + case PW_STREAM_STATE_PAUSED: + res = pipewire_stream_set_active(pw->thread_loop, mic->stream, true); + break; + default: + break; } + + return res; } -static bool pipewire_microphone_start_mic(void *driver_context, void *microphone_context) +static bool pipewire_microphone_stop_mic(void *driver_context, void *mic_context) { - pipewire_core_t *pw = (pipewire_core_t*)driver_context; - pipewire_microphone_t *microphone = (pipewire_microphone_t*)microphone_context; - const char *error = NULL; + pipewire_core_t *pw = (pipewire_core_t*)driver_context; + pipewire_microphone_t *mic = (pipewire_microphone_t*)mic_context; + const char *error = NULL; + bool res = false; - if (!microphone->is_ready) + if (!pw || !mic) return false; - if (pw_stream_get_state(microphone->stream, &error) == PW_STREAM_STATE_STREAMING) - return true; - return pipewire_set_active(pw->thread_loop, microphone->stream, true); + if (pw_stream_get_state(mic->stream, &error) == PW_STREAM_STATE_STREAMING) + res = pipewire_stream_set_active(pw->thread_loop, mic->stream, false); + else + /* For other states we assume that the stream is inactive */ + res = true; + + spa_ringbuffer_read_update(&mic->ring, 0); + spa_ringbuffer_write_update(&mic->ring, 0); + + return res; } -static bool pipewire_microphone_stop_mic(void *driver_context, void *microphone_context) +static bool pipewire_microphone_mic_use_float(const void *a, const void *b) { - pipewire_core_t *pw = (pipewire_core_t*)driver_context; - pipewire_microphone_t *microphone = (pipewire_microphone_t*)microphone_context; - const char *error = NULL; - - if (!microphone->is_ready) - return false; - if (pw_stream_get_state(microphone->stream, &error) == PW_STREAM_STATE_PAUSED) - return true; - - return pipewire_set_active(pw->thread_loop, microphone->stream, false); -} - -static bool pipewire_microphone_mic_use_float(const void *driver_context, const void *microphone_context) -{ - (void)driver_context; - (void)microphone_context; return true; } diff --git a/audio/drivers_microphone/sdl_microphone.c b/audio/drivers_microphone/sdl_microphone.c index b414ac6546..24e8e03804 100644 --- a/audio/drivers_microphone/sdl_microphone.c +++ b/audio/drivers_microphone/sdl_microphone.c @@ -45,9 +45,7 @@ typedef struct sdl_microphone static INLINE int sdl_microphone_find_num_frames(int rate, int latency) { int frames = (rate * latency) / 1000; - /* SDL only likes 2^n sized buffers. */ - return next_pow2(frames); } @@ -55,7 +53,6 @@ static void *sdl_microphone_init(void) { sdl_microphone_t *sdl = NULL; uint32_t sdl_subsystem_flags = SDL_WasInit(0); - /* Initialise audio subsystem, if required */ if (sdl_subsystem_flags == 0) { @@ -67,32 +64,30 @@ static void *sdl_microphone_init(void) if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) return NULL; } - if (!(sdl = (sdl_microphone_t*)calloc(1, sizeof(*sdl)))) return NULL; - return sdl; } -static void sdl_microphone_close_mic(void *driver_context, void *microphone_context) +static void sdl_microphone_close_mic(void *driver_context, void *mic_context) { - sdl_microphone_handle_t *microphone = (sdl_microphone_handle_t *)microphone_context; + sdl_microphone_handle_t *mic = (sdl_microphone_handle_t *)mic_context; - if (microphone) + if (mic) { /* If the microphone was originally initialized successfully... */ - if (microphone->device_id > 0) - SDL_CloseAudioDevice(microphone->device_id); + if (mic->device_id > 0) + SDL_CloseAudioDevice(mic->device_id); - fifo_free(microphone->sample_buffer); + fifo_free(mic->sample_buffer); #ifdef HAVE_THREADS - slock_free(microphone->lock); - scond_free(microphone->cond); + slock_free(mic->lock); + scond_free(mic->cond); #endif - RARCH_LOG("[SDL audio]: Freed microphone with former device ID %u\n", microphone->device_id); - free(microphone); + RARCH_LOG("[SDL audio]: Freed microphone with former device ID %u\n", mic->device_id); + free(mic); } } @@ -109,28 +104,24 @@ static void sdl_microphone_free(void *data) static void sdl_audio_record_cb(void *data, Uint8 *stream, int len) { - sdl_microphone_handle_t *microphone = (sdl_microphone_handle_t*)data; - size_t avail = FIFO_WRITE_AVAIL(microphone->sample_buffer); - size_t read_size = MIN(len, (int)avail); + sdl_microphone_handle_t *mic = (sdl_microphone_handle_t*)data; + size_t avail = FIFO_WRITE_AVAIL(mic->sample_buffer); + size_t read_size = MIN(len, (int)avail); /* If the sample buffer is almost full, just write as much as we can into it*/ - - fifo_write(microphone->sample_buffer, stream, read_size); + fifo_write(mic->sample_buffer, stream, read_size); #ifdef HAVE_THREADS - scond_signal(microphone->cond); + scond_signal(mic->cond); #endif } -static void *sdl_microphone_open_mic(void *driver_context, - const char *device, - unsigned rate, - unsigned latency, - unsigned *new_rate) +static void *sdl_microphone_open_mic(void *driver_context, const char *device, + unsigned rate, unsigned latency, unsigned *new_rate) { int frames; size_t bufsize; - sdl_microphone_handle_t *microphone = NULL; - SDL_AudioSpec desired_spec = {0}; - void *tmp = NULL; + void *tmp = NULL; + sdl_microphone_handle_t *mic = NULL; + SDL_AudioSpec desired_spec = {0}; #if __APPLE__ if (!string_is_equal(audio_driver_get_ident(), "sdl2")) @@ -150,7 +141,7 @@ static void *sdl_microphone_open_mic(void *driver_context, return NULL; } - if (!(microphone = (sdl_microphone_handle_t *) + if (!(mic = (sdl_microphone_handle_t *) calloc(1, sizeof(sdl_microphone_handle_t)))) return NULL; @@ -174,30 +165,31 @@ static void *sdl_microphone_open_mic(void *driver_context, desired_spec.format = AUDIO_F32SYS; desired_spec.channels = 1; /* Microphones only usually provide input in mono */ desired_spec.samples = frames; - desired_spec.userdata = microphone; + desired_spec.userdata = mic; desired_spec.callback = sdl_audio_record_cb; - microphone->device_id = SDL_OpenAudioDevice( + mic->device_id = SDL_OpenAudioDevice( NULL, true, &desired_spec, - µphone->device_spec, - SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_FORMAT_CHANGE); + &mic->device_spec, + SDL_AUDIO_ALLOW_FREQUENCY_CHANGE + | SDL_AUDIO_ALLOW_FORMAT_CHANGE); - if (microphone->device_id == 0) + if (mic->device_id == 0) { RARCH_ERR("[SDL mic]: Failed to open SDL audio input device: %s\n", SDL_GetError()); goto error; } RARCH_DBG("[SDL mic]: Opened SDL audio input device with ID %u\n", - microphone->device_id); + mic->device_id); RARCH_DBG("[SDL mic]: Requested a microphone frequency of %u Hz, got %u Hz\n", - desired_spec.freq, microphone->device_spec.freq); + desired_spec.freq, mic->device_spec.freq); RARCH_DBG("[SDL mic]: Requested %u channels for microphone, got %u\n", - desired_spec.channels, microphone->device_spec.channels); + desired_spec.channels, mic->device_spec.channels); RARCH_DBG("[SDL mic]: Requested a %u-sample microphone buffer, got %u samples (%u bytes)\n", - frames, microphone->device_spec.samples, microphone->device_spec.size); - RARCH_DBG("[SDL mic]: Got a microphone silence value of %u\n", microphone->device_spec.silence); + frames, mic->device_spec.samples, mic->device_spec.size); + RARCH_DBG("[SDL mic]: Got a microphone silence value of %u\n", mic->device_spec.silence); RARCH_DBG("[SDL mic]: Requested microphone audio format: %u-bit %s %s %s endian\n", SDL_AUDIO_BITSIZE(desired_spec.format), SDL_AUDIO_ISSIGNED(desired_spec.format) ? "signed" : "unsigned", @@ -211,87 +203,85 @@ static void *sdl_microphone_open_mic(void *driver_context, SDL_AUDIO_ISBIGENDIAN(desired_spec.format) ? "big" : "little"); if (new_rate) - *new_rate = microphone->device_spec.freq; + *new_rate = mic->device_spec.freq; #ifdef HAVE_THREADS - microphone->lock = slock_new(); - microphone->cond = scond_new(); + mic->lock = slock_new(); + mic->cond = scond_new(); #endif RARCH_LOG("[SDL audio]: Requested %u ms latency for input device, got %d ms\n", - latency, (int)(microphone->device_spec.samples * 4 * 1000 / microphone->device_spec.freq)); + latency, (int)(mic->device_spec.samples * 4 * 1000 / mic->device_spec.freq)); /* Create a buffer twice as big as needed and prefill the buffer. */ - bufsize = microphone->device_spec.samples * 2 * (SDL_AUDIO_BITSIZE(microphone->device_spec.format) / 8); - tmp = calloc(1, bufsize); - microphone->sample_buffer = fifo_new(bufsize); + bufsize = mic->device_spec.samples * 2 * (SDL_AUDIO_BITSIZE(mic->device_spec.format) / 8); + tmp = calloc(1, bufsize); + mic->sample_buffer = fifo_new(bufsize); RARCH_DBG("[SDL audio]: Initialized microphone sample queue with %u bytes\n", bufsize); if (tmp) { - fifo_write(microphone->sample_buffer, tmp, bufsize); + fifo_write(mic->sample_buffer, tmp, bufsize); free(tmp); } - RARCH_LOG("[SDL audio]: Initialized microphone with device ID %u\n", microphone->device_id); - return microphone; + RARCH_LOG("[SDL audio]: Initialized microphone with device ID %u\n", mic->device_id); + return mic; error: - free(microphone); + free(mic); return NULL; } -static bool sdl_microphone_mic_alive(const void *data, const void *microphone_context) +static bool sdl_microphone_mic_alive(const void *data, const void *mic_context) { - const sdl_microphone_handle_t *microphone = (const sdl_microphone_handle_t*)microphone_context; - if (!microphone) + const sdl_microphone_handle_t *mic = (const sdl_microphone_handle_t*)mic_context; + if (!mic) return false; /* Both params must be non-null */ - return SDL_GetAudioDeviceStatus(microphone->device_id) == SDL_AUDIO_PLAYING; + return SDL_GetAudioDeviceStatus(mic->device_id) == SDL_AUDIO_PLAYING; } -static bool sdl_microphone_start_mic(void *driver_context, void *microphone_context) +static bool sdl_microphone_start_mic(void *driver_context, void *mic_context) { - sdl_microphone_handle_t *microphone = (sdl_microphone_handle_t*)microphone_context; - - if (!microphone) + sdl_microphone_handle_t *mic = (sdl_microphone_handle_t*)mic_context; + if (!mic) return false; - - SDL_PauseAudioDevice(microphone->device_id, false); - - if (SDL_GetAudioDeviceStatus(microphone->device_id) != SDL_AUDIO_PLAYING) + SDL_PauseAudioDevice(mic->device_id, false); + if (SDL_GetAudioDeviceStatus(mic->device_id) != SDL_AUDIO_PLAYING) { - RARCH_ERR("[SDL mic]: Failed to start microphone %u: %s\n", microphone->device_id, SDL_GetError()); + RARCH_ERR("[SDL mic]: Failed to start microphone %u: %s\n", mic->device_id, SDL_GetError()); return false; } - - RARCH_DBG("[SDL mic]: Started microphone %u\n", microphone->device_id); + RARCH_DBG("[SDL mic]: Started microphone %u\n", mic->device_id); return true; } -static bool sdl_microphone_stop_mic(void *driver_context, void *microphone_context) +static bool sdl_microphone_stop_mic(void *driver_context, void *mic_context) { - sdl_microphone_t *sdl = (sdl_microphone_t*)driver_context; - sdl_microphone_handle_t *microphone = (sdl_microphone_handle_t*)microphone_context; + sdl_microphone_t *sdl = (sdl_microphone_t*)driver_context; + sdl_microphone_handle_t *mic = (sdl_microphone_handle_t*)mic_context; - if (!sdl || !microphone) + if (!sdl || !mic) return false; - SDL_PauseAudioDevice(microphone->device_id, true); + SDL_PauseAudioDevice(mic->device_id, true); - switch (SDL_GetAudioDeviceStatus(microphone->device_id)) + switch (SDL_GetAudioDeviceStatus(mic->device_id)) { case SDL_AUDIO_PLAYING: - RARCH_ERR("[SDL mic]: Microphone %u failed to pause\n", microphone->device_id); + RARCH_ERR("[SDL mic]: Microphone %u failed to pause\n", mic->device_id); return false; case SDL_AUDIO_STOPPED: - RARCH_WARN("[SDL mic]: Microphone %u is in state STOPPED; it may not start again\n", microphone->device_id); + RARCH_WARN("[SDL mic]: Microphone %u is in state STOPPED; it may not start again\n", + mic->device_id); /* fall-through */ case SDL_AUDIO_PAUSED: break; default: - RARCH_ERR("[SDL mic]: Microphone %u is in unknown state\n", microphone->device_id); + RARCH_ERR("[SDL mic]: Microphone %u is in unknown state\n", + mic->device_id); return false; } @@ -305,64 +295,68 @@ static void sdl_microphone_set_nonblock_state(void *driver_context, bool state) sdl->nonblock = state; } -static int sdl_microphone_read(void *driver_context, void *microphone_context, void *buf, size_t size) +static int sdl_microphone_read(void *driver_context, void *mic_context, void *s, size_t len) { - int ret = 0; - sdl_microphone_t *sdl = (sdl_microphone_t*)driver_context; - sdl_microphone_handle_t *microphone = (sdl_microphone_handle_t*)microphone_context; + int ret = 0; + sdl_microphone_t *sdl = (sdl_microphone_t*)driver_context; + sdl_microphone_handle_t *mic = (sdl_microphone_handle_t*)mic_context; - if (!sdl || !microphone || !buf) + if (!sdl || !mic || !s) return -1; + /* If we shouldn't block on an empty queue... */ if (sdl->nonblock) - { /* If we shouldn't block on an empty queue... */ + { size_t avail, read_amt; - SDL_LockAudioDevice(microphone->device_id); /* Stop the SDL mic thread */ - avail = FIFO_READ_AVAIL(microphone->sample_buffer); - read_amt = avail > size ? size : avail; + SDL_LockAudioDevice(mic->device_id); /* Stop the SDL mic thread */ + avail = FIFO_READ_AVAIL(mic->sample_buffer); + read_amt = avail > len ? len : avail; if (read_amt > 0) { /* If the incoming queue isn't empty... */ - fifo_read(microphone->sample_buffer, buf, read_amt); + fifo_read(mic->sample_buffer, s, read_amt); /* ...then read as much data as will fit in buf */ } - SDL_UnlockAudioDevice(microphone->device_id); /* Let the mic thread run again */ + SDL_UnlockAudioDevice(mic->device_id); /* Let the mic thread run again */ ret = (int)read_amt; } else { size_t read = 0; - while (read < size) - { /* Until we've given the caller as much data as they've asked for... */ + /* Until we've given the caller as much data as they've asked for... */ + while (read < len) + { size_t avail; - SDL_LockAudioDevice(microphone->device_id); + SDL_LockAudioDevice(mic->device_id); /* Stop the SDL microphone thread from running */ - avail = FIFO_READ_AVAIL(microphone->sample_buffer); + avail = FIFO_READ_AVAIL(mic->sample_buffer); if (avail == 0) { /* If the incoming sample queue is empty... */ - SDL_UnlockAudioDevice(microphone->device_id); - /* Let the SDL microphone thread run so it can push some incoming samples */ + SDL_UnlockAudioDevice(mic->device_id); + /* Let the SDL microphone thread run so it can + * push some incoming samples */ #ifdef HAVE_THREADS - slock_lock(microphone->lock); - /* Let *only* the SDL microphone thread access the incoming sample queue. */ - - scond_wait(microphone->cond, microphone->lock); - /* Wait until the SDL microphone thread tells us it's added some samples. */ - - slock_unlock(microphone->lock); - /* Allow this thread to access the incoming sample queue, which we'll do next iteration */ + slock_lock(mic->lock); + /* Let *only* the SDL microphone thread access + * the incoming sample queue. */ + scond_wait(mic->cond, mic->lock); + /* Wait until the SDL microphone thread tells us + * it's added some samples. */ + slock_unlock(mic->lock); + /* Allow this thread to access the incoming sample queue, + * which we'll do next iteration */ #endif } else { - size_t read_amt = MIN(size - read, avail); - fifo_read(microphone->sample_buffer, buf + read, read_amt); - /* Read as many samples as we have available without underflowing the queue */ - - SDL_UnlockAudioDevice(microphone->device_id); + size_t read_amt = MIN(len - read, avail); + fifo_read(mic->sample_buffer, s + read, read_amt); + /* Read as many samples as we have available without + * underflowing the queue */ + SDL_UnlockAudioDevice(mic->device_id); /* Let the SDL microphone thread run again */ read += read_amt; } @@ -373,10 +367,10 @@ static int sdl_microphone_read(void *driver_context, void *microphone_context, v return ret; } -static bool sdl_microphone_mic_use_float(const void *driver_context, const void *microphone_context) +static bool sdl_microphone_mic_use_float(const void *driver_context, const void *mic_context) { - sdl_microphone_handle_t *microphone = (sdl_microphone_handle_t*)microphone_context; - return SDL_AUDIO_ISFLOAT(microphone->device_spec.format); + sdl_microphone_handle_t *mic = (sdl_microphone_handle_t*)mic_context; + return SDL_AUDIO_ISFLOAT(mic->device_spec.format); } microphone_driver_t microphone_sdl = { diff --git a/audio/drivers_microphone/wasapi.c b/audio/drivers_microphone/wasapi.c index fc51e4f175..775a7c9743 100644 --- a/audio/drivers_microphone/wasapi.c +++ b/audio/drivers_microphone/wasapi.c @@ -51,34 +51,61 @@ typedef struct wasapi_microphone bool nonblock; } wasapi_microphone_t; +static void wasapi_microphone_close_mic(void *driver_context, void *mic_context) +{ + DWORD ir; + HANDLE write_event; + wasapi_microphone_t *wasapi = (wasapi_microphone_t*)driver_context; + wasapi_microphone_handle_t *mic = (wasapi_microphone_handle_t*)mic_context; + + if (!wasapi || !mic) + return; + + write_event = mic->read_event; + + IFACE_RELEASE(mic->capture); + if (mic->client) + _IAudioClient_Stop(mic->client); + IFACE_RELEASE(mic->client); + IFACE_RELEASE(mic->device); + if (mic->buffer) + fifo_free(mic->buffer); + if (mic->device_name) + free(mic->device_name); + free(mic); + + ir = WaitForSingleObject(write_event, 20); + if (ir == WAIT_FAILED) + { + RARCH_ERR("[WASAPI mic]: WaitForSingleObject failed: %s\n", wasapi_error(GetLastError())); + } + + /* If event isn't signaled log and leak */ + if (ir != WAIT_OBJECT_0) + return; + + CloseHandle(write_event); +} -static void wasapi_microphone_close_mic(void *driver_context, void *microphone_context); static void *wasapi_microphone_init(void) { - settings_t *settings = config_get_ptr(); wasapi_microphone_t *wasapi = (wasapi_microphone_t*)calloc(1, sizeof(wasapi_microphone_t)); - if (!wasapi) { RARCH_ERR("[WASAPI mic]: Failed to allocate microphone driver context\n"); return NULL; } - - wasapi->nonblock = !settings->bools.audio_sync; + wasapi->nonblock = !config_get_ptr()->bools.audio_sync; RARCH_DBG("[WASAPI mic]: Initialized microphone driver context.\n"); - return wasapi; } static void wasapi_microphone_free(void *driver_context) { wasapi_microphone_t *wasapi = (wasapi_microphone_t*)driver_context; - - if (!wasapi) - return; - - free(wasapi); + if (wasapi) + free(wasapi); } /** @@ -90,7 +117,7 @@ static void wasapi_microphone_free(void *driver_context) * @return The number of bytes in the queue after fetching input, * or -1 if there was an error. */ -static int wasapi_microphone_fetch_fifo(wasapi_microphone_handle_t *microphone) +static int wasapi_microphone_fetch_fifo(wasapi_microphone_handle_t *mic) { UINT32 next_packet_size = 0; /* Shared-mode capture streams split their input buffer into multiple packets, @@ -106,21 +133,20 @@ static int wasapi_microphone_fetch_fifo(wasapi_microphone_handle_t *microphone) UINT32 frames_read = 0; UINT32 bytes_read = 0; DWORD buffer_status_flags = 0; - HRESULT hr = _IAudioCaptureClient_GetBuffer(microphone->capture, + HRESULT hr = _IAudioCaptureClient_GetBuffer(mic->capture, &mic_input, &frames_read, &buffer_status_flags, NULL, NULL); if (FAILED(hr)) { RARCH_ERR("[WASAPI]: Failed to get capture device \"%s\"'s buffer: %s\n", - microphone->device_name, - hresult_name(hr)); + mic->device_name, hresult_name(hr)); return -1; } - bytes_read = frames_read * microphone->frame_size; + bytes_read = frames_read * mic->frame_size; /* If the queue has room for the packets we just got... */ - if (FIFO_WRITE_AVAIL(microphone->buffer) >= bytes_read && bytes_read > 0) + if (FIFO_WRITE_AVAIL(mic->buffer) >= bytes_read && bytes_read > 0) { - fifo_write(microphone->buffer, mic_input, bytes_read); + fifo_write(mic->buffer, mic_input, bytes_read); /* ...then enqueue the bytes directly from the mic's buffer */ } else /* Not enough space for new frames, so we can't consume this packet right now */ @@ -128,25 +154,23 @@ static int wasapi_microphone_fetch_fifo(wasapi_microphone_handle_t *microphone) /* If there's insufficient room in the queue, then we can't read the packet. * In that case, we leave the packet for next time. */ - hr = _IAudioCaptureClient_ReleaseBuffer(microphone->capture, frames_read); + hr = _IAudioCaptureClient_ReleaseBuffer(mic->capture, frames_read); if (FAILED(hr)) { RARCH_ERR("[WASAPI]: Failed to release capture device \"%s\"'s buffer after consuming %u frames: %s\n", - microphone->device_name, - frames_read, - hresult_name(hr)); + mic->device_name, frames_read, hresult_name(hr)); return -1; } /* If this is a shared-mode stream and we didn't run out of room in the sample queue... */ - if (!microphone->exclusive && frames_read > 0) + if (!mic->exclusive && frames_read > 0) { - hr = _IAudioCaptureClient_GetNextPacketSize(microphone->capture, &next_packet_size); + hr = _IAudioCaptureClient_GetNextPacketSize(mic->capture, &next_packet_size); /* Get the number of frames that the mic has for us. */ if (FAILED(hr)) { RARCH_ERR("[WASAPI]: Failed to get capture device \"%s\"'s next packet size: %s\n", - microphone->device_name, hresult_name(hr)); + mic->device_name, hresult_name(hr)); return -1; } } @@ -156,7 +180,7 @@ static int wasapi_microphone_fetch_fifo(wasapi_microphone_handle_t *microphone) } while (next_packet_size != 0); - return FIFO_READ_AVAIL(microphone->buffer); + return FIFO_READ_AVAIL(mic->buffer); } /** @@ -167,20 +191,20 @@ static int wasapi_microphone_fetch_fifo(wasapi_microphone_handle_t *microphone) * @return \c true if the event was signalled, * \c false if it timed out or there was an error. */ -static bool wasapi_microphone_wait_for_capture_event(wasapi_microphone_handle_t *microphone, DWORD timeout) +static bool wasapi_microphone_wait_for_capture_event(wasapi_microphone_handle_t *mic, DWORD timeout) { /*...then let's wait for the mic to tell us that samples are ready. */ - switch (WaitForSingleObject(microphone->read_event, timeout)) + switch (WaitForSingleObject(mic->read_event, timeout)) { case WAIT_OBJECT_0: /* Okay, there's data available. */ return true; case WAIT_TIMEOUT: /* Time out; there's nothing here for us. */ - RARCH_ERR("[WASAPI]: Failed to wait for capture device \"%s\" event: Timeout after %ums\n", microphone->device_name, timeout); + RARCH_ERR("[WASAPI]: Failed to wait for capture device \"%s\" event: Timeout after %ums\n", mic->device_name, timeout); break; default: - RARCH_ERR("[WASAPI]: Failed to wait for capture device \"%s\" event: %s\n", microphone->device_name, wasapi_error(GetLastError())); + RARCH_ERR("[WASAPI]: Failed to wait for capture device \"%s\" event: %s\n", mic->device_name, wasapi_error(GetLastError())); break; } return false; @@ -202,22 +226,20 @@ static bool wasapi_microphone_wait_for_capture_event(wasapi_microphone_handle_t * or -1 if there was an error (including timeout). */ static int wasapi_microphone_read_buffered( - wasapi_microphone_handle_t *microphone, - void *buffer, - size_t buffer_size, + wasapi_microphone_handle_t *mic, void *s, size_t len, DWORD timeout) { int bytes_read = 0; /* Number of bytes sent to the core */ - int bytes_available = FIFO_READ_AVAIL(microphone->buffer); + int bytes_available = FIFO_READ_AVAIL(mic->buffer); /* If we don't have any queued samples to give to the core... */ if (!bytes_available) { /* If we couldn't wait for the microphone to signal a capture event... */ - if (!wasapi_microphone_wait_for_capture_event(microphone, timeout)) + if (!wasapi_microphone_wait_for_capture_event(mic, timeout)) return -1; - bytes_available = wasapi_microphone_fetch_fifo(microphone); + bytes_available = wasapi_microphone_fetch_fifo(mic); /* If we couldn't fetch samples from the microphone... */ if (bytes_available < 0) return -1; @@ -225,34 +247,33 @@ static int wasapi_microphone_read_buffered( /* Now that we have samples available, let's give them to the core */ - bytes_read = MIN((int)buffer_size, bytes_available); - fifo_read(microphone->buffer, buffer, bytes_read); + bytes_read = MIN((int)len, bytes_available); + fifo_read(mic->buffer, s, bytes_read); /* Read data from the sample queue and store it in the provided buffer */ - return bytes_read; } -static int wasapi_microphone_read(void *driver_context, void *mic_context, void *buffer, size_t buffer_size) +static int wasapi_microphone_read(void *driver_context, void *mic_context, void *s, size_t len) { - int bytes_read = 0; - wasapi_microphone_t *wasapi = (wasapi_microphone_t *)driver_context; - wasapi_microphone_handle_t *microphone = (wasapi_microphone_handle_t*)mic_context; + int bytes_read = 0; + wasapi_microphone_t *wasapi = (wasapi_microphone_t *)driver_context; + wasapi_microphone_handle_t *mic = (wasapi_microphone_handle_t*)mic_context; - if (!wasapi || !microphone || !buffer) + if (!wasapi || !mic || !s) return -1; /* If microphones shouldn't block... */ if (wasapi->nonblock) - return wasapi_microphone_read_buffered(microphone, buffer, buffer_size, 0); + return wasapi_microphone_read_buffered(mic, s, len, 0); - if (microphone->exclusive) + if (mic->exclusive) { int read; - for (read = -1; (size_t)bytes_read < buffer_size; bytes_read += read) + for (read = -1; (size_t)bytes_read < len; bytes_read += read) { - read = wasapi_microphone_read_buffered(microphone, - (char *)buffer + bytes_read, - buffer_size - bytes_read, + read = wasapi_microphone_read_buffered(mic, + (char *)s + bytes_read, + len - bytes_read, INFINITE); if (read == -1) return -1; @@ -261,11 +282,11 @@ static int wasapi_microphone_read(void *driver_context, void *mic_context, void else { int read; - for (read = -1; (size_t)bytes_read < buffer_size; bytes_read += read) + for (read = -1; (size_t)bytes_read < len; bytes_read += read) { - read = wasapi_microphone_read_buffered(microphone, - (char *)buffer + bytes_read, - buffer_size - bytes_read, + read = wasapi_microphone_read_buffered(mic, + (char *)s + bytes_read, + len - bytes_read, INFINITE); if (read == -1) return -1; @@ -278,7 +299,6 @@ static int wasapi_microphone_read(void *driver_context, void *mic_context, void static void wasapi_microphone_set_nonblock_state(void *driver_context, bool nonblock) { wasapi_microphone_t *wasapi = (wasapi_microphone_t*)driver_context; - wasapi->nonblock = nonblock; } @@ -286,81 +306,80 @@ static void *wasapi_microphone_open_mic(void *driver_context, const char *device unsigned latency, unsigned *new_rate) { HRESULT hr; - settings_t *settings = config_get_ptr(); - DWORD flags = 0; - UINT32 frame_count = 0; - REFERENCE_TIME dev_period = 0; - BYTE *dest = NULL; - bool float_format = settings->bools.microphone_wasapi_float_format; - bool exclusive_mode = settings->bools.microphone_wasapi_exclusive_mode; - unsigned sh_buffer_length = settings->uints.microphone_wasapi_sh_buffer_length; - wasapi_microphone_handle_t *microphone = (wasapi_microphone_handle_t*)calloc( + settings_t *settings = config_get_ptr(); + DWORD flags = 0; + UINT32 frame_count = 0; + REFERENCE_TIME dev_period = 0; + BYTE *dest = NULL; + bool float_format = settings->bools.microphone_wasapi_float_format; + bool exclusive_mode = settings->bools.microphone_wasapi_exclusive_mode; + unsigned sh_buffer_length = settings->uints.microphone_wasapi_sh_buffer_length; + wasapi_microphone_handle_t *mic = (wasapi_microphone_handle_t*)calloc( 1, sizeof(wasapi_microphone_handle_t)); - if (!microphone) + if (!mic) return NULL; - microphone->exclusive = exclusive_mode; - microphone->device = wasapi_init_device(device, eCapture); + mic->exclusive = exclusive_mode; + mic->device = wasapi_init_device(device, eCapture); /* If we requested a particular capture device, but couldn't open it... */ - if (device && !microphone->device) + if (device && !mic->device) { RARCH_WARN("[WASAPI]: Failed to open requested capture device \"%s\", attempting to open default device\n", device); - microphone->device = wasapi_init_device(NULL, eCapture); + mic->device = wasapi_init_device(NULL, eCapture); } - if (!microphone->device) + if (!mic->device) { RARCH_ERR("[WASAPI]: Failed to open capture device\n"); goto error; } - microphone->device_name = mmdevice_name(microphone->device); - if (!microphone->device_name) + if (!(mic->device_name = mmdevice_name(mic->device))) { RARCH_ERR("[WASAPI]: Failed to get friendly name of capture device\n"); goto error; } - microphone->client = wasapi_init_client(microphone->device, - µphone->exclusive, &float_format, &rate, latency, 1); - if (!microphone->client) + mic->client = wasapi_init_client(mic->device, + &mic->exclusive, &float_format, &rate, latency, 1); + if (!mic->client) { - RARCH_ERR("[WASAPI]: Failed to open client for capture device \"%s\"\n", microphone->device_name); + RARCH_ERR("[WASAPI]: Failed to open client for capture device \"%s\"\n", mic->device_name); goto error; } - hr = _IAudioClient_GetBufferSize(microphone->client, &frame_count); + hr = _IAudioClient_GetBufferSize(mic->client, &frame_count); if (FAILED(hr)) { RARCH_ERR("[WASAPI]: Failed to get buffer size of IAudioClient for capture device \"%s\": %s\n", - microphone->device_name, hresult_name(hr)); + mic->device_name, hresult_name(hr)); goto error; } - microphone->frame_size = float_format ? sizeof(float) : sizeof(int16_t); - microphone->engine_buffer_size = frame_count * microphone->frame_size; + mic->frame_size = float_format ? sizeof(float) : sizeof(int16_t); + mic->engine_buffer_size = frame_count * mic->frame_size; /* If this mic should be used *exclusively* by RetroArch... */ - if (microphone->exclusive) + if (mic->exclusive) { - microphone->buffer = fifo_new(microphone->engine_buffer_size); - if (!microphone->buffer) + mic->buffer = fifo_new(mic->engine_buffer_size); + if (!mic->buffer) { RARCH_ERR("[WASAPI]: Failed to initialize FIFO queue for capture device.\n"); goto error; } RARCH_LOG("[WASAPI]: Intermediate exclusive-mode capture buffer length is %u frames (%.1fms, %u bytes).\n", - frame_count, (double)frame_count * 1000.0 / rate, microphone->engine_buffer_size); + frame_count, (double)frame_count * 1000.0 / rate, mic->engine_buffer_size); } else { /* If the user selected the "default" shared buffer length... */ if (sh_buffer_length <= 0) { - hr = _IAudioClient_GetDevicePeriod(microphone->client, &dev_period, NULL); + hr = _IAudioClient_GetDevicePeriod(mic->client, &dev_period, NULL); if (FAILED(hr)) goto error; @@ -369,30 +388,29 @@ static void *wasapi_microphone_open_mic(void *driver_context, const char *device * Doubling it seems to work okay. Dunno why. */ } - microphone->buffer = fifo_new(sh_buffer_length * microphone->frame_size); - if (!microphone->buffer) + mic->buffer = fifo_new(sh_buffer_length * mic->frame_size); + if (!mic->buffer) goto error; RARCH_LOG("[WASAPI]: Intermediate shared-mode capture buffer length is %u frames (%.1fms, %u bytes).\n", - sh_buffer_length, (double)sh_buffer_length * 1000.0 / rate, sh_buffer_length * microphone->frame_size); + sh_buffer_length, (double)sh_buffer_length * 1000.0 / rate, sh_buffer_length * mic->frame_size); } - microphone->read_event = CreateEventA(NULL, FALSE, FALSE, NULL); - if (!microphone->read_event) + if (!(mic->read_event = CreateEventA(NULL, FALSE, FALSE, NULL))) { RARCH_ERR("[WASAPI]: Failed to allocate capture device's event handle\n"); goto error; } - hr = _IAudioClient_SetEventHandle(microphone->client, microphone->read_event); + hr = _IAudioClient_SetEventHandle(mic->client, mic->read_event); if (FAILED(hr)) { RARCH_ERR("[WASAPI]: Failed to set capture device's event handle: %s\n", hresult_name(hr)); goto error; } - hr = _IAudioClient_GetService(microphone->client, - IID_IAudioCaptureClient, (void**)µphone->capture); + hr = _IAudioClient_GetService(mic->client, + IID_IAudioCaptureClient, (void**)&mic->capture); if (FAILED(hr)) { RARCH_ERR("[WASAPI]: Failed to get capture device's IAudioCaptureClient service: %s\n", hresult_name(hr)); @@ -400,132 +418,81 @@ static void *wasapi_microphone_open_mic(void *driver_context, const char *device } /* Get and release the buffer, just to ensure that we can. */ - hr = _IAudioCaptureClient_GetBuffer(microphone->capture, &dest, &frame_count, &flags, NULL, NULL); + hr = _IAudioCaptureClient_GetBuffer(mic->capture, &dest, &frame_count, &flags, NULL, NULL); if (FAILED(hr)) { RARCH_ERR("[WASAPI]: Failed to get capture client buffer: %s\n", hresult_name(hr)); goto error; } - hr = _IAudioCaptureClient_ReleaseBuffer(microphone->capture, 0); + hr = _IAudioCaptureClient_ReleaseBuffer(mic->capture, 0); if (FAILED(hr)) { RARCH_ERR("[WASAPI]: Failed to release capture client buffer: %s\n", hresult_name(hr)); goto error; } + /* The rate was (possibly) modified when we initialized the client */ if (new_rate) - { /* The rate was (possibly) modified when we initialized the client */ *new_rate = rate; - } - return microphone; + return mic; error: - IFACE_RELEASE(microphone->capture); - IFACE_RELEASE(microphone->client); - IFACE_RELEASE(microphone->device); - if (microphone->read_event) - CloseHandle(microphone->read_event); - if (microphone->buffer) - fifo_free(microphone->buffer); - if (microphone->device_name) - free(microphone->device_name); - free(microphone); - + IFACE_RELEASE(mic->capture); + IFACE_RELEASE(mic->client); + IFACE_RELEASE(mic->device); + if (mic->read_event) + CloseHandle(mic->read_event); + if (mic->buffer) + fifo_free(mic->buffer); + if (mic->device_name) + free(mic->device_name); + free(mic); return NULL; } -static void wasapi_microphone_close_mic(void *driver_context, void *microphone_context) +static bool wasapi_microphone_start_mic(void *driver_context, void *mic_context) { - DWORD ir; - wasapi_microphone_t *wasapi = (wasapi_microphone_t*)driver_context; - wasapi_microphone_handle_t *microphone = (wasapi_microphone_handle_t*)microphone_context; - HANDLE write_event; - - if (!wasapi || !microphone) - return; - - write_event = microphone->read_event; - - IFACE_RELEASE(microphone->capture); - if (microphone->client) - _IAudioClient_Stop(microphone->client); - IFACE_RELEASE(microphone->client); - IFACE_RELEASE(microphone->device); - if (microphone->buffer) - fifo_free(microphone->buffer); - if (microphone->device_name) - free(microphone->device_name); - free(microphone); - - ir = WaitForSingleObject(write_event, 20); - if (ir == WAIT_FAILED) - { - RARCH_ERR("[WASAPI mic]: WaitForSingleObject failed: %s\n", wasapi_error(GetLastError())); - } - - /* If event isn't signaled log and leak */ - if (ir != WAIT_OBJECT_0) - return; - - CloseHandle(write_event); -} - -static bool wasapi_microphone_start_mic(void *driver_context, void *microphone_context) -{ - wasapi_microphone_handle_t *microphone = (wasapi_microphone_handle_t*)microphone_context; + wasapi_microphone_handle_t *mic = (wasapi_microphone_handle_t*)mic_context; HRESULT hr; - (void)driver_context; - - if (!microphone) + if (!mic) return false; + hr = _IAudioClient_Start(mic->client); - hr = _IAudioClient_Start(microphone->client); - + /* Starting an already-active microphone is not an error */ if (SUCCEEDED(hr) || hr == AUDCLNT_E_NOT_STOPPED) - { /* Starting an already-active microphone is not an error */ - microphone->running = true; - } + mic->running = true; else { RARCH_ERR("[WASAPI mic]: Failed to start capture device \"%s\"'s IAudioClient: %s\n", - microphone->device_name, hresult_name(hr)); - microphone->running = false; + mic->device_name, hresult_name(hr)); + mic->running = false; } - - return microphone->running; + return mic->running; } -static bool wasapi_microphone_stop_mic(void *driver_context, void *microphone_context) +static bool wasapi_microphone_stop_mic(void *driver_context, void *mic_context) { - wasapi_microphone_handle_t *microphone = (wasapi_microphone_handle_t*)microphone_context; + wasapi_microphone_handle_t *mic = (wasapi_microphone_handle_t*)mic_context; HRESULT hr; - (void)driver_context; - - if (!microphone) + if (!mic) return false; - - hr = _IAudioClient_Stop(microphone->client); + hr = _IAudioClient_Stop(mic->client); if (FAILED(hr)) { RARCH_ERR("[WASAPI mic]: Failed to stop capture device \"%s\"'s IAudioClient: %s\n", - microphone->device_name, hresult_name(hr)); + mic->device_name, hresult_name(hr)); return false; } - - RARCH_LOG("[WASAPI mic]: Stopped capture device \"%s\".\n", microphone->device_name); - - microphone->running = false; - + RARCH_LOG("[WASAPI mic]: Stopped capture device \"%s\".\n", mic->device_name); + mic->running = false; return true; } static bool wasapi_microphone_mic_alive(const void *driver_context, const void *mic_context) { - wasapi_microphone_handle_t *microphone = (wasapi_microphone_handle_t *)mic_context; - (void)driver_context; - - return microphone && microphone->running; + wasapi_microphone_handle_t *mic = (wasapi_microphone_handle_t *)mic_context; + return mic && mic->running; } static struct string_list *wasapi_microphone_device_list_new(const void *driver_context) @@ -536,20 +503,14 @@ static struct string_list *wasapi_microphone_device_list_new(const void *driver_ static void wasapi_microphone_device_list_free(const void *driver_context, struct string_list *devices) { struct string_list *sl = (struct string_list*)devices; - if (sl) string_list_free(sl); } -static bool wasapi_microphone_use_float(const void *driver_context, const void *microphone_context) +static bool wasapi_microphone_use_float(const void *driver_context, const void *mic_context) { - wasapi_microphone_handle_t *microphone = (wasapi_microphone_handle_t *)microphone_context; - (void)driver_context; - - if (!microphone) - return false; - - return microphone->frame_size == sizeof(float); + wasapi_microphone_handle_t *mic = (wasapi_microphone_handle_t *)mic_context; + return (mic && (mic->frame_size == sizeof(float))); } microphone_driver_t microphone_wasapi = { diff --git a/audio/librsound.c b/audio/librsound.c index 6034930618..49a508ec44 100644 --- a/audio/librsound.c +++ b/audio/librsound.c @@ -150,8 +150,8 @@ static int init_count = 0; #define net_recv(a,b,c,d) recv(a,b,c,d) #endif -static ssize_t rsnd_send_chunk(int socket, const void *buf, size_t size, int blocking); -static ssize_t rsnd_recv_chunk(int socket, void *buf, size_t size, int blocking); +static ssize_t rsnd_send_chunk(int socket, const void *s, size_t len, int blocking); +static ssize_t rsnd_recv_chunk(int socket, void *s, size_t len, int blocking); static int rsnd_start_thread(rsound_t *rd); static int rsnd_stop_thread(rsound_t *rd); static size_t rsnd_get_delay(rsound_t *rd); @@ -177,20 +177,20 @@ static INLINE int rsnd_is_little_endian(void) } /* Simple functions for swapping bytes */ -static INLINE void rsnd_swap_endian_16 ( uint16_t * x ) +static INLINE void rsnd_swap_endian_16(uint16_t *x) { *x = (*x>>8) | (*x<<8); } -static INLINE void rsnd_swap_endian_32 ( uint32_t * x ) +static INLINE void rsnd_swap_endian_32(uint32_t *x) { - *x = (*x >> 24 ) | - ((*x<<8) & 0x00FF0000) | - ((*x>>8) & 0x0000FF00) | - (*x << 24); + *x = (*x >> 24) + | ((*x<<8) & 0x00FF0000) + | ((*x>>8) & 0x0000FF00) + | (*x << 24); } -static INLINE int rsnd_format_to_samplesize ( uint16_t fmt ) +static INLINE int rsnd_format_to_samplesize(uint16_t fmt) { switch(fmt) { @@ -217,22 +217,20 @@ static INLINE int rsnd_format_to_samplesize ( uint16_t fmt ) return 1; default: - return -1; + break; } + return -1; } -int rsd_samplesize( rsound_t *rd ) -{ - return rd->samplesize; -} +int rsd_samplesize(rsound_t *rd) { return rd->samplesize; } -/* Creates sockets and attempts to connect to the server. Returns -1 when failed, and 0 when success. */ -static int rsnd_connect_server( rsound_t *rd ) +/* Creates sockets and attempts to connect to the server. + * Returns -1 when failed, and 0 when success. */ +static int rsnd_connect_server(rsound_t *rd) { struct sockaddr_in addr; struct pollfd fd; int i = 1; - (void)i; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; @@ -252,11 +250,11 @@ static int rsnd_connect_server( rsound_t *rd ) rd->conn_type = RSD_CONN_TCP; rd->conn.socket = net_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if ( rd->conn.socket < 0 ) + if (rd->conn.socket < 0) goto error; rd->conn.ctl_socket = net_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if ( rd->conn.ctl_socket < 0 ) + if (rd->conn.ctl_socket < 0) goto error; /* Uses non-blocking IO since it performed more deterministic with poll()/send() */ @@ -295,61 +293,68 @@ error: return -1; } -/* Conjures a WAV-header and sends this to server. Returns -1 when failed, and 0 when success. */ +/* Fancy macros for embedding little endian values into the header. */ +#define SET32(buf,offset,x) (*((uint32_t*)(buf+offset)) = x) +#define SET16(buf,offset,x) (*((uint16_t*)(buf+offset)) = x) + +#define LSB16(x) if (!rsnd_is_little_endian()) { rsnd_swap_endian_16(&(x)); } +#define LSB32(x) if (!rsnd_is_little_endian()) { rsnd_swap_endian_32(&(x)); } + +#define HEADER_SIZE 44 +#define RATE 24 +#define CHANNEL 22 +#define FRAMESIZE 34 +#define FORMAT 42 + +/* Conjures a WAV-header and sends this to server. + * Returns -1 when failed, and 0 when success. */ static int rsnd_send_header_info(rsound_t *rd) { - + uint32_t temp_rate, temp32; + uint16_t temp_channels, temp_bits, temp_format, temp16; /* Defines the size of a wave header */ -#define HEADER_SIZE 44 - char *header = calloc(1, HEADER_SIZE); + char *header = (char*)calloc(1, HEADER_SIZE); if (!header) { RSD_ERR("[RSound] Could not allocate memory."); return -1; } - uint16_t temp16; - uint32_t temp32; /* These magic numbers represent the position of the elements in the wave header. We can't simply send a wave struct over the network since the compiler is allowed to pad our structs as they like, so sizeof(waveheader) might not be similar on two different systems. */ -#define RATE 24 -#define CHANNEL 22 -#define FRAMESIZE 34 -#define FORMAT 42 + temp_rate = rd->rate; + temp_channels = rd->channels; - uint32_t temp_rate = rd->rate; - uint16_t temp_channels = rd->channels; - - uint16_t temp_bits = 8 * rsnd_format_to_samplesize(rd->format); - uint16_t temp_format = rd->format; + temp_bits = 8 * rsnd_format_to_samplesize(rd->format); + temp_format = rd->format; /* Checks the format for native endian which will need to be set properly. */ - switch ( temp_format ) + switch (temp_format) { case RSD_S16_NE: - if ( rsnd_is_little_endian() ) + if (rsnd_is_little_endian()) temp_format = RSD_S16_LE; else temp_format = RSD_S16_BE; break; case RSD_U16_NE: - if ( rsnd_is_little_endian() ) + if (rsnd_is_little_endian()) temp_format = RSD_U16_LE; else temp_format = RSD_U16_BE; break; case RSD_S32_NE: - if ( rsnd_is_little_endian() ) + if (rsnd_is_little_endian()) temp_format = RSD_S32_LE; else temp_format = RSD_S32_BE; break; case RSD_U32_NE: - if ( rsnd_is_little_endian() ) + if (rsnd_is_little_endian()) temp_format = RSD_U32_LE; else temp_format = RSD_U32_BE; @@ -363,12 +368,6 @@ static int rsnd_send_header_info(rsound_t *rd) to determine whether we're running it or not, so we can byte swap accordingly. Could determine this compile time, but it was simpler to do it this way. */ - /* Fancy macros for embedding little endian values into the header. */ -#define SET32(buf,offset,x) (*((uint32_t*)(buf+offset)) = x) -#define SET16(buf,offset,x) (*((uint16_t*)(buf+offset)) = x) - -#define LSB16(x) if ( !rsnd_is_little_endian() ) { rsnd_swap_endian_16(&(x)); } -#define LSB32(x) if ( !rsnd_is_little_endian() ) { rsnd_swap_endian_32(&(x)); } /* Here we embed in the rest of the WAV header for it to be somewhat valid */ @@ -383,7 +382,7 @@ static int rsnd_send_header_info(rsound_t *rd) temp16 = 0; /* PCM data */ - switch( rd->format ) + switch (rd->format) { case RSD_S16_LE: case RSD_U8: @@ -421,7 +420,7 @@ static int rsnd_send_header_info(rsound_t *rd) LSB16(temp_bits); SET16(header, FRAMESIZE, temp_bits); - strlcpy(header+36, "data", sizeof(header)); + strlcpy(header + 36, "data", sizeof(header)); /* Do not care about cksize here (impossible to know beforehand). * It is used by the server for format. */ @@ -430,8 +429,8 @@ static int rsnd_send_header_info(rsound_t *rd) SET16(header, FORMAT, temp_format); /* End static header */ - - if ( rsnd_send_chunk(rd->conn.socket, header, HEADER_SIZE, 1) != HEADER_SIZE ) + if ( rsnd_send_chunk(rd->conn.socket, header, HEADER_SIZE, 1) + != HEADER_SIZE) { free(header); return -1; @@ -441,54 +440,62 @@ static int rsnd_send_header_info(rsound_t *rd) return 0; } -/* Receives backend info from server that is of interest to the client. (This mini-protocol might be extended later on.) */ -static int rsnd_get_backend_info ( rsound_t *rd ) -{ #define RSND_HEADER_SIZE 8 #define LATENCY 0 #define CHUNKSIZE 1 +#define MAX_CHUNK_SIZE 1024 /* We do not want larger chunk sizes than this. */ +#define MAX_TCP_BUFSIZE (1 << 14) + +/* Receives backend info from server that is of interest to the client. + * (This mini-protocol might be extended later on.) */ +static int rsnd_get_backend_info(rsound_t *rd) +{ /* Header is 2 uint32_t's. = 8 bytes. */ uint32_t rsnd_header[2] = {0}; - if ( rsnd_recv_chunk(rd->conn.socket, rsnd_header, RSND_HEADER_SIZE, 1) != RSND_HEADER_SIZE ) + if ( rsnd_recv_chunk(rd->conn.socket, rsnd_header, RSND_HEADER_SIZE, 1) + != RSND_HEADER_SIZE) { RSD_ERR("[RSound] Couldn't receive chunk.\n"); return -1; } - /* Again, we can't be 100% certain that sizeof(backend_info_t) is equal on every system */ + /* Again, we can't be 100% certain that sizeof(backend_info_t) + * is equal on every system */ - if ( rsnd_is_little_endian() ) + if (rsnd_is_little_endian()) { rsnd_swap_endian_32(&rsnd_header[LATENCY]); rsnd_swap_endian_32(&rsnd_header[CHUNKSIZE]); } - rd->backend_info.latency = rsnd_header[LATENCY]; + rd->backend_info.latency = rsnd_header[LATENCY]; rd->backend_info.chunk_size = rsnd_header[CHUNKSIZE]; -#define MAX_CHUNK_SIZE 1024 /* We do not want larger chunk sizes than this. */ - if ( rd->backend_info.chunk_size > MAX_CHUNK_SIZE || rd->backend_info.chunk_size <= 0 ) + if ( rd->backend_info.chunk_size > MAX_CHUNK_SIZE + || rd->backend_info.chunk_size <= 0) rd->backend_info.chunk_size = MAX_CHUNK_SIZE; - /* Assumes a default buffer size should it cause problems of being too small */ - if ( rd->buffer_size == 0 || rd->buffer_size < rd->backend_info.chunk_size * 2 ) + /* Assumes a default buffer size should it cause + * problems of being too small. */ + if ( rd->buffer_size == 0 + || rd->buffer_size < rd->backend_info.chunk_size * 2) rd->buffer_size = rd->backend_info.chunk_size * 32; - if ( rd->fifo_buffer != NULL ) + if (rd->fifo_buffer) fifo_free(rd->fifo_buffer); - rd->fifo_buffer = fifo_new (rd->buffer_size); - if (!rd->fifo_buffer) + + if (!(rd->fifo_buffer = fifo_new (rd->buffer_size))) { RSD_ERR("[RSound] Failed to create FIFO buffer.\n"); return -1; } /* Only bother with setting network buffer size if we're doing TCP. */ - if ( rd->conn_type & RSD_CONN_TCP ) + if (rd->conn_type & RSD_CONN_TCP) { -#define MAX_TCP_BUFSIZE (1 << 14) + int flag = 1; int bufsiz = rd->buffer_size; if (bufsiz > MAX_TCP_BUFSIZE) bufsiz = MAX_TCP_BUFSIZE; @@ -499,7 +506,6 @@ static int rsnd_get_backend_info ( rsound_t *rd ) bufsiz = rd->buffer_size; setsockopt(rd->conn.ctl_socket, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(int)); - int flag = 1; setsockopt(rd->conn.socket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); flag = 1; setsockopt(rd->conn.ctl_socket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); @@ -507,7 +513,7 @@ static int rsnd_get_backend_info ( rsound_t *rd ) /* Can we read the last 8 bytes so we can use the protocol interface? */ /* This is non-blocking. */ - if ( rsnd_recv_chunk(rd->conn.socket, rsnd_header, RSND_HEADER_SIZE, 0) == RSND_HEADER_SIZE ) + if (rsnd_recv_chunk(rd->conn.socket, rsnd_header, RSND_HEADER_SIZE, 0) == RSND_HEADER_SIZE) rd->conn_type |= RSD_CONN_PROTO; else { RSD_DEBUG("[RSound] Failed to get new proto.\n"); } @@ -522,44 +528,45 @@ static int rsnd_get_backend_info ( rsound_t *rd ) return 0; } -/* Makes sure that we're connected and done with wave header handshaking. Returns -1 on error, and 0 on success. - This goes for all other functions in use. */ +/* Makes sure that we're connected and done with wave header handshaking. + * Returns -1 on error, and 0 on success. + * This goes for all other functions in use. */ static int rsnd_create_connection(rsound_t *rd) { int rc; - - /* Are we connected to the server? If not, these values have been set to <0, so we make sure that we connect */ - if ( rd->conn.socket <= 0 && rd->conn.ctl_socket <= 0 ) + /* Are we connected to the server? If not, these values have + * been set to <0, so we make sure that we connect. */ + if (rd->conn.socket <= 0 && rd->conn.ctl_socket <= 0) { + struct pollfd fd; + rc = rsnd_connect_server(rd); if (rc < 0) { RSD_ERR("[RSound] connect server failed.\n"); - rsd_stop(rd); - return -1; + goto error; } - /* After connecting, makes really sure that we have a working connection. */ - struct pollfd fd; + /* After connecting, makes really sure that + * we have a working connection. */ pollfd_fd(fd) = rd->conn.socket; - fd.events = POLLOUT; + fd.events = POLLOUT; - if ( rsnd_poll(&fd, 1, 2000) < 0 ) + if (rsnd_poll(&fd, 1, 2000) < 0) { RSD_ERR("[RSound] rsnd_poll failed.\n"); - rsd_stop(rd); - return -1; + goto error; } - if ( !(fd.revents & POLLOUT) ) + if (!(fd.revents & POLLOUT)) { RSD_ERR("[RSound] Poll didn't return what we wanted.\n"); - rsd_stop(rd); - return -1; + goto error; } } + /* Is the server ready for data? The first thing it expects is the wave header */ - if ( !rd->ready_for_data ) + if (!rd->ready_for_data) { /* Part of the uber simple protocol. 1. Send wave header. @@ -570,120 +577,125 @@ static int rsnd_create_connection(rsound_t *rd) if (rc < 0) { RSD_ERR("[RSound] Send header failed.\n"); - rsd_stop(rd); - return -1; + goto error; } rc = rsnd_get_backend_info(rd); if (rc < 0) { RSD_ERR("[RSound] Get backend info failed.\n"); - rsd_stop(rd); - return -1; + goto error; } rc = rsnd_start_thread(rd); if (rc < 0) { RSD_ERR("[RSound] Starting thread failed.\n"); - rsd_stop(rd); - return -1; + goto error; } - if ( (rd->conn_type & RSD_CONN_PROTO) && strlen(rd->identity) > 0 ) - { + if ((rd->conn_type & RSD_CONN_PROTO) && strlen(rd->identity) > 0) rsnd_send_identity_info(rd); - } rd->ready_for_data = 1; } return 0; + +error: + rsd_stop(rd); + return -1; } -/* Sends a chunk over the network. Makes sure that everything is sent if blocking. Returns -1 if connection is lost, non-negative if success. - * If blocking, and not enough data is received, it will return -1. */ -static ssize_t rsnd_send_chunk(int socket, const void* buf, size_t size, int blocking) -{ - ssize_t rc = 0; - size_t wrote = 0; - ssize_t send_size = 0; - struct pollfd fd; - pollfd_fd(fd) = socket; - fd.events = POLLOUT; - - int sleep_time = (blocking) ? 10000 : 0; - #define MAX_PACKET_SIZE 1024 - while ( wrote < size ) +/* Sends a chunk over the network. Makes sure that everything is sent + * if blocking. + * Returns -1 if connection is lost, non-negative if success. + * If blocking, and not enough data is received, it will return -1. */ +static ssize_t rsnd_send_chunk(int socket, const void *s, + size_t len, int blocking) +{ + struct pollfd fd; + int sleep_time = 0; + ssize_t rc = 0; + ssize_t written = 0; + ssize_t send_size = 0; + + pollfd_fd(fd) = socket; + fd.events = POLLOUT; + + if (blocking) + sleep_time = 10000; + + while (written < len) { - if ( rsnd_poll(&fd, 1, sleep_time) < 0 ) + if (rsnd_poll(&fd, 1, sleep_time) < 0) return -1; - if ( fd.revents & POLLHUP ) + if (fd.revents & POLLHUP) { RSD_WARN("*** Remote side hung up! ***"); return -1; } - if ( fd.revents & POLLOUT ) + if (fd.revents & POLLOUT) { /* We try to limit ourselves to 1KiB packet sizes. */ - send_size = (size - wrote) > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : size - wrote; - rc = net_send(socket, (const char*)buf + wrote, send_size, 0); - if ( rc < 0 ) + send_size = (len - written) > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : len - written; + rc = net_send(socket, (const char*)s + written, send_size, 0); + if (rc < 0) { RSD_ERR("[RSound] Error sending chunk, %s.\n", strerror(errno)); return rc; } - wrote += rc; + written += rc; } else { - /* If server hasn't stopped blocking after 10 secs, then we should probably shut down the stream. */ - if ( blocking ) + /* If server hasn't stopped blocking after 10 secs, + * then we should probably shut down the stream. */ + if (blocking) return -1; - else - return wrote; + break; } - } - return (ssize_t)wrote; + return written; } -/* Received chunk. Makes sure that everything is received if blocking. Returns -1 if connection is lost, non-negative if success. +/* Received chunk. Makes sure that everything is received if blocking. + * Returns -1 if connection is lost, non-negative if success. * If blocking, and not enough data is received, it will return -1. */ -static ssize_t rsnd_recv_chunk(int socket, void *buf, size_t size, int blocking) +static ssize_t rsnd_recv_chunk(int socket, void *s, size_t len, int blocking) { - ssize_t rc = 0; - size_t has_read = 0; - ssize_t read_size = 0; struct pollfd fd; - pollfd_fd(fd) = socket; - fd.events = POLLIN; - int sleep_time = (blocking) ? 5000 : 0; + ssize_t has_read = 0; + int sleep_time = (blocking) ? 5000 : 0; - while ( has_read < size ) + pollfd_fd(fd) = socket; + fd.events = POLLIN; + + while (has_read < len) { - if ( rsnd_poll(&fd, 1, sleep_time) < 0 ) + if (rsnd_poll(&fd, 1, sleep_time) < 0) { RSD_ERR("[RSound] Poll failed.\n"); return -1; } - if ( fd.revents & POLLHUP ) + if (fd.revents & POLLHUP) { RSD_ERR("[RSound] Server hung up.\n"); return -1; } - if ( fd.revents & POLLIN ) + if (fd.revents & POLLIN) { - read_size = (size - has_read) > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : size - has_read; - rc = net_recv(socket, (char*)buf + has_read, read_size, 0); - if ( rc <= 0 ) + ssize_t read_size = (len - has_read) > MAX_PACKET_SIZE + ? MAX_PACKET_SIZE : len - has_read; + ssize_t rc = net_recv(socket, (char*)s + has_read, read_size, 0); + if (rc <= 0) { RSD_ERR("[RSound] Error receiving chunk, %s.\n", strerror(errno)); return rc; @@ -692,17 +704,16 @@ static ssize_t rsnd_recv_chunk(int socket, void *buf, size_t size, int blocking) } else { - if ( blocking ) + if (blocking) { RSD_ERR("[RSound] Block fail.\n"); return -1; } - else - return has_read; + break; } } - return (ssize_t)has_read; + return has_read; } static int rsnd_poll(struct pollfd *fd, int numfd, int timeout) @@ -717,18 +728,18 @@ static int rsnd_poll(struct pollfd *fd, int numfd, int timeout) perror("poll"); return -1; } - return 0; + break; } + return 0; } static int64_t rsnd_get_time_usec(void) { #if defined(_WIN32) static LARGE_INTEGER freq; + LARGE_INTEGER count; if (!freq.QuadPart && !QueryPerformanceFrequency(&freq)) /* Frequency is guaranteed to not change. */ return 0; - - LARGE_INTEGER count; if (!QueryPerformanceCounter(&count)) return 0; return count.QuadPart * 1000000 / freq.QuadPart; @@ -755,22 +766,27 @@ static int64_t rsnd_get_time_usec(void) #endif } -/* Calculates how many bytes there are in total in the virtual buffer. This is calculated client side. - It should be accurate enough unless we have big problems with buffer underruns. - This function is called by rsd_delay() to determine the latency. - This function might be changed in the future to correctly determine latency from server. */ +/* Calculates how many bytes there are in total in the virtual buffer. + * This is calculated client side. + * + * It should be accurate enough unless we have big problems with + * buffer underruns. + * This function is called by rsd_delay() to determine the latency. + * This function might be changed in the future to correctly determine + * latency from server. */ static void rsnd_drain(rsound_t *rd) { /* If the audio playback has started on the server we need to use timers. */ - if ( rd->has_written ) + if (rd->has_written) { /* Calculates the amount of bytes that the server has consumed. */ - int64_t time = rsnd_get_time_usec(); + int64_t time = rsnd_get_time_usec(); - int64_t delta = time - rd->start_time; - delta *= rd->rate * rd->channels * rd->samplesize; - delta /= 1000000; - /* Calculates the amount of data we have in our virtual buffer. Only used to calculate delay. */ + int64_t delta = time - rd->start_time; + delta *= rd->rate * rd->channels * rd->samplesize; + delta /= 1000000; + /* Calculates the amount of data we have in our virtual buffer. + * Only used to calculate delay. */ slock_lock(rd->thread.mutex); rd->bytes_in_buffer = (int)((int64_t)rd->total_written + (int64_t)FIFO_READ_AVAIL(rd->fifo_buffer) - delta); slock_unlock(rd->thread.mutex); @@ -783,20 +799,21 @@ static void rsnd_drain(rsound_t *rd) } } -/* Tries to fill the buffer. Uses signals to determine when the buffer is ready to be filled. Should the thread not be active - it will treat this as an error. Crude implementation of a blocking FIFO. */ -static size_t rsnd_fill_buffer(rsound_t *rd, const char *buf, size_t size) +/* Tries to fill the buffer. Uses signals to determine when the buffer is + * ready to be filled. Should the thread not be active it will treat this + * as an error. Crude implementation of a blocking FIFO. */ +static size_t rsnd_fill_buffer(rsound_t *rd, const char *s, size_t len) { - /* Wait until we have a ready buffer */ for (;;) { - /* Should the thread be shut down while we're running, return with error */ - if ( !rd->thread_active ) + /* Should the thread be shut down while we're running, + * return with error */ + if (!rd->thread_active) return 0; slock_lock(rd->thread.mutex); - if (FIFO_WRITE_AVAIL(rd->fifo_buffer) >= size) + if (FIFO_WRITE_AVAIL(rd->fifo_buffer) >= len) { slock_unlock(rd->thread.mutex); break; @@ -814,7 +831,7 @@ static size_t rsnd_fill_buffer(rsound_t *rd, const char *buf, size_t size) } slock_lock(rd->thread.mutex); - fifo_write(rd->fifo_buffer, buf, size); + fifo_write(rd->fifo_buffer, s, len); slock_unlock(rd->thread.mutex); #if 0 RSD_DEBUG("[RSound] fill_buffer: Wrote to buffer.\n"); @@ -825,34 +842,32 @@ static size_t rsnd_fill_buffer(rsound_t *rd, const char *buf, size_t size) RSD_DEBUG("[RSound] fill_buffer: Waking up thread.\n"); #endif scond_signal(rd->thread.cond); - - return size; + return len; } static int rsnd_start_thread(rsound_t *rd) { - if ( !rd->thread_active ) + if (!rd->thread_active) { rd->thread_active = 1; - rd->thread.thread = (sthread_t*)sthread_create(rd->audio_callback ? rsnd_cb_thread : rsnd_thread, rd); - if ( !rd->thread.thread ) + rd->thread.thread = (sthread_t*)sthread_create(rd->audio_callback + ? rsnd_cb_thread : rsnd_thread, rd); + + if (!rd->thread.thread) { rd->thread_active = 0; RSD_ERR("[RSound] Failed to create thread."); return -1; } - return 0; } - else - return 0; + return 0; } /* Makes sure that the playback thread has been correctly shut down */ static int rsnd_stop_thread(rsound_t *rd) { - if ( rd->thread_active ) + if (rd->thread_active) { - RSD_DEBUG("[RSound] Shutting down thread.\n"); slock_lock(rd->thread.cond_mutex); @@ -862,14 +877,12 @@ static int rsnd_stop_thread(rsound_t *rd) sthread_join(rd->thread.thread); RSD_DEBUG("[RSound] Thread joined successfully.\n"); - - return 0; } else { RSD_DEBUG("Thread is already shut down.\n"); - return 0; } + return 0; } /* Calculates audio delay in bytes */ @@ -878,18 +891,14 @@ static size_t rsnd_get_delay(rsound_t *rd) int ptr; rsnd_drain(rd); ptr = rd->bytes_in_buffer; - /* Adds the backend latency to the calculated latency. */ ptr += (int)rd->backend_info.latency; - slock_lock(rd->thread.mutex); ptr += rd->delay_offset; RSD_DEBUG("Offset: %d.\n", rd->delay_offset); slock_unlock(rd->thread.mutex); - - if ( ptr < 0 ) - ptr = 0; - + if (ptr < 0) + return (size_t)0; return (size_t)ptr; } @@ -903,11 +912,11 @@ static size_t rsnd_get_ptr(rsound_t *rd) return ptr; } -static int rsnd_send_identity_info(rsound_t *rd) -{ #define RSD_PROTO_MAXSIZE 256 #define RSD_PROTO_CHUNKSIZE 8 +static int rsnd_send_identity_info(rsound_t *rd) +{ char tmpbuf[RSD_PROTO_MAXSIZE]; char sendbuf[RSD_PROTO_MAXSIZE]; @@ -916,7 +925,8 @@ static int rsnd_send_identity_info(rsound_t *rd) snprintf(sendbuf, RSD_PROTO_MAXSIZE - 1, "RSD%5d%s", (int)strlen(tmpbuf), tmpbuf); sendbuf[RSD_PROTO_MAXSIZE - 1] = '\0'; - if ( rsnd_send_chunk(rd->conn.ctl_socket, sendbuf, strlen(sendbuf), 0) != (ssize_t)strlen(sendbuf) ) + if ( rsnd_send_chunk(rd->conn.ctl_socket, sendbuf, strlen(sendbuf), 0) + != (ssize_t)strlen(sendbuf)) return -1; return 0; @@ -924,30 +934,31 @@ static int rsnd_send_identity_info(rsound_t *rd) static int rsnd_close_ctl(rsound_t *rd) { - if ( !(rd->conn_type & RSD_CONN_PROTO) ) - return -1; - struct pollfd fd; - pollfd_fd(fd) = rd->conn.ctl_socket; - fd.events = POLLOUT; + int index = 0; + char buf[RSD_PROTO_MAXSIZE*2] = {0}; - if ( rsnd_poll(&fd, 1, 0) < 0 ) + if (!(rd->conn_type & RSD_CONN_PROTO)) return -1; - if ( fd.revents & POLLOUT ) + pollfd_fd(fd) = rd->conn.ctl_socket; + fd.events = POLLOUT; + + if (rsnd_poll(&fd, 1, 0) < 0) + return -1; + + if (fd.revents & POLLOUT) { const char *sendbuf = "RSD 9 CLOSECTL"; - if (net_send(rd->conn.ctl_socket, sendbuf, strlen(sendbuf), 0) < 0 ) + if (net_send(rd->conn.ctl_socket, sendbuf, strlen(sendbuf), 0) < 0) return -1; } - else if ( fd.revents & POLLHUP ) + else if (fd.revents & POLLHUP) return 0; /* Let's wait for reply (or POLLHUP) */ fd.events = POLLIN; - int index = 0; - char buf[RSD_PROTO_MAXSIZE*2] = {0}; for (;;) { @@ -964,24 +975,22 @@ static int rsnd_close_ctl(rsound_t *rd) * what we're looking for */ int rc = net_recv(rd->conn.ctl_socket, buf + index, RSD_PROTO_MAXSIZE*2 - 1 - index, 0); - if (rc <= 0 ) + if (rc <= 0) return -1; /* Can we find it directly? */ - if ( strstr(buf, "RSD 12 CLOSECTL OK") != NULL ) + if (strstr(buf, "RSD 12 CLOSECTL OK") != NULL) break; - else if ( strstr(buf, "RSD 15 CLOSECTL ERROR") != NULL ) + else if (strstr(buf, "RSD 15 CLOSECTL ERROR") != NULL) return -1; - subchar = strrchr(buf, 'R'); - if (!subchar) + if (!(subchar = strrchr(buf, 'R'))) index = 0; else { memmove(buf, subchar, strlen(subchar) + 1); index = strlen(buf); } - } else return -1; @@ -1004,7 +1013,7 @@ static int rsnd_send_info_query(rsound_t *rd) snprintf(sendbuf, RSD_PROTO_MAXSIZE - 1, "RSD%5d%s", (int)strlen(tmpbuf), tmpbuf); sendbuf[RSD_PROTO_MAXSIZE - 1] = '\0'; - if ( rsnd_send_chunk(rd->conn.ctl_socket, sendbuf, strlen(sendbuf), 0) != (ssize_t)strlen(sendbuf) ) + if (rsnd_send_chunk(rd->conn.ctl_socket, sendbuf, strlen(sendbuf), 0) != (ssize_t)strlen(sendbuf)) return -1; return 0; @@ -1014,23 +1023,23 @@ static int rsnd_send_info_query(rsound_t *rd) * In that case, we read the packet. */ static int rsnd_update_server_info(rsound_t *rd) { - long long int client_ptr = -1; - long long int serv_ptr = -1; + long long int client_ptr = -1; + long long int serv_ptr = -1; char temp[RSD_PROTO_MAXSIZE + 1] = {0}; /* We read until we have the last (most recent) data in the network buffer. */ for (;;) { ssize_t rc; - const char *substr; char *tmpstr; + const char *substr; memset(temp, 0, sizeof(temp)); /* We first receive the small header. We just use the larger buffer as it is disposable. */ rc = rsnd_recv_chunk(rd->conn.ctl_socket, temp, RSD_PROTO_CHUNKSIZE, 0); - if ( rc == 0 ) + if (rc == 0) break; - else if ( rc < RSD_PROTO_CHUNKSIZE ) + else if (rc < RSD_PROTO_CHUNKSIZE) return -1; temp[RSD_PROTO_CHUNKSIZE] = '\0'; @@ -1045,7 +1054,7 @@ static int rsnd_update_server_info(rsound_t *rd) long int len = strtol(substr, NULL, 0); /* Receive the rest of the data. */ - if ( rsnd_recv_chunk(rd->conn.ctl_socket, temp, len, 0) < len ) + if (rsnd_recv_chunk(rd->conn.ctl_socket, temp, len, 0) < len) return -1; /* We only bother if this is an INFO message. */ @@ -1057,34 +1066,34 @@ static int rsnd_update_server_info(rsound_t *rd) substr += 4; client_ptr = strtoull(substr, &tmpstr, 0); - if ( client_ptr == 0 || *tmpstr == '\0' ) + if (client_ptr == 0 || *tmpstr == '\0') return -1; - substr = tmpstr; + substr = tmpstr; serv_ptr = strtoull(substr, NULL, 0); - if ( serv_ptr <= 0 ) + if (serv_ptr <= 0) return -1; } - if ( client_ptr > 0 && serv_ptr > 0 ) + if (client_ptr > 0 && serv_ptr > 0) { - int delay = rsd_delay(rd); int delta = (int)(client_ptr - serv_ptr); slock_lock(rd->thread.mutex); - delta += FIFO_READ_AVAIL(rd->fifo_buffer); + delta += FIFO_READ_AVAIL(rd->fifo_buffer); slock_unlock(rd->thread.mutex); RSD_DEBUG("[RSound] Delay: %d, Delta: %d.\n", delay, delta); /* We only update the pointer if the data we got is quite recent. */ - if ( rd->total_written - client_ptr < 4 * rd->backend_info.chunk_size && rd->total_written > client_ptr ) + if ( rd->total_written - client_ptr < 4 * rd->backend_info.chunk_size + && rd->total_written > client_ptr) { int offset_delta = delta - delay; - int max_offset = rd->backend_info.chunk_size; - if ( offset_delta < -max_offset ) + int max_offset = rd->backend_info.chunk_size; + if (offset_delta < -max_offset) offset_delta = -max_offset; - else if ( offset_delta > max_offset ) + else if (offset_delta > max_offset) offset_delta = max_offset; slock_lock(rd->thread.mutex); @@ -1099,36 +1108,42 @@ static int rsnd_update_server_info(rsound_t *rd) /* Sort of simulates the behavior of pthread_cancel() */ #define _TEST_CANCEL() \ - if ( !rd->thread_active ) \ + if (!rd->thread_active) \ break /* The blocking thread */ -static void rsnd_thread ( void * thread_data ) +static void rsnd_thread(void * thread_data) { /* We share data between thread and callable functions */ - rsound_t *rd = thread_data; int rc; + rsound_t *rd = thread_data; char buffer[rd->backend_info.chunk_size]; - /* Plays back data as long as there is data in the buffer. Else, sleep until it can. */ - /* Two (;;) for loops! :3 Beware! */ + /* Plays back data as long as there is data in the buffer. + * Else, sleep until it can. + * Two (;;) for loops! :3 Beware! */ for (;;) { for (;;) { _TEST_CANCEL(); - /* We ask the server to send its latest backend data. Do not really care about errors atm. - * We only bother to check after 1 sec of audio has been played, as it might be quite inaccurate in the start of the stream. */ - if ( (rd->conn_type & RSD_CONN_PROTO) && (rd->total_written > rd->channels * rd->rate * rd->samplesize) ) + /* We ask the server to send its latest backend data. Do not really care + * about errors ATM. + * We only bother to check after 1 sec of audio has been played, as it + * might be quite inaccurate in the start of the stream. */ + if ( (rd->conn_type & RSD_CONN_PROTO) + && (rd->total_written > rd->channels * rd->rate * rd->samplesize)) { rsnd_send_info_query(rd); rsnd_update_server_info(rd); } - /* If the buffer is empty or we've stopped the stream, jump out of this for loop */ + /* If the buffer is empty or we've stopped the stream, + * jump out of this for loop */ slock_lock(rd->thread.mutex); - if (FIFO_READ_AVAIL(rd->fifo_buffer) < rd->backend_info.chunk_size || !rd->thread_active) + if ( FIFO_READ_AVAIL(rd->fifo_buffer) < rd->backend_info.chunk_size + || !rd->thread_active) { slock_unlock(rd->thread.mutex); break; @@ -1141,8 +1156,9 @@ static void rsnd_thread ( void * thread_data ) slock_unlock(rd->thread.mutex); rc = rsnd_send_chunk(rd->conn.socket, buffer, sizeof(buffer), 1); - /* If this happens, we should make sure that subsequent and current calls to rsd_write() will fail. */ - if ( rc != (int)rd->backend_info.chunk_size ) + /* If this happens, we should make sure that subsequent + * and current calls to rsd_write() will fail. */ + if (rc != (int)rd->backend_info.chunk_size) { _TEST_CANCEL(); rsnd_reset(rd); @@ -1156,7 +1172,7 @@ static void rsnd_thread ( void * thread_data ) } /* If this was the first write, set the start point for the timer. */ - if ( !rd->has_written ) + if (!rd->has_written) { slock_lock(rd->thread.mutex); rd->start_time = rsnd_get_time_usec(); @@ -1174,18 +1190,21 @@ static void rsnd_thread ( void * thread_data ) } - /* If we're still good to go, sleep. We are waiting for fill_buffer() to fill up some data. */ + /* If we're still good to go, sleep. We are waiting + * for fill_buffer() to fill up some data. */ - if ( rd->thread_active ) + if (rd->thread_active) { - /* There is a very slim change of getting a deadlock using the cond_wait scheme. - * This solution is rather dirty, but avoids complete deadlocks at the very least. - */ + /* There is a very slim change of getting a deadlock + * using the cond_wait scheme. + * This solution is rather dirty, but avoids complete + * deadlocks at the very least. + */ slock_lock(rd->thread.cond_mutex); scond_signal(rd->thread.cond); - if ( rd->thread_active ) + if (rd->thread_active) { RSD_DEBUG("[RSound] Thread going to sleep.\n"); scond_wait(rd->thread.cond, rd->thread.cond_mutex); @@ -1195,8 +1214,7 @@ static void rsnd_thread ( void * thread_data ) slock_unlock(rd->thread.cond_mutex); RSD_DEBUG("[RSound] Thread unlocked cond_mutex.\n"); } - /* Abort request, chap. */ - else + else /* Abort request, chap. */ { scond_signal(rd->thread.cond); return; @@ -1221,10 +1239,12 @@ static void rsnd_cb_thread(void *thread_data) while (has_read < rd->backend_info.chunk_size) { - size_t will_read = read_size < rd->backend_info.chunk_size - has_read ? read_size : rd->backend_info.chunk_size - has_read; + ssize_t ret; + size_t will_read = read_size < rd->backend_info.chunk_size - has_read + ? read_size : rd->backend_info.chunk_size - has_read; rsd_callback_lock(rd); - ssize_t ret = rd->audio_callback(buffer + has_read, will_read, rd->cb_data); + ret = rd->audio_callback(buffer + has_read, will_read, rd->cb_data); rsd_callback_unlock(rd); if (ret < 0) @@ -1241,16 +1261,19 @@ static void rsnd_cb_thread(void *thread_data) { if ((int)rsd_delay_ms(rd) < rd->max_latency / 2) { - RSD_DEBUG("[RSound] Callback thread: Requested %d bytes, got %d.\n", (int)will_read, (int)ret); + RSD_DEBUG("[RSound] Callback thread: Requested %d bytes, got %d.\n", + (int)will_read, (int)ret); memset(buffer + has_read, 0, will_read - ret); has_read += will_read - ret; } else { - /* The network might do things in large chunks, so it may request large amounts of data in short periods of time. - * This breaks when the caller cannot buffer up big buffers beforehand, so do short sleeps inbetween. + /* The network might do things in large chunks, so it may request + * large amounts of data in short periods of time. + * This breaks when the caller cannot buffer up big buffers beforehand, + * so do short sleeps inbetween. * This is somewhat dirty, but I cannot see a better solution - */ + */ retro_sleep(1); } } @@ -1268,13 +1291,14 @@ static void rsnd_cb_thread(void *thread_data) /* If this was the first write, set the start point for the timer. */ if (!rd->has_written) { - rd->start_time = rsnd_get_time_usec(); + rd->start_time = rsnd_get_time_usec(); rd->has_written = 1; } rd->total_written += rd->backend_info.chunk_size; - if ( (rd->conn_type & RSD_CONN_PROTO) && (rd->total_written > rd->channels * rd->rate * rd->samplesize) ) + if ( (rd->conn_type & RSD_CONN_PROTO) + && (rd->total_written > rd->channels * rd->rate * rd->samplesize)) { rsnd_send_info_query(rd); rsnd_update_server_info(rd); @@ -1287,22 +1311,22 @@ static void rsnd_cb_thread(void *thread_data) static int rsnd_reset(rsound_t *rd) { - if ( rd->conn.socket != -1 ) + if (rd->conn.socket != -1) net_socketclose(rd->conn.socket); - if ( rd->conn.socket != 1 ) + if (rd->conn.socket != 1) net_socketclose(rd->conn.ctl_socket); /* Pristine stuff, baby! */ slock_lock(rd->thread.mutex); - rd->conn.socket = -1; + rd->conn.socket = -1; rd->conn.ctl_socket = -1; - rd->total_written = 0; - rd->ready_for_data = 0; - rd->has_written = 0; + rd->total_written = 0; + rd->ready_for_data = 0; + rd->has_written = 0; rd->bytes_in_buffer = 0; - rd->thread_active = 0; - rd->delay_offset = 0; + rd->thread_active = 0; + rd->delay_offset = 0; slock_unlock(rd->thread.mutex); scond_signal(rd->thread.cond); @@ -1323,19 +1347,19 @@ int rsd_stop(rsound_t *rd) return 0; } -size_t rsd_write( rsound_t *rsound, const void* buf, size_t size) +size_t rsd_write(rsound_t *rsound, const void* buf, size_t len) { size_t max_write, written = 0; - if ( !rsound->ready_for_data ) + if (!rsound->ready_for_data) return 0; - max_write = (rsound->buffer_size - rsound->backend_info.chunk_size)/2; + max_write = (rsound->buffer_size - rsound->backend_info.chunk_size) / 2; /* Makes sure that we can handle arbitrary large write sizes */ - while ( written < size ) + while (written < len) { - size_t write_size = (size - written) > max_write ? max_write : (size - written); + size_t write_size = (len - written) > max_write ? max_write : (len - written); size_t result = rsnd_fill_buffer(rsound, (const char*)buf + written, write_size); if (result == 0) @@ -1350,20 +1374,23 @@ size_t rsd_write( rsound_t *rsound, const void* buf, size_t size) int rsd_start(rsound_t *rsound) { - if ( rsnd_create_connection(rsound) < 0 ) + if (rsnd_create_connection(rsound) < 0) return -1; return 0; } int rsd_exec(rsound_t *rsound) { + int fd; +#ifdef __PS3__ + int i = 0; +#endif RSD_DEBUG("[RSound] rsd_exec().\n"); - /* Makes sure we have a working connection */ - if ( rsound->conn.socket < 0 ) + if (rsound->conn.socket < 0) { RSD_DEBUG("[RSound] Calling rsd_start().\n"); - if ( rsd_start(rsound) < 0 ) + if (rsd_start(rsound) < 0) { RSD_ERR("[RSound] rsd_start() failed.\n"); return -1; @@ -1371,27 +1398,26 @@ int rsd_exec(rsound_t *rsound) } RSD_DEBUG("[RSound] Closing ctl.\n"); - if ( rsnd_close_ctl(rsound) < 0 ) + if (rsnd_close_ctl(rsound) < 0) return -1; - int fd = rsound->conn.socket; + fd = rsound->conn.socket; RSD_DEBUG("[RSound] Socket: %d.\n", fd); rsnd_stop_thread(rsound); #ifdef __PS3__ - int i = 0; setsockopt(rsound->conn.socket, SOL_SOCKET, SO_NBIO, &i, sizeof(int)); #else fcntl(rsound->conn.socket, F_SETFL, O_NONBLOCK); #endif /* Flush the buffer */ - if (FIFO_READ_AVAIL(rsound->fifo_buffer) > 0 ) + if (FIFO_READ_AVAIL(rsound->fifo_buffer) > 0) { char buffer[FIFO_READ_AVAIL(rsound->fifo_buffer)]; fifo_read(rsound->fifo_buffer, buffer, sizeof(buffer)); - if ( rsnd_send_chunk(fd, buffer, sizeof(buffer), 1) != (ssize_t)sizeof(buffer) ) + if (rsnd_send_chunk(fd, buffer, sizeof(buffer), 1) != (ssize_t)sizeof(buffer)) { RSD_DEBUG("[RSound] Failed flushing buffer.\n"); net_socketclose(fd); @@ -1412,7 +1438,7 @@ int rsd_set_param(rsound_t *rd, enum rsd_settings option, void* param) switch(option) { case RSD_SAMPLERATE: - if ( *(int*)param > 0 ) + if (*(int*)param > 0) { rd->rate = *((int*)param); break; @@ -1421,7 +1447,7 @@ int rsd_set_param(rsound_t *rd, enum rsd_settings option, void* param) retval = -1; break; case RSD_CHANNELS: - if ( *(int*)param > 0 ) + if (*(int*)param > 0) { rd->channels = *((int*)param); break; @@ -1430,17 +1456,17 @@ int rsd_set_param(rsound_t *rd, enum rsd_settings option, void* param) retval = -1; break; case RSD_HOST: - if ( rd->host != NULL ) + if (rd->host) free(rd->host); rd->host = strdup((char*)param); break; case RSD_PORT: - if ( rd->port != NULL ) + if (rd->port) free(rd->port); rd->port = strdup((char*)param); break; case RSD_BUFSIZE: - if ( *(int*)param > 0 ) + if (*(int*)param > 0) { rd->buffer_size = *((int*)param); break; @@ -1454,12 +1480,12 @@ int rsd_set_param(rsound_t *rd, enum rsd_settings option, void* param) /* Checks if format is valid. */ case RSD_FORMAT: - rd->format = (uint16_t)(*((int*)param)); - rd->samplesize = rsnd_format_to_samplesize(rd->format); + rd->format = (uint16_t)(*((int*)param)); + rd->samplesize = rsnd_format_to_samplesize(rd->format); - if ( rd->samplesize == -1 ) + if (rd->samplesize == -1) { - rd->format = RSD_S16_LE; + rd->format = RSD_S16_LE; rd->samplesize = rsnd_format_to_samplesize(RSD_S16_LE); *((int*)param) = (int)RSD_S16_LE; } @@ -1477,22 +1503,20 @@ int rsd_set_param(rsound_t *rd, enum rsd_settings option, void* param) return retval; } +/* When called, we make sure that the latency never goes over the time designated in RSD_LATENCY. + Useful for certain blocking I/O designs where the latency still needs to be quite low. + Without this, the latency of the stream will depend on how big the network buffers are. + (We simulate that we're a low latency sound card) */ void rsd_delay_wait(rsound_t *rd) { - - /* When called, we make sure that the latency never goes over the time designated in RSD_LATENCY. - Useful for certain blocking I/O designs where the latency still needs to be quite low. - Without this, the latency of the stream will depend on how big the network buffers are. - ( We simulate that we're a low latency sound card ) */ - /* Should we bother with checking latency at all? */ - if ( rd->max_latency > 0 ) + if (rd->max_latency > 0) { /* Latency of stream in ms */ int latency_ms = rsd_delay_ms(rd); /* Should we sleep for a while to keep the latency low? */ - if ( rd->max_latency < latency_ms ) + if (rd->max_latency < latency_ms) { int64_t sleep_ms = latency_ms - rd->max_latency; RSD_DEBUG("[RSound] Delay wait: %d ms.\n", (int)sleep_ms); @@ -1501,52 +1525,43 @@ void rsd_delay_wait(rsound_t *rd) } } -size_t rsd_pointer(rsound_t *rsound) -{ - return rsnd_get_ptr(rsound); -} - -size_t rsd_get_avail(rsound_t *rd) -{ - return rd->buffer_size - rsnd_get_ptr(rd); -} +size_t rsd_pointer(rsound_t *rsound) { return rsnd_get_ptr(rsound); } +size_t rsd_get_avail(rsound_t *rd) { return rd->buffer_size - rsnd_get_ptr(rd); } size_t rsd_delay(rsound_t *rd) { int ptr = rsnd_get_delay(rd); if (ptr < 0) - ptr = 0; - + return 0; return ptr; } size_t rsd_delay_ms(rsound_t* rd) { - return (rsd_delay(rd) * 1000) / ( rd->rate * rd->channels * rd->samplesize ); + return (rsd_delay(rd) * 1000) / (rd->rate * rd->channels * rd->samplesize); } int rsd_pause(rsound_t* rsound, int enable) { if (enable) return rsd_stop(rsound); - return rsd_start(rsound); } int rsd_init(rsound_t** rsound) { int format = RSD_S16_LE; - *rsound = calloc(1, sizeof(rsound_t)); + *rsound = (rsound_t*)calloc(1, sizeof(rsound_t)); if (*rsound == NULL) return -1; - (*rsound)->conn.socket = -1; - (*rsound)->conn.ctl_socket = -1; + (*rsound)->conn.socket = -1; + (*rsound)->conn.ctl_socket = -1; - (*rsound)->thread.mutex = slock_new(); + (*rsound)->thread.mutex = slock_new(); (*rsound)->thread.cond_mutex = slock_new(); - (*rsound)->cb_lock = slock_new(); - (*rsound)->thread.cond = scond_new(); + (*rsound)->cb_lock = slock_new(); + (*rsound)->thread.cond = scond_new(); /* Assumes default of S16_LE samples. */ rsd_set_param(*rsound, RSD_FORMAT, &format); @@ -1566,55 +1581,49 @@ int rsd_init(rsound_t** rsound) return 0; } -int rsd_simple_start(rsound_t** rsound, const char* host, const char* port, const char* ident, - int rate, int channels, enum rsd_format format) +int rsd_simple_start(rsound_t** rsound, const char* host, const char* port, + const char* ident, int rate, int channels, enum rsd_format format) { - if ( rsd_init(rsound) < 0 ) + int fmt; + if (rsd_init(rsound) < 0) return -1; - int fmt = format; + fmt = format; - if ( host != NULL ) + if (host) rsd_set_param(*rsound, RSD_HOST, (void*)host); - if ( port != NULL ) + if (port) rsd_set_param(*rsound, RSD_PORT, (void*)port); - if ( ident != NULL ) + if (ident) rsd_set_param(*rsound, RSD_IDENTITY, (void*)ident); - if ( rsd_set_param(*rsound, RSD_SAMPLERATE, &rate) < 0 || - rsd_set_param(*rsound, RSD_CHANNELS, &channels) < 0 || - rsd_set_param(*rsound, RSD_FORMAT, &fmt) < 0 ) - { - rsd_free(*rsound); - return -1; - } + if ( (rsd_set_param(*rsound, RSD_SAMPLERATE, &rate) < 0) + || (rsd_set_param(*rsound, RSD_CHANNELS, &channels) < 0) + || (rsd_set_param(*rsound, RSD_FORMAT, &fmt) < 0) + ) + goto error; - if ( rsd_start(*rsound) < 0 ) - { - rsd_free(*rsound); - return -1; - } + if (rsd_start(*rsound) < 0) + goto error; return 0; + +error: + rsd_free(*rsound); + return -1; } -void rsd_set_callback(rsound_t *rsound, rsd_audio_callback_t audio_cb, rsd_error_callback_t err_cb, size_t max_size, void *userdata) +void rsd_set_callback(rsound_t *rsound, rsd_audio_callback_t audio_cb, + rsd_error_callback_t err_cb, size_t len, void *userdata) { rsound->audio_callback = audio_cb; rsound->error_callback = err_cb; - rsound->cb_max_size = max_size; + rsound->cb_max_size = len; rsound->cb_data = userdata; } -void rsd_callback_lock(rsound_t *rsound) -{ - slock_lock(rsound->cb_lock); -} - -void rsd_callback_unlock(rsound_t *rsound) -{ - slock_unlock(rsound->cb_lock); -} +void rsd_callback_lock(rsound_t *rsound) { slock_lock(rsound->cb_lock); } +void rsd_callback_unlock(rsound_t *rsound) { slock_unlock(rsound->cb_lock); } int rsd_free(rsound_t *rsound) { diff --git a/audio/microphone_driver.c b/audio/microphone_driver.c index 874704a3e8..f3f7dc3d11 100644 --- a/audio/microphone_driver.c +++ b/audio/microphone_driver.c @@ -143,9 +143,7 @@ const char *config_get_microphone_driver_options(void) return char_list_new_special(STRING_LIST_MICROPHONE_DRIVERS, NULL); } -bool microphone_driver_find_driver( - void *settings_data, - const char *prefix, +bool microphone_driver_find_driver(void *settings_data, const char *prefix, bool verbosity_enabled) { settings_t *settings = (settings_t*)settings_data; @@ -184,21 +182,23 @@ bool microphone_driver_find_driver( return true; } -static void mic_driver_microphone_handle_init(retro_microphone_t *microphone, const retro_microphone_params_t *params) +static void mic_driver_microphone_handle_init(retro_microphone_t *microphone, + const retro_microphone_params_t *params) { if (microphone) { - const settings_t *settings = config_get_ptr(); - microphone->microphone_context = NULL; - microphone->flags = MICROPHONE_FLAG_ACTIVE; - microphone->sample_buffer = NULL; - microphone->sample_buffer_length = 0; + const settings_t *settings = config_get_ptr(); + unsigned microphone_sample_rate = settings->uints.microphone_sample_rate; + microphone->microphone_context = NULL; + microphone->flags = MICROPHONE_FLAG_ACTIVE; + microphone->sample_buffer = NULL; + microphone->sample_buffer_length = 0; - microphone->requested_params.rate = params ? params->rate : settings->uints.microphone_sample_rate; - microphone->actual_params.rate = 0; + microphone->requested_params.rate = params ? params->rate : microphone_sample_rate; + microphone->actual_params.rate = 0; /* We don't set the actual parameters until we actually open the mic. * (Remember, the core can request one before the driver is ready.) */ - microphone->effective_params.rate = params ? params->rate : settings->uints.microphone_sample_rate; + microphone->effective_params.rate = params ? params->rate : microphone_sample_rate; /* We set the effective parameters because * the frontend has to do what it can * to give the core what it asks for. */ @@ -253,14 +253,6 @@ static void mic_driver_microphone_handle_free(retro_microphone_t *microphone, bo /* Do NOT free the microphone handle itself! It's allocated statically! */ } -static enum resampler_quality microphone_driver_get_resampler_quality( - settings_t *settings) -{ - if (settings) - return (enum resampler_quality)settings->uints.microphone_resampler_quality; - return RESAMPLER_QUALITY_DONTCARE; -} - bool microphone_driver_init_internal(void *settings_data) { settings_t *settings = (settings_t*)settings_data; @@ -329,7 +321,7 @@ bool microphone_driver_init_internal(void *settings_data) else mic_st->resampler_ident[0] = '\0'; - mic_st->resampler_quality = microphone_driver_get_resampler_quality(settings); + mic_st->resampler_quality = (enum resampler_quality)settings->uints.microphone_resampler_quality; RARCH_LOG("[Microphone]: Initialized microphone driver.\n"); @@ -710,15 +702,13 @@ retro_microphone_t *microphone_driver_open_mic(const retro_microphone_params_t * void *driver_context = mic_st->driver_context; if (!settings) - { - RARCH_ERR("[Microphone]: Failed to open microphone due to uninitialized config.\n"); return NULL; - } + /* Not checking mic_st->flags because they might not be set yet; + * don't forget, the core can ask for a mic + * before the audio driver is ready to create one. */ if (!settings->bools.microphone_enable) - { /* Not checking mic_st->flags because they might not be set yet; - * don't forget, the core can ask for a mic - * before the audio driver is ready to create one. */ + { RARCH_DBG("[Microphone]: Refused to open microphone because it's disabled in the settings.\n"); return NULL; } @@ -729,8 +719,8 @@ retro_microphone_t *microphone_driver_open_mic(const retro_microphone_params_t * return NULL; } - if (!mic_driver && - (string_is_equal(settings->arrays.microphone_driver, "null") + if ( !mic_driver + && (string_is_equal(settings->arrays.microphone_driver, "null") || string_is_empty(settings->arrays.microphone_driver))) { /* If the mic driver hasn't been initialized, but it's not going to be... */ RARCH_ERR("[Microphone]: Cannot open microphone as the driver won't be initialized.\n"); @@ -756,8 +746,9 @@ retro_microphone_t *microphone_driver_open_mic(const retro_microphone_params_t * * But the user still wants a handle, so we'll give them one. */ mic_driver_microphone_handle_init(&mic_st->microphone, params); - /* If driver_context is NULL, the handle won't have a valid microphone context (but we'll create one later) */ + /* If driver_context is NULL, the handle won't have + * a valid microphone context (but we'll create one later) */ if (driver_context) { /* If the microphone driver is ready to open a microphone... */ diff --git a/autosave.h b/autosave.h index 1421d60436..12324b819f 100644 --- a/autosave.h +++ b/autosave.h @@ -37,7 +37,7 @@ void autosave_lock(void); **/ void autosave_unlock(void); -bool autosave_init(void); +bool autosave_init(bool compress_files, unsigned autosave_interval); void autosave_deinit(void); diff --git a/bluetooth/drivers/bluetoothctl.c b/bluetooth/drivers/bluetoothctl.c index 8913aaae45..16d04cc292 100644 --- a/bluetooth/drivers/bluetoothctl.c +++ b/bluetooth/drivers/bluetoothctl.c @@ -64,9 +64,9 @@ static void bluetoothctl_scan(void *data) while (fgets(line, 512, dev_file)) { - size_t len = strlen(line); - if (len > 0 && line[len-1] == '\n') - line[--len] = '\0'; + size_t _len = strlen(line); + if (_len > 0 && line[_len - 1] == '\n') + line[--_len] = '\0'; string_list_append(btctl->lines, line, attr); } @@ -225,8 +225,14 @@ static bool bluetoothctl_remove_device(void *data, unsigned idx) string_list_free(list); snprintf(btctl->command, sizeof(btctl->command), "\ - echo -e \"disconnect %s\\nremove %s\\n\" | bluetoothctl", - device, device); + bluetoothctl -- disconnect %s", + device); + + pclose(popen(btctl->command, "r")); + + snprintf(btctl->command, sizeof(btctl->command), "\ + bluetoothctl -- remove %s", + device); pclose(popen(btctl->command, "r")); diff --git a/camera/camera_driver.c b/camera/camera_driver.c index 01ed040d40..e09d011109 100644 --- a/camera/camera_driver.c +++ b/camera/camera_driver.c @@ -27,6 +27,12 @@ #include "camera_driver.h" +#if defined(HAVE_FFMPEG) && defined(HAVE_AVFORMAT) && defined(HAVE_AVCODEC) && \ + defined(HAVE_AVDEVICE) && defined(HAVE_AVUTIL) && defined(HAVE_SWSCALE) +/* FFMPEG consists of several libraries, and the camera driver needs most of them */ +#define HAVE_FFMPEG_CAMERA +#endif + static void *nullcamera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { return (void*)-1; } static void nullcamera_free(void *data) { } @@ -49,11 +55,20 @@ const camera_driver_t *camera_drivers[] = { #ifdef HAVE_V4L2 &camera_v4l2, #endif +#ifdef HAVE_PIPEWIRE_STABLE + &camera_pipewire, +#endif #ifdef EMSCRIPTEN &camera_rwebcam, #endif #ifdef ANDROID &camera_android, +#endif +#ifdef HAVE_AVF + &camera_avfoundation, +#endif +#ifdef HAVE_FFMPEG_CAMERA + &camera_ffmpeg, #endif &camera_null, NULL, diff --git a/camera/camera_driver.h b/camera/camera_driver.h index 51ecb35d8f..02be831359 100644 --- a/camera/camera_driver.h +++ b/camera/camera_driver.h @@ -28,6 +28,8 @@ RETRO_BEGIN_DECLS +struct string_list; + typedef struct camera_driver { /* FIXME: params for initialization - queries for resolution, @@ -62,9 +64,11 @@ extern const camera_driver_t *camera_drivers[]; extern camera_driver_t camera_v4l2; +extern camera_driver_t camera_pipewire; extern camera_driver_t camera_android; extern camera_driver_t camera_rwebcam; extern camera_driver_t camera_avfoundation; +extern camera_driver_t camera_ffmpeg; /** * config_get_camera_driver_options: diff --git a/camera/drivers/avfoundation.m b/camera/drivers/avfoundation.m new file mode 100644 index 0000000000..05f03043b5 --- /dev/null +++ b/camera/drivers/avfoundation.m @@ -0,0 +1,725 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2025 - Joseph Mattiello + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include +#include "../camera/camera_driver.h" +#include "../verbosity.h" +/// For image scaling and color space DSP +#import +#if TARGET_OS_IOS +/// For camera rotation detection +#import +#endif + +// TODO: Add an API to retroarch to allow selection of camera +#ifndef CAMERA_PREFER_FRONTFACING +#define CAMERA_PREFER_FRONTFACING 1 /// Default to front camera +#endif + +#ifndef CAMERA_MIRROR_FRONT_CAMERA +#define CAMERA_MIRROR_FRONT_CAMERA 1 +#endif + +@interface AVCameraManager : NSObject +@property (strong, nonatomic) AVCaptureSession *session; +@property (strong, nonatomic) AVCaptureDeviceInput *input; +@property (strong, nonatomic) AVCaptureVideoDataOutput *output; +@property (assign) uint32_t *frameBuffer; +@property (assign) size_t width; +@property (assign) size_t height; + +- (bool)setupCameraSession; +@end + +@implementation AVCameraManager + ++ (AVCameraManager *)sharedInstance { + static AVCameraManager *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[AVCameraManager alloc] init]; + }); + return instance; +} + +- (void)requestCameraAuthorizationWithCompletion:(void (^)(BOOL granted))completion { + RARCH_LOG("[Camera]: Checking camera authorization status\n"); + + AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + + switch (status) { + case AVAuthorizationStatusAuthorized: { + RARCH_LOG("[Camera]: Camera access already authorized\n"); + completion(YES); + break; + } + + case AVAuthorizationStatusNotDetermined: { + + RARCH_LOG("[Camera]: Requesting camera authorization...\n"); + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo + completionHandler:^(BOOL granted) { + RARCH_LOG("[Camera]: Authorization %s\n", granted ? "granted" : "denied"); + completion(granted); + }]; + break; + } + + case AVAuthorizationStatusDenied: { + RARCH_ERR("[Camera]: Camera access denied by user\n"); + completion(NO); + break; + } + + case AVAuthorizationStatusRestricted: { + RARCH_ERR("[Camera]: Camera access restricted (parental controls?)\n"); + completion(NO); + break; + } + + default: { + RARCH_ERR("[Camera]: Unknown authorization status\n"); + completion(NO); + break; + } + } +} + +- (void)captureOutput:(AVCaptureOutput *)output +didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer + fromConnection:(AVCaptureConnection *)connection { + @autoreleasepool { + if (!self.frameBuffer) + return; + + CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + if (!imageBuffer) { + RARCH_ERR("[Camera]: Failed to get image buffer\n"); + return; + } + + CVPixelBufferLockBaseAddress(imageBuffer, 0); + + size_t sourceWidth = CVPixelBufferGetWidth(imageBuffer); + size_t sourceHeight = CVPixelBufferGetHeight(imageBuffer); + OSType pixelFormat = CVPixelBufferGetPixelFormatType(imageBuffer); + +#ifdef DEBUG + RARCH_LOG("[Camera]: Processing frame %zux%zu format: %u\n", sourceWidth, sourceHeight, (unsigned int)pixelFormat); +#endif + // Create intermediate buffer for full-size converted image + uint32_t *intermediateBuffer = (uint32_t*)malloc(sourceWidth * sourceHeight * 4); + if (!intermediateBuffer) { + RARCH_ERR("[Camera]: Failed to allocate intermediate buffer\n"); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + return; + } + + vImage_Buffer srcBuffer = {}, intermediateVBuffer = {}, dstBuffer = {}; + vImage_Error err = kvImageNoError; + + // Setup intermediate buffer + intermediateVBuffer.data = intermediateBuffer; + intermediateVBuffer.width = sourceWidth; + intermediateVBuffer.height = sourceHeight; + intermediateVBuffer.rowBytes = sourceWidth * 4; + + // Setup destination buffer + dstBuffer.data = self.frameBuffer; + dstBuffer.width = self.width; + dstBuffer.height = self.height; + dstBuffer.rowBytes = self.width * 4; + + // Convert source format to RGBA + switch (pixelFormat) { + case kCVPixelFormatType_32BGRA: { + srcBuffer.data = CVPixelBufferGetBaseAddress(imageBuffer); + srcBuffer.width = sourceWidth; + srcBuffer.height = sourceHeight; + srcBuffer.rowBytes = CVPixelBufferGetBytesPerRow(imageBuffer); + + uint8_t permuteMap[4] = {2, 1, 0, 3}; // BGRA -> RGBA + err = vImagePermuteChannels_ARGB8888(&srcBuffer, &intermediateVBuffer, permuteMap, kvImageNoFlags); + break; + } + + case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: + case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: { + // YUV to RGB conversion + vImage_Buffer srcY = {}, srcCbCr = {}; + + srcY.data = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0); + srcY.width = sourceWidth; + srcY.height = sourceHeight; + srcY.rowBytes = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0); + + srcCbCr.data = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 1); + srcCbCr.width = sourceWidth / 2; + srcCbCr.height = sourceHeight / 2; + srcCbCr.rowBytes = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 1); + + vImage_YpCbCrToARGB info; + vImage_YpCbCrPixelRange pixelRange = + (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) ? + (vImage_YpCbCrPixelRange){16, 128, 235, 240} : // Video range + (vImage_YpCbCrPixelRange){0, 128, 255, 255}; // Full range + + err = vImageConvert_YpCbCrToARGB_GenerateConversion(kvImage_YpCbCrToARGBMatrix_ITU_R_601_4, + &pixelRange, + &info, + kvImage420Yp8_CbCr8, + kvImageARGB8888, + kvImageNoFlags); + + if (err == kvImageNoError) { + err = vImageConvert_420Yp8_CbCr8ToARGB8888(&srcY, + &srcCbCr, + &intermediateVBuffer, + &info, + NULL, + 255, + kvImageNoFlags); + } + break; + } + + default: + RARCH_ERR("[Camera]: Unsupported pixel format: %u\n", (unsigned int)pixelFormat); + free(intermediateBuffer); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + return; + } + + if (err != kvImageNoError) { + RARCH_ERR("[Camera]: Error converting color format: %ld\n", err); + free(intermediateBuffer); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + return; + } + + // Determine rotation based on platform and camera type +#if TARGET_OS_OSX + int rotationDegrees = 0; // Default 180-degree rotation for most cases + bool shouldMirror = true; +#else + int rotationDegrees = 180; // Default 180-degree rotation for most cases + bool shouldMirror = false; + + /// For camera rotation detection + UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; + if (orientation == UIDeviceOrientationPortrait || + orientation == UIDeviceOrientationPortraitUpsideDown) { + // In portrait mode, adjust rotation based on camera type + if (self.input.device.position == AVCaptureDevicePositionFront) { + rotationDegrees = 270; + #if CAMERA_MIRROR_FRONT_CAMERA + // TODO: Add an API to retroarch to allow for mirroring of front camera + shouldMirror = true; // Mirror front camera + #endif + RARCH_LOG("[Camera]: Using 270-degree rotation with mirroring for front camera in portrait mode\n"); + } + } +#endif + + // Rotate image + vImage_Buffer rotatedBuffer = {}; + rotatedBuffer.data = malloc(sourceWidth * sourceHeight * 4); + if (!rotatedBuffer.data) { + RARCH_ERR("[Camera]: Failed to allocate rotation buffer\n"); + free(intermediateBuffer); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + return; + } + + // Set dimensions based on rotation angle + if (rotationDegrees == 90 || rotationDegrees == 270) { + rotatedBuffer.width = sourceHeight; + rotatedBuffer.height = sourceWidth; + } else { + rotatedBuffer.width = sourceWidth; + rotatedBuffer.height = sourceHeight; + } + rotatedBuffer.rowBytes = rotatedBuffer.width * 4; + + const Pixel_8888 backgroundColor = {0, 0, 0, 255}; + + err = vImageRotate90_ARGB8888(&intermediateVBuffer, + &rotatedBuffer, + rotationDegrees / 90, + backgroundColor, + kvImageNoFlags); + + if (err != kvImageNoError) { + RARCH_ERR("[Camera]: Error rotating image: %ld\n", err); + free(rotatedBuffer.data); + free(intermediateBuffer); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + return; + } + + // Mirror the image if needed + if (shouldMirror) { + vImage_Buffer mirroredBuffer = {}; + mirroredBuffer.data = malloc(rotatedBuffer.height * rotatedBuffer.rowBytes); + if (!mirroredBuffer.data) { + RARCH_ERR("[Camera]: Failed to allocate mirror buffer\n"); + free(rotatedBuffer.data); + free(intermediateBuffer); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + return; + } + + mirroredBuffer.width = rotatedBuffer.width; + mirroredBuffer.height = rotatedBuffer.height; + mirroredBuffer.rowBytes = rotatedBuffer.rowBytes; + + err = vImageHorizontalReflect_ARGB8888(&rotatedBuffer, &mirroredBuffer, kvImageNoFlags); + + if (err == kvImageNoError) { + // Free rotated buffer and use mirrored buffer for scaling + free(rotatedBuffer.data); + rotatedBuffer = mirroredBuffer; + } else { + RARCH_ERR("[Camera]: Error mirroring image: %ld\n", err); + free(mirroredBuffer.data); + } + } + + // Calculate aspect fill scaling + float sourceAspect = (float)rotatedBuffer.width / rotatedBuffer.height; + float targetAspect = (float)self.width / self.height; + + vImage_Buffer scaledBuffer = {}; + size_t scaledWidth, scaledHeight; + + if (sourceAspect > targetAspect) { + // Source is wider - scale to match height + scaledHeight = self.height; + scaledWidth = (size_t)(self.height * sourceAspect); + } else { + // Source is taller - scale to match width + scaledWidth = self.width; + scaledHeight = (size_t)(self.width / sourceAspect); + } + + RARCH_LOG("[Camera]: Aspect fill scaling from %zux%zu to %zux%zu\n", + rotatedBuffer.width, rotatedBuffer.height, scaledWidth, scaledHeight); + + scaledBuffer.data = malloc(scaledWidth * scaledHeight * 4); + if (!scaledBuffer.data) { + RARCH_ERR("[Camera]: Failed to allocate scaled buffer\n"); + free(rotatedBuffer.data); + free(intermediateBuffer); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + return; + } + + scaledBuffer.width = scaledWidth; + scaledBuffer.height = scaledHeight; + scaledBuffer.rowBytes = scaledWidth * 4; + + // Scale maintaining aspect ratio + err = vImageScale_ARGB8888(&rotatedBuffer, &scaledBuffer, NULL, kvImageHighQualityResampling); + + if (err != kvImageNoError) { + RARCH_ERR("[Camera]: Error scaling image: %ld\n", err); + free(scaledBuffer.data); + free(rotatedBuffer.data); + free(intermediateBuffer); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + return; + } + + // Center crop the scaled image into the destination buffer + size_t xOffset = (scaledWidth > self.width) ? (scaledWidth - self.width) / 2 : 0; + size_t yOffset = (scaledHeight > self.height) ? (scaledHeight - self.height) / 2 : 0; + + // Copy the centered portion to the destination buffer + uint32_t *srcPtr = (uint32_t *)scaledBuffer.data; + uint32_t *dstPtr = (uint32_t *)self.frameBuffer; + + for (size_t y = 0; y < self.height; y++) { + memcpy(dstPtr + y * self.width, + srcPtr + (y + yOffset) * scaledWidth + xOffset, + self.width * 4); + } + + // Clean up + free(scaledBuffer.data); + free(rotatedBuffer.data); + free(intermediateBuffer); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + } // End of autorelease pool +} + +- (AVCaptureDevice *)selectCameraDevice { + RARCH_LOG("[Camera]: Selecting camera device\n"); + + NSArray *devices; + +#if TARGET_OS_OSX + // On macOS, use default discovery method + // Could probably due the same as iOS but need to test. + devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; +#else + // On iOS/tvOS use modern discovery session + NSArray *deviceTypes; + if (@available(iOS 17.0, *)) { + deviceTypes = @[ + AVCaptureDeviceTypeExternal, + AVCaptureDeviceTypeBuiltInWideAngleCamera, + AVCaptureDeviceTypeBuiltInTelephotoCamera, + AVCaptureDeviceTypeBuiltInUltraWideCamera, + // AVCaptureDeviceTypeBuiltInDualCamera, + // AVCaptureDeviceTypeBuiltInDualWideCamera, + // AVCaptureDeviceTypeBuiltInTripleCamera, + // AVCaptureDeviceTypeBuiltInTrueDepthCamera, + // AVCaptureDeviceTypeBuiltInLiDARDepthCamera, + // AVCaptureDeviceTypeContinuityCamera, + ]; + } else { + deviceTypes = @[ + AVCaptureDeviceTypeBuiltInWideAngleCamera, + AVCaptureDeviceTypeBuiltInTelephotoCamera, + AVCaptureDeviceTypeBuiltInUltraWideCamera, + // AVCaptureDeviceTypeBuiltInDualCamera, + // AVCaptureDeviceTypeBuiltInDualWideCamera, + // AVCaptureDeviceTypeBuiltInTripleCamera, + // AVCaptureDeviceTypeBuiltInTrueDepthCamera, + // AVCaptureDeviceTypeBuiltInLiDARDepthCamera, + // AVCaptureDeviceTypeContinuityCamera, + ]; + } + AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession + discoverySessionWithDeviceTypes:deviceTypes + mediaType:AVMediaTypeVideo + position:AVCaptureDevicePositionUnspecified]; + + devices = discoverySession.devices; +#endif + + if (devices.count == 0) { + RARCH_ERR("[Camera]: No camera devices found\n"); + return nil; + } + + // Log available devices + for (AVCaptureDevice *device in devices) { + RARCH_LOG("[Camera]: Found device: %s - Position: %d\n", + [device.localizedName UTF8String], + (int)device.position); + } + +#if TARGET_OS_OSX + // macOS: Just use the first available camera if only one exists + if (devices.count == 1) { + RARCH_LOG("[Camera]: Using only available camera: %s\n", + [devices.firstObject.localizedName UTF8String]); + return devices.firstObject; + } + + // Try to match by name for built-in cameras + for (AVCaptureDevice *device in devices) { + BOOL isFrontFacing = [device.localizedName containsString:@"FaceTime"] || + [device.localizedName containsString:@"Front"]; + if (CAMERA_PREFER_FRONTFACING == isFrontFacing) { + RARCH_LOG("[Camera]: Selected macOS camera: %s\n", + [device.localizedName UTF8String]); + return device; + } + } +#else + // iOS: Use position property + AVCaptureDevicePosition preferredPosition = CAMERA_PREFER_FRONTFACING ? + AVCaptureDevicePositionFront : AVCaptureDevicePositionBack; + + // Try to find preferred camera + for (AVCaptureDevice *device in devices) { + if (device.position == preferredPosition) { + RARCH_LOG("[Camera]: Selected iOS camera position: %d\n", + (int)preferredPosition); + return device; + } + } +#endif + + // Fallback to first available camera + RARCH_LOG("[Camera]: Using fallback camera: %s\n", + [devices.firstObject.localizedName UTF8String]); + return devices.firstObject; +} + +- (bool)setupCameraSession { + // Initialize capture session + self.session = [[AVCaptureSession alloc] init]; + + // Get camera device + AVCaptureDevice *device = [self selectCameraDevice]; + if (!device) { + RARCH_ERR("[Camera]: No camera device found\n"); + return false; + } + + // Create device input + NSError *error = nil; + self.input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; + if (error) { + RARCH_ERR("[Camera]: Failed to create device input: %s\n", + [error.localizedDescription UTF8String]); + return false; + } + + if ([self.session canAddInput:self.input]) { + [self.session addInput:self.input]; + RARCH_LOG("[Camera]: Added camera input to session\n"); + } + + // Create and configure video output + self.output = [[AVCaptureVideoDataOutput alloc] init]; + self.output.videoSettings = @{ + (NSString*)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA) + }; + [self.output setSampleBufferDelegate:self queue:dispatch_get_main_queue()]; + + if ([self.session canAddOutput:self.output]) { + [self.session addOutput:self.output]; + RARCH_LOG("[Camera]: Added video output to session\n"); + } + + return true; +} + +@end + +typedef struct +{ + AVCameraManager *manager; + unsigned width; + unsigned height; +} avfoundation_t; + +static void generateColorBars(uint32_t *buffer, size_t width, size_t height) { + const uint32_t colors[] = { + 0xFFFFFFFF, // White + 0xFFFFFF00, // Yellow + 0xFF00FFFF, // Cyan + 0xFF00FF00, // Green + 0xFFFF00FF, // Magenta + 0xFFFF0000, // Red + 0xFF0000FF, // Blue + 0xFF000000 // Black + }; + + size_t barWidth = width / 8; + for (size_t y = 0; y < height; y++) { + for (size_t x = 0; x < width; x++) { + size_t colorIndex = x / barWidth; + buffer[y * width + x] = colors[colorIndex]; + } + } +} + +static void *avfoundation_init(const char *device, uint64_t caps, + unsigned width, unsigned height) +{ + RARCH_LOG("[Camera]: Initializing AVFoundation camera %ux%u\n", width, height); + + avfoundation_t *avf = (avfoundation_t*)calloc(1, sizeof(avfoundation_t)); + if (!avf) { + RARCH_ERR("[Camera]: Failed to allocate avfoundation_t\n"); + return NULL; + } + + avf->manager = [AVCameraManager sharedInstance]; + avf->width = width; + avf->height = height; + avf->manager.width = width; + avf->manager.height = height; + + // Check if we're on the main thread + if ([NSThread isMainThread]) { + RARCH_LOG("[Camera]: Initializing on main thread\n"); + // Direct initialization on main thread + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { + AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + if (status != AVAuthorizationStatusAuthorized) { + RARCH_ERR("[Camera]: Camera access not authorized (status: %d)\n", (int)status); + free(avf); + return; + } + }]; + } else { + RARCH_LOG("[Camera]: Initializing on background thread\n"); + // Use dispatch_sync to run authorization check on main thread + __block AVAuthorizationStatus status; + dispatch_sync(dispatch_get_main_queue(), ^{ + status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + }); + + if (status != AVAuthorizationStatusAuthorized) { + RARCH_ERR("[Camera]: Camera access not authorized (status: %d)\n", (int)status); + free(avf); + return NULL; + } + } + + // Allocate frame buffer + avf->manager.frameBuffer = (uint32_t*)calloc(width * height, sizeof(uint32_t)); + if (!avf->manager.frameBuffer) { + RARCH_ERR("[Camera]: Failed to allocate frame buffer\n"); + free(avf); + return NULL; + } + + // Initialize capture session on main thread + __block bool setupSuccess = false; + + if ([NSThread isMainThread]) { + @autoreleasepool { + setupSuccess = [avf->manager setupCameraSession]; + if (setupSuccess) { + [avf->manager.session startRunning]; + RARCH_LOG("[Camera]: Started camera session\n"); + } + } + } else { + dispatch_sync(dispatch_get_main_queue(), ^{ + @autoreleasepool { + setupSuccess = [avf->manager setupCameraSession]; + if (setupSuccess) { + [avf->manager.session startRunning]; + RARCH_LOG("[Camera]: Started camera session\n"); + } + } + }); + } + + if (!setupSuccess) { + RARCH_ERR("[Camera]: Failed to setup camera\n"); + free(avf->manager.frameBuffer); + free(avf); + return NULL; + } + + // Add a check to verify the session is actually running + if (!avf->manager.session.isRunning) { + RARCH_ERR("[Camera]: Failed to start camera session\n"); + free(avf->manager.frameBuffer); + free(avf); + return NULL; + } + + RARCH_LOG("[Camera]: AVFoundation camera initialized and started successfully\n"); + return avf; +} + +static void avfoundation_free(void *data) +{ + avfoundation_t *avf = (avfoundation_t*)data; + if (!avf) + return; + + RARCH_LOG("[Camera]: Freeing AVFoundation camera\n"); + + if (avf->manager.session) { + [avf->manager.session stopRunning]; + } + + if (avf->manager.frameBuffer) { + free(avf->manager.frameBuffer); + avf->manager.frameBuffer = NULL; + } + + free(avf); + RARCH_LOG("[Camera]: AVFoundation camera freed\n"); +} + +static bool avfoundation_start(void *data) +{ + avfoundation_t *avf = (avfoundation_t*)data; + if (!avf || !avf->manager.session) { + RARCH_ERR("[Camera]: Cannot start - invalid data\n"); + return false; + } + + RARCH_LOG("[Camera]: Starting AVFoundation camera\n"); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [avf->manager.session startRunning]; + RARCH_LOG("[Camera]: Camera session started on background thread\n"); + }); + + // Give the session a moment to start + usleep(100000); // 100ms + + bool isRunning = avf->manager.session.isRunning; + RARCH_LOG("[Camera]: Camera session running: %s\n", isRunning ? "YES" : "NO"); + return isRunning; +} + +static void avfoundation_stop(void *data) +{ + avfoundation_t *avf = (avfoundation_t*)data; + if (!avf || !avf->manager.session) + return; + + RARCH_LOG("[Camera]: Stopping AVFoundation camera\n"); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [avf->manager.session stopRunning]; + RARCH_LOG("[Camera]: Camera session stopped on background thread\n"); + }); +} + +static bool avfoundation_poll(void *data, + retro_camera_frame_raw_framebuffer_t frame_raw_cb, + retro_camera_frame_opengl_texture_t frame_gl_cb) +{ + avfoundation_t *avf = (avfoundation_t*)data; + if (!avf || !frame_raw_cb) { + RARCH_ERR("[Camera]: Cannot poll - invalid data or callback\n"); + return false; + } + + if (!avf->manager.session.isRunning) { + RARCH_LOG("[Camera]: Camera not running, generating color bars\n"); + uint32_t *tempBuffer = (uint32_t*)calloc(avf->width * avf->height, sizeof(uint32_t)); + if (tempBuffer) { + generateColorBars(tempBuffer, avf->width, avf->height); + frame_raw_cb(tempBuffer, avf->width, avf->height, avf->width * 4); + free(tempBuffer); + return true; + } + return false; + } + +#ifdef DEBUG + RARCH_LOG("[Camera]: Delivering camera frame\n"); +#endif + frame_raw_cb(avf->manager.frameBuffer, avf->width, avf->height, avf->width * 4); + return true; +} + +camera_driver_t camera_avfoundation = { + avfoundation_init, + avfoundation_free, + avfoundation_start, + avfoundation_stop, + avfoundation_poll, + "avfoundation" +}; diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c new file mode 100644 index 0000000000..925c1247b0 --- /dev/null +++ b/camera/drivers/ffmpeg.c @@ -0,0 +1,625 @@ +/* RetroArch - A frontend for libretro. +* Copyright (C) 2010-2023 - Hans-Kristian Arntzen +* Copyright (C) 2023 - Jesse Talavera-Greenberg +* +* RetroArch is free software: you can redistribute it and/or modify it under the terms +* of the GNU General Public License as published by the Free Software Found- +* ation, either version 3 of the License, or (at your option) any later version. +* +* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with RetroArch. +* If not, see . +*/ + +#include +#include + +#include "../camera_driver.h" +#include "lists/string_list.h" +#include "verbosity.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ANDROID +#define FFMPEG_CAMERA_DEFAULT_BACKEND "android_camera" +#elif defined(__linux__) +#define FFMPEG_CAMERA_DEFAULT_BACKEND "v4l2" +#elif defined(__APPLE__) +#define FFMPEG_CAMERA_DEFAULT_BACKEND "avfoundation" +#elif defined(__WIN32__) +#define FFMPEG_CAMERA_DEFAULT_BACKEND "dshow" +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) +#define FFMPEG_CAMERA_DEFAULT_BACKEND "bktr" +#endif + +typedef struct ffmpeg_camera +{ + sthread_t *poll_thread; + AVFormatContext *format_context; + AVCodecContext *decoder_context; + const AVCodec *decoder; + const AVInputFormat *input_format; /* owned by ffmpeg, don't free it */ + AVDictionary *options; + AVPacket *packet; + AVFrame *camera_frame; + unsigned requested_width; + unsigned requested_height; + uint8_t *target_planes[4]; + int target_linesizes[4]; + unsigned target_width; + unsigned target_height; + struct SwsContext *scale_context; + + /* "name" for the camera device. + * Not just the reported name, there may be a bit of extra syntax. + * See https://ffmpeg.org/ffmpeg-devices.html#Input-Devices for details. */ + char url[512]; + + uint8_t *target_buffers[2]; + size_t target_buffer_length; + slock_t *target_buffer_lock; + volatile bool done; + uint8_t *active_buffer; +} ffmpeg_camera_t; + +static void ffmpeg_camera_free(void *data); + +static int ffmpeg_camera_get_initial_options( + const AVInputFormat *backend, + AVDictionary **options, + uint64_t caps, + unsigned width, + unsigned height +) +{ + int result = 0; + char dimensions[128]; + if (width != 0 && height != 0) + { /* If the core is letting the frontend pick the size... */ + snprintf(dimensions, sizeof(dimensions), "%ux%u", width, height); + + result = av_dict_set(options, "video_size", dimensions, 0); + + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to set option: %s\n", av_err2str(result)); + goto error; + } + } + /* I wanted to list supported formats and pick the most appropriate size + * if the requested size isn't available, + * but ffmpeg doesn't seem to offer a way to do that. + */ + + if (!options) + { + RARCH_DBG("[FFMPEG]: No options set, not allocating a dict (this isn't an error)"); + } + + return result; + +error: + av_dict_free(options); + return result; + +} + +/* Device URL syntax varies by backend. + * See https://ffmpeg.org/ffmpeg-devices.html for details. */ +static void ffmpeg_camera_get_source_url(ffmpeg_camera_t *ffmpeg, const AVDeviceInfo *device) +{ +#ifdef __WIN32__ + if (string_is_equal(ffmpeg->input_format->name, "dshow")) + { + snprintf(ffmpeg->url, sizeof(ffmpeg->url), "video=%s", device->device_description); + return; + } +#elif defined(__APPLE__) + if (string_is_equal(ffmpeg->input_format->name, "avfoundation")) + { + /* we only want video, not audio */ + snprintf(ffmpeg->url, sizeof(ffmpeg->url), "%s:none", device->device_description); + return; + } +#endif + + /* Other backends that support listing available sources use the name as-is; + * some advanced backends have extra syntax (e.g. gdigrab) + * but they don't support listing available sources, + * so players will have to enter them manually. + */ + strlcpy(ffmpeg->url, device->device_description, sizeof(ffmpeg->url)); +} + +static int ffmpeg_camera_open_device(ffmpeg_camera_t *ffmpeg) +{ + AVDictionaryEntry *e = NULL; + AVDictionary *options = NULL; + int result = ffmpeg->options ? av_dict_copy(&options, ffmpeg->options, 0) : 0; + /* copy the options dict so that other steps in start() can use it, + * as avformat_open_input clears it and adds unrecognized settings */ + + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy options: %s\n", av_err2str(result)); + goto done; + } + + result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, &options); + if (result < 0) + { + RARCH_WARN("[FFMPEG]: Failed to open video input device \"%s\": %s\n", ffmpeg->url, av_err2str(result)); + + if (ffmpeg->options) + { /* If we're not already requesting the default format... */ + + result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, NULL); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to open the same device in its default format: %s\n", av_err2str(result)); + goto done; + } + } + } + +done: + if (options) + { + const AVDictionaryEntry prev; + while ((e = av_dict_get(options, "", &prev, AV_DICT_IGNORE_SUFFIX))) { + /* av_dict_iterate isn't always available, so we use av_dict_get's legacy behavior instead */ + RARCH_WARN("[FFMPEG]: Unrecognized option on video input device: %s=%s\n", e->key, e->value); + } + } + + av_dict_free(&options); /* noop if NULL */ + if (result == 0) + { + RARCH_LOG("[FFMPEG]: Opened video input device \"%s\".\n", ffmpeg->url); + } + return result; +} + +static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) +{ + ffmpeg_camera_t *ffmpeg = NULL; + AVDeviceInfoList *device_list = NULL; + int result = 0; + int num_sources = 0; + + if ((caps & (UINT64_C(1) << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER)) == 0) + { /* If the core didn't ask for raw framebuffers... */ + RARCH_ERR("[FFMPEG]: Camera driver only supports raw framebuffer output.\n"); + return NULL; + } + + ffmpeg = (ffmpeg_camera_t*)calloc(1, sizeof(*ffmpeg)); + if (!ffmpeg) + { + RARCH_ERR("[FFMPEG]: Failed to allocate memory for camera driver.\n"); + return NULL; + } + + ffmpeg->requested_width = width; + ffmpeg->requested_height = height; + + avdevice_register_all(); + RARCH_LOG("[FFMPEG]: Initialized libavdevice.\n"); + + ffmpeg->input_format = av_find_input_format(FFMPEG_CAMERA_DEFAULT_BACKEND); + if (!ffmpeg->input_format) + { + RARCH_ERR("[FFMPEG]: No suitable video input backend found.\n"); + goto error; + } + + RARCH_LOG("[FFMPEG]: Using camera backend: %s (%s, flags=0x%x)\n", ffmpeg->input_format->name, ffmpeg->input_format->long_name, ffmpeg->input_format->flags); + + result = ffmpeg_camera_get_initial_options(ffmpeg->input_format, &ffmpeg->options, caps, width, height); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to get initial options: %s\n", av_err2str(result)); + goto error; + } + + num_sources = avdevice_list_input_sources(ffmpeg->input_format, NULL, ffmpeg->options, &device_list); + if (num_sources == 0) + { + RARCH_ERR("[FFMPEG]: No video input sources found.\n"); + goto error; + } + + if (num_sources < 0) + { + RARCH_ERR("[FFMPEG]: Failed to list video input sources: %s\n", av_err2str(num_sources)); + goto error; + } + + ffmpeg_camera_get_source_url(ffmpeg, device_list->devices[0]); + RARCH_LOG("[FFMPEG]: Using video input device: %s (%s, flags=0x%x)\n", ffmpeg->input_format->name, ffmpeg->input_format->long_name, ffmpeg->input_format->flags); + + avdevice_free_list_devices(&device_list); + return ffmpeg; +error: + avdevice_free_list_devices(&device_list); + ffmpeg_camera_free(ffmpeg); + return NULL; +} + +static void ffmpeg_camera_stop(void *data); +static void ffmpeg_camera_free(void *data) +{ + ffmpeg_camera_t *ffmpeg = data; + + if (!ffmpeg) + return; + + ffmpeg_camera_stop(ffmpeg); + + av_dict_free(&ffmpeg->options); + + free(ffmpeg); +} + +static void ffmpeg_camera_poll_thread(void *data); + +static bool ffmpeg_camera_start(void *data) +{ + ffmpeg_camera_t *ffmpeg = data; + int result = 0; + AVStream *stream = NULL; + AVDictionary *options = NULL; + const AVDictionaryEntry *e = NULL; + const AVDictionaryEntry prev; + int target_buffer_length = 0; + + if (ffmpeg->format_context) + { // TODO: Check the actual format context, not just the pointer + RARCH_LOG("[FFMPEG]: Camera %s is already started, no action needed.\n", ffmpeg->format_context->url); + return true; + } + + result = ffmpeg_camera_open_device(ffmpeg); + if (result < 0) + goto error; + + result = av_dict_copy(&options, ffmpeg->options, 0); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy options: %s\n", av_err2str(result)); + goto error; + } + + result = avformat_find_stream_info(ffmpeg->format_context, &options); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to find stream info: %s\n", av_err2str(result)); + goto error; + } + + while ((e = av_dict_get(options, "", &prev, AV_DICT_IGNORE_SUFFIX))) { + RARCH_WARN("[FFMPEG]: Unrecognized option on video input device: %s=%s\n", e->key, e->value); + } + + result = av_find_best_stream(ffmpeg->format_context, AVMEDIA_TYPE_VIDEO, -1, -1, &ffmpeg->decoder, 0); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to find video stream: %s\n", av_err2str(result)); + goto error; + } + stream = ffmpeg->format_context->streams[result]; + + RARCH_LOG("[FFMPEG]: Using video stream #%d with decoder \"%s\" (%s).\n", result, ffmpeg->decoder->name, ffmpeg->decoder->long_name); + + ffmpeg->decoder_context = avcodec_alloc_context3(ffmpeg->decoder); + if (!ffmpeg->decoder_context) + { + RARCH_ERR("[FFMPEG]: Failed to allocate decoder context.\n"); + goto error; + } + + result = avcodec_parameters_to_context(ffmpeg->decoder_context, stream->codecpar); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy codec parameters to decoder context: %s\n", av_err2str(result)); + goto error; + } + + if (!sws_isSupportedInput(ffmpeg->decoder_context->pix_fmt)) + { + RARCH_ERR("[FFMPEG]: Unsupported scaler input pixel format: %s\n", av_get_pix_fmt_name(ffmpeg->decoder_context->pix_fmt)); + goto error; + } + + result = av_dict_copy(&ffmpeg->options, options, 0); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy options: %s\n", av_err2str(result)); + goto error; + } + + result = avcodec_open2(ffmpeg->decoder_context, ffmpeg->decoder, &options); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to open decoder: %s\n", av_err2str(result)); + goto error; + } + + while ((e = av_dict_get(options, "", &prev, AV_DICT_IGNORE_SUFFIX))) { + RARCH_WARN("[FFMPEG]: Unrecognized option on video input device: %s=%s\n", e->key, e->value); + } + + av_dict_free(&options); + + ffmpeg->packet = av_packet_alloc(); + if (!ffmpeg->packet) + { + RARCH_ERR("[FFMPEG]: Failed to allocate packet.\n"); + goto error; + } + + ffmpeg->camera_frame = av_frame_alloc(); + if (!ffmpeg->camera_frame) + { + RARCH_ERR("[FFMPEG]: Failed to allocate camera frame.\n"); + goto error; + } + + ffmpeg->target_width = ffmpeg->requested_width ? ffmpeg->requested_width : (unsigned)ffmpeg->decoder_context->width; + ffmpeg->target_height = ffmpeg->requested_height ? ffmpeg->requested_height : (unsigned)ffmpeg->decoder_context->height; + + target_buffer_length = av_image_alloc( + ffmpeg->target_planes, + ffmpeg->target_linesizes, + ffmpeg->target_width, + ffmpeg->target_height, + AV_PIX_FMT_BGRA, + 1 + ); + if (target_buffer_length < 0) + { + RARCH_ERR("[FFMPEG]: Failed to allocate target plane: %s\n", av_err2str(target_buffer_length)); + goto error; + } + + /* target buffer aligned to 4 bytes because it's exposed to the core as a uint32_t[] */ + ffmpeg->target_buffer_length = target_buffer_length; + ffmpeg->target_buffers[0] = memalign_alloc(4, target_buffer_length); + ffmpeg->target_buffers[1] = memalign_alloc(4, target_buffer_length); + ffmpeg->active_buffer = ffmpeg->target_buffers[0]; + if (!ffmpeg->target_buffers[0] || !ffmpeg->target_buffers[1]) + { + RARCH_ERR("[FFMPEG]: Failed to allocate target %d-byte buffer for %dx%d %s-formatted video data.\n", + target_buffer_length, + ffmpeg->decoder_context->width, + ffmpeg->decoder_context->height, + av_get_pix_fmt_name(AV_PIX_FMT_BGRA) + ); + goto error; + } + + RARCH_LOG("[FFMPEG]: Allocated %d bytes for %dx%d %s-formatted video data.\n", + target_buffer_length, + ffmpeg->decoder_context->width, + ffmpeg->decoder_context->height, + av_get_pix_fmt_name(ffmpeg->decoder_context->pix_fmt) + ); + + ffmpeg->scale_context = sws_getContext( + ffmpeg->decoder_context->width, + ffmpeg->decoder_context->height, + ffmpeg->decoder_context->pix_fmt, + ffmpeg->target_width, + ffmpeg->target_height, + AV_PIX_FMT_BGRA, + SWS_BILINEAR, + NULL, NULL, NULL + ); + if (!ffmpeg->scale_context) + { + RARCH_ERR("[FFMPEG]: Failed to create scale context.\n"); + goto error; + } + + ffmpeg->target_buffer_lock = slock_new(); + if (!ffmpeg->target_buffer_lock) + { + RARCH_ERR("[FFMPEG]: Failed to create target buffer lock.\n"); + goto error; + } + + ffmpeg->poll_thread = sthread_create(ffmpeg_camera_poll_thread, ffmpeg); + if (!ffmpeg->poll_thread) + { + RARCH_ERR("[FFMPEG]: Failed to create poll thread.\n"); + goto error; + } + + return true; +error: + ffmpeg_camera_stop(ffmpeg); + + return false; +} + +static void ffmpeg_camera_stop(void *data) +{ + ffmpeg_camera_t *ffmpeg = data; + + if (!ffmpeg->format_context) + { + RARCH_LOG("[FFMPEG]: Camera %s is already stopped, no flush needed.\n", ffmpeg->url); + } + else + { + int result = avcodec_send_packet(ffmpeg->decoder_context, NULL); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to flush decoder: %s\n", av_err2str(result)); + } + } + + /* these functions are noops for NULL pointers */ + ffmpeg->done = true; + sthread_join(ffmpeg->poll_thread); /* wait for the thread to finish, then free it */ + ffmpeg->poll_thread = NULL; + + slock_free(ffmpeg->target_buffer_lock); + ffmpeg->target_buffer_lock = NULL; + + sws_freeContext(ffmpeg->scale_context); + ffmpeg->scale_context = NULL; + + memalign_free(ffmpeg->target_buffers[0]); + memalign_free(ffmpeg->target_buffers[1]); + ffmpeg->active_buffer = NULL; + ffmpeg->target_buffers[0] = NULL; + ffmpeg->target_buffers[1] = NULL; + ffmpeg->target_buffer_length = 0; + ffmpeg->target_width = 0; + ffmpeg->target_height = 0; + + av_frame_free(&ffmpeg->camera_frame); + av_freep(&ffmpeg->target_buffers[0]); + memset(ffmpeg->target_linesizes, 0, sizeof(ffmpeg->target_linesizes)); + + av_packet_free(&ffmpeg->packet); + avcodec_free_context(&ffmpeg->decoder_context); + avformat_close_input(&ffmpeg->format_context); + RARCH_LOG("[FFMPEG]: Closed video input device %s.\n", ffmpeg->url); +} + +static void ffmpeg_camera_poll_thread(void *data) +{ + ffmpeg_camera_t *ffmpeg = data; + + if (!ffmpeg) + return; + + while (!ffmpeg->done) + { + int result = av_read_frame(ffmpeg->format_context, ffmpeg->packet); + if (result < 0) + { /* Read the raw data from the camera. If that fails... */ + RARCH_ERR("[FFMPEG]: Failed to read frame: %s\n", av_err2str(result)); + continue; + } + + result = avcodec_send_packet(ffmpeg->decoder_context, ffmpeg->packet); + if (result < 0) + { /* Send the raw data to the decoder. If that fails... */ + if (result == AVERROR_EOF) + { + RARCH_DBG("[FFMPEG]: Video capture device closed\n"); + } + else + { + RARCH_ERR("[FFMPEG]: Failed to send packet to decoder: %s\n", av_err2str(result)); + } + + goto done_loop; + } + + /* video streams consist of exactly one frame per packet */ + result = avcodec_receive_frame(ffmpeg->decoder_context, ffmpeg->camera_frame); + if (result < 0) + { /* Send the decoded data to the camera frame. If that fails... */ + if (!(result == AVERROR_EOF || result == AVERROR(EAGAIN))) + { /* these error codes mean no new frame, but not necessarily a problem */ + RARCH_ERR("[FFMPEG]: Failed to receive camera frame from decoder: %s\n", av_err2str(result)); + } + + goto done_loop; + } + + retro_assert(ffmpeg->decoder->type == AVMEDIA_TYPE_VIDEO); + + /* sws_scale_frame is tidier but isn't as widely available */ + result = sws_scale( + ffmpeg->scale_context, + (const uint8_t *const *)ffmpeg->camera_frame->data, + ffmpeg->camera_frame->linesize, + 0, + ffmpeg->camera_frame->height, + ffmpeg->target_planes, + ffmpeg->target_linesizes + ); + if (result < 0) + { /* Scale and convert the frame to the target format. If that fails... */ + RARCH_ERR("[FFMPEG]: Failed to scale frame: %s\n", av_err2str(result)); + goto done_loop; + } + + slock_lock(ffmpeg->target_buffer_lock); + result = av_image_copy_to_buffer( + ffmpeg->active_buffer, + ffmpeg->target_buffer_length, + (const uint8_t *const *)ffmpeg->target_planes, + ffmpeg->target_linesizes, + AV_PIX_FMT_BGRA, + ffmpeg->target_width, + ffmpeg->target_height, + 1 + ); + if (result >= 0) { + ffmpeg->active_buffer = ffmpeg->active_buffer == ffmpeg->target_buffers[0] ? ffmpeg->target_buffers[1] : ffmpeg->target_buffers[0]; + } + slock_unlock(ffmpeg->target_buffer_lock); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy frame to buffer: %s\n", av_err2str(result)); + goto done_loop; + } + done_loop: + /* must be called when we're done with it */ + av_frame_unref(ffmpeg->camera_frame); + } + + /* every operation in this function needs this packet */ + av_packet_unref(ffmpeg->packet); +} + +static bool ffmpeg_camera_poll( + void *data, + retro_camera_frame_raw_framebuffer_t frame_raw_cb, + retro_camera_frame_opengl_texture_t frame_gl_cb) +{ + ffmpeg_camera_t *ffmpeg = data; + + if (!ffmpeg->format_context) + { + RARCH_ERR("[FFMPEG]: Camera is not started, cannot poll.\n"); + return false; + } + + if (!frame_raw_cb) + { + RARCH_ERR("[FFMPEG]: No callback provided, cannot poll.\n"); + return false; + } + + slock_lock(ffmpeg->target_buffer_lock); + frame_raw_cb((uint32_t*)ffmpeg->active_buffer, ffmpeg->target_width, ffmpeg->target_height, ffmpeg->target_linesizes[0]); + slock_unlock(ffmpeg->target_buffer_lock); + + return true; +} + +camera_driver_t camera_ffmpeg = { + ffmpeg_camera_init, + ffmpeg_camera_free, + ffmpeg_camera_start, + ffmpeg_camera_stop, + ffmpeg_camera_poll, + "ffmpeg", +}; diff --git a/camera/drivers/pipewire.c b/camera/drivers/pipewire.c new file mode 100644 index 0000000000..32b348a88b --- /dev/null +++ b/camera/drivers/pipewire.c @@ -0,0 +1,466 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2025 - Viachaslau Khalikin + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../camera_driver.h" +#include "../../audio/common/pipewire.h" +#include "../../verbosity.h" + + +/* TODO/FIXME: detect size */ +#define WIDTH 640 +#define HEIGHT 480 + +#define MAX_BUFFERS 64 + +typedef struct pipewire_camera +{ + pipewire_core_t *pw; + + struct pw_stream *stream; + struct spa_hook stream_listener; + + struct scaler_ctx scaler; + uint32_t *buffer_output; + + struct spa_io_position *position; + struct spa_video_info format; + struct spa_rectangle size; +} pipewire_camera_t; + +static struct +{ + uint32_t format; + uint32_t id; +} scaler_video_formats[] = { + { SCALER_FMT_ARGB8888, SPA_VIDEO_FORMAT_ARGB }, + { SCALER_FMT_ABGR8888, SPA_VIDEO_FORMAT_ABGR }, + { SCALER_FMT_0RGB1555, SPA_VIDEO_FORMAT_UNKNOWN }, + { SCALER_FMT_RGB565, SPA_VIDEO_FORMAT_UNKNOWN }, + { SCALER_FMT_BGR24, SPA_VIDEO_FORMAT_BGR }, + { SCALER_FMT_YUYV, SPA_VIDEO_FORMAT_YUY2 }, + { SCALER_FMT_RGBA4444, SPA_VIDEO_FORMAT_UNKNOWN }, +}; + +#if 0 +{ + SPA_FOR_EACH_ELEMENT_VAR(scaler_video_formats, f) + { + if (f->format == format) + return f->id; + } + return SPA_VIDEO_FORMAT_UNKNOWN; +} +#endif + +static uint32_t id_to_scaler_format(uint32_t id) +{ + SPA_FOR_EACH_ELEMENT_VAR(scaler_video_formats, f) + { + if (f->id == id) + return f->format; + } + return SCALER_FMT_ARGB8888; +} + +static int build_format(struct spa_pod_builder *b, const struct spa_pod **params, + uint32_t width, uint32_t height) +{ + struct spa_pod_frame frame[2]; + + /* make an object of type SPA_TYPE_OBJECT_Format and id SPA_PARAM_EnumFormat. + * The object type is important because it defines the properties that are + * acceptable. The id gives more context about what the object is meant to + * contain. In this case we enumerate supported formats. */ + spa_pod_builder_push_object(b, &frame[0], SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); + /* add media type and media subtype properties */ + spa_pod_builder_prop(b, SPA_FORMAT_mediaType, 0); + spa_pod_builder_id(b, SPA_MEDIA_TYPE_video); + spa_pod_builder_prop(b, SPA_FORMAT_mediaSubtype, 0); + spa_pod_builder_id(b, SPA_MEDIA_SUBTYPE_raw); + + /* build an enumeration of formats */ + spa_pod_builder_prop(b, SPA_FORMAT_VIDEO_format, 0); + spa_pod_builder_push_choice(b, &frame[1], SPA_CHOICE_Enum, 0); + spa_pod_builder_id(b, SPA_VIDEO_FORMAT_YUY2); /* default */ + SPA_FOR_EACH_ELEMENT_VAR(scaler_video_formats, f) + { + uint32_t id = f->id; + if (id != SPA_VIDEO_FORMAT_UNKNOWN) + spa_pod_builder_id(b, id); /* alternative */ + } + + spa_pod_builder_pop(b, &frame[1]); + + /* add size and framerate ranges */ + spa_pod_builder_add(b, + SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle( + &SPA_RECTANGLE(MAX(width, 1), MAX(height, 1)), + &SPA_RECTANGLE(1, 1), + &SPA_RECTANGLE(MAX(width, WIDTH), MAX(height, HEIGHT))), + SPA_FORMAT_VIDEO_framerate, SPA_POD_CHOICE_RANGE_Fraction( + &SPA_FRACTION(25, 1), + &SPA_FRACTION(0, 1), + &SPA_FRACTION(30, 1)), + 0); + + params[0] = spa_pod_builder_pop(b, &frame[0]); + + RARCH_LOG("[Camera] [PipeWire]: Supported raw formats:\n"); + spa_debug_format(2, NULL, params[0]); + + return 1; +} + +static bool preprocess_image(pipewire_camera_t *camera) +{ + struct spa_buffer *buf; + struct spa_meta_header *h; + struct pw_buffer *b = NULL; + struct scaler_ctx *ctx = NULL; + + for (;;) + { + if ((b = pw_stream_dequeue_buffer(camera->stream))) + break; + } + if (b == NULL) + { + RARCH_DBG("[Camera] [PipeWire]: Out of buffers\n"); + return false; + } + + buf = b->buffer; + + if ((h = spa_buffer_find_meta_data(buf, SPA_META_Header, sizeof(*h)))) + { + if (h->flags & SPA_META_HEADER_FLAG_CORRUPTED) { + RARCH_LOG("[Camera] [PipeWire] Dropping corruped frame.\n"); + pw_stream_queue_buffer(camera->stream, b); + return false; + } + uint64_t now = pw_stream_get_nsec(camera->stream); + RARCH_DBG("[Camera] [PipeWire]: now:%"PRIu64" pts:%"PRIu64" diff:%"PRIi64"\n", + now, h->pts, now - h->pts); + } + + if (buf->datas[0].data == NULL) + return false; + + ctx = &camera->scaler; + scaler_ctx_scale_direct(ctx, camera->buffer_output, (const uint8_t*)buf->datas[0].data); + + pw_stream_queue_buffer(camera->stream, b); + return true; +} + +static void stream_state_changed_cb(void *data, enum pw_stream_state old, + enum pw_stream_state state, const char *error) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + + RARCH_DBG("[Camera] [PipeWire]: Stream state changed %s -> %s\n", + pw_stream_state_as_string(old), + pw_stream_state_as_string(state)); + + pw_thread_loop_signal(camera->pw->thread_loop, false); +} + +static void stream_io_changed_cb(void *data, uint32_t id, void *area, uint32_t size) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + + switch (id) + { + case SPA_IO_Position: + camera->position = area; + break; + } +} + +static void stream_param_changed_cb(void *data, uint32_t id, const struct spa_pod *param) +{ + uint8_t params_buffer[1024]; + const struct spa_pod *params[5]; + pipewire_camera_t *camera = (pipewire_camera_t*)data; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); + + if (param && id == SPA_PARAM_Tag) + { + spa_debug_pod(0, NULL, param); + return; + } + if (param && id == SPA_PARAM_Latency) + { + struct spa_latency_info info; + if (spa_latency_parse(param, &info) >= 0) + RARCH_DBG("[Camera] [PipeWire]: Got latency: %"PRIu64"\n", (info.min_ns + info.max_ns) / 2); + return; + } + /* NULL means to clear the format */ + if (param == NULL || id != SPA_PARAM_Format) + return; + + RARCH_DBG("[Camera] [PipeWire]: Got format:\n"); + spa_debug_format(2, NULL, param); + + if (spa_format_parse(param, &camera->format.media_type, &camera->format.media_subtype) < 0) + { + RARCH_DBG("[Camera] [PipeWire]: Failed to parse video format.\n"); + return; + } + + if (camera->format.media_type != SPA_MEDIA_TYPE_video) + return; + + switch (camera->format.media_subtype) + { + case SPA_MEDIA_SUBTYPE_raw: + spa_format_video_raw_parse(param, &camera->format.info.raw); + camera->scaler.in_fmt = id_to_scaler_format(camera->format.info.raw.format); + camera->size = SPA_RECTANGLE(camera->format.info.raw.size.width, camera->format.info.raw.size.height); + RARCH_DBG("[Camera] [PipeWire]: Configured capture format = %d\n", camera->format.info.raw.format); + break; + default: + RARCH_WARN("[Camera] [PipeWire]: Unsupported video format: %d\n", camera->format.media_subtype); + return; + } + + if (!camera->size.width || !camera->size.height) + { + pw_stream_set_error(camera->stream, -EINVAL, "invalid size"); + return; + } + + struct spa_pod_frame frame; + spa_pod_builder_push_object(&b, &frame, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers); + spa_pod_builder_add(&b, + SPA_PARAM_BUFFERS_stride, SPA_POD_Int(camera->size.width * 2), + 0); + + spa_pod_builder_add(&b, + SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(8, 1, MAX_BUFFERS), + SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1 << SPA_DATA_MemPtr), + 0); + + params[0] = spa_pod_builder_pop(&b, &frame); + + params[1] = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, + SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header), + SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header))); +#if 0 + params[2] = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, + SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform), + SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_videotransform))); +#endif + + camera->buffer_output = (uint32_t *) + malloc(camera->size.width * camera->size.height * sizeof(uint32_t)); + if (!camera->buffer_output) + { + RARCH_ERR("[Camera] [PipeWire]: Failed to allocate output buffer.\n"); + return; + } + + camera->scaler.in_width = camera->scaler.out_width = camera->size.width; + camera->scaler.in_height = camera->scaler.out_height = camera->size.height; + camera->scaler.out_fmt = SCALER_FMT_ARGB8888; + camera->scaler.in_stride = camera->size.width * 2; + camera->scaler.out_stride = camera->size.width * 4; + if (!scaler_ctx_gen_filter(&camera->scaler)) + { + RARCH_ERR("[Camera] [PipeWire]: Failed to create scaler.\n"); + return; + } + + pw_stream_update_params(camera->stream, params, 2); +} + +static const struct pw_stream_events stream_events = { + PW_VERSION_STREAM_EVENTS, + .state_changed = stream_state_changed_cb, + .io_changed = stream_io_changed_cb, + .param_changed = stream_param_changed_cb, + .process = NULL, +}; + +static void pipewire_stop(void *data) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + const char *error = NULL; + + retro_assert(camera); + retro_assert(camera->stream); + retro_assert(camera->pw); + + if (pw_stream_get_state(camera->stream, &error) == PW_STREAM_STATE_PAUSED) + pipewire_stream_set_active(camera->pw->thread_loop, camera->stream, false); +} + +static bool pipewire_start(void *data) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + const char *error = NULL; + + retro_assert(camera); + retro_assert(camera->stream); + retro_assert(camera->pw); + + if (pw_stream_get_state(camera->stream, &error) == PW_STREAM_STATE_STREAMING) + return true; + + return pipewire_stream_set_active(camera->pw->thread_loop, camera->stream, true); +} + +static void pipewire_free(void *data) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + + if (!camera) + return; + + if (camera->stream) + { + pw_thread_loop_lock(camera->pw->thread_loop); + pw_stream_destroy(camera->stream); + camera->stream = NULL; + pw_thread_loop_unlock(camera->pw->thread_loop); + } + + pipewire_core_deinit(camera->pw); + + if (camera->buffer_output) + free(camera->buffer_output); + + scaler_ctx_gen_reset(&camera->scaler); + free(camera); +} + +static void *pipewire_init(const char *device, uint64_t caps, + unsigned width, unsigned height) +{ + int res, n_params; + const struct spa_pod *params[3]; + struct pw_properties *props; + uint8_t buffer[1024]; + pipewire_camera_t *camera = (pipewire_camera_t*)calloc(1, sizeof(*camera)); + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + + if (!camera) + goto error; + + if (!pipewire_core_init(&camera->pw, "camera_driver", NULL)) + goto error; + + pipewire_core_wait_resync(camera->pw); + + props = pw_properties_new(PW_KEY_MEDIA_TYPE, PW_RARCH_MEDIA_TYPE_VIDEO, + PW_KEY_MEDIA_CATEGORY, PW_RARCH_MEDIA_CATEGORY_RECORD, + PW_KEY_MEDIA_ROLE, PW_RARCH_MEDIA_ROLE, + NULL); + if (!props) + goto error; + + if (device) + pw_properties_set(props, PW_KEY_TARGET_OBJECT, device); + + camera->stream = pw_stream_new(camera->pw->core, PW_RARCH_APPNAME, props); + + pw_stream_add_listener(camera->stream, &camera->stream_listener, &stream_events, camera); + + /* build the extra parameters to connect with. To connect, we can provide + * a list of supported formats. We use a builder that writes the param + * object to the stack. */ + n_params = build_format(&b, params, width, height); + { + struct spa_pod_frame f; + struct spa_dict_item items[1]; + /* send a tag, input tags travel upstream */ + spa_tag_build_start(&b, &f, SPA_PARAM_Tag, SPA_DIRECTION_INPUT); + items[0] = SPA_DICT_ITEM_INIT("my-tag-other-key", "my-special-other-tag-value"); + spa_tag_build_add_dict(&b, &SPA_DICT_INIT(items, 1)); + params[n_params++] = spa_tag_build_end(&b, &f); + } + + res = pw_stream_connect(camera->stream, + PW_DIRECTION_INPUT, + PW_ID_ANY, + PW_STREAM_FLAG_AUTOCONNECT | + PW_STREAM_FLAG_INACTIVE | + PW_STREAM_FLAG_MAP_BUFFERS, + params, n_params); + + if (res < 0) + { + RARCH_ERR("[Camera] [PipeWire]: can't connect: %s\n", spa_strerror(res)); + goto error; + } + + pw_thread_loop_unlock(camera->pw->thread_loop); + + return camera; + +error: + RARCH_ERR("[Camera] [PipeWire]: Failed to initialize camera\n"); + pipewire_free(camera); + return NULL; +} + +static bool pipewire_poll(void *data, + retro_camera_frame_raw_framebuffer_t frame_raw_cb, + retro_camera_frame_opengl_texture_t frame_gl_cb) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + const char *error = NULL; + + (void)frame_gl_cb; + + retro_assert(camera); + + if (pw_stream_get_state(camera->stream, &error) != PW_STREAM_STATE_STREAMING) + return false; + + if (!frame_raw_cb || !preprocess_image(camera)) + return false; + + frame_raw_cb(camera->buffer_output, camera->size.width, + camera->size.height, camera->size.width * 4); + return true; +} + +camera_driver_t camera_pipewire = { + pipewire_init, + pipewire_free, + pipewire_start, + pipewire_stop, + pipewire_poll, + "pipewire", +}; diff --git a/cheat_manager.c b/cheat_manager.c index d0d2e3ec05..d2baf97e5d 100644 --- a/cheat_manager.c +++ b/cheat_manager.c @@ -43,7 +43,6 @@ #include "cheat_manager.h" #include "msg_hash.h" -#include "configuration.h" #include "retroarch.h" #include "runloop.h" #include "dynamic.h" @@ -68,19 +67,18 @@ unsigned cheat_manager_get_size(void) #ifdef HAVE_CHEEVOS static void cheat_manager_pause_cheevos(void) { - const char *msg = msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT); + char msg[128]; + size_t _len = strlcpy(msg, msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT), sizeof(msg)); rcheevos_pause_hardcore(); - - runloop_msg_queue_push(msg, strlen(msg), 1, 180, true, NULL, + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", msg); } #endif -void cheat_manager_apply_cheats(void) +void cheat_manager_apply_cheats(bool notification_show_cheats_applied) { unsigned i, idx = 0; - settings_t *settings = config_get_ptr(); cheat_manager_t *cheat_st = &cheat_manager_state; if (!cheat_st->cheats) @@ -104,12 +102,13 @@ void cheat_manager_apply_cheats(void) } } - if (cheat_st->size > 0 && settings->bools.notification_show_cheats_applied) + if (cheat_st->size > 0 && notification_show_cheats_applied) { - const char *_msg = msg_hash_to_str(MSG_APPLYING_CHEAT); - runloop_msg_queue_push(_msg, strlen(_msg), 1, 180, true, NULL, + char msg[128]; + size_t _len = strlcpy(msg, msg_hash_to_str(MSG_APPLYING_CHEAT), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - RARCH_LOG("%s\n", _msg); + RARCH_LOG("%s\n", msg); } #ifdef HAVE_CHEEVOS @@ -121,11 +120,13 @@ void cheat_manager_apply_cheats(void) void cheat_manager_set_code(unsigned i, const char *str) { cheat_manager_t *cheat_st = &cheat_manager_state; - if (!cheat_st->cheats) + if (!cheat_st->cheats || string_is_empty(str)) return; - if (!string_is_empty(str)) - strcpy(cheat_st->cheats[i].code, str); + if (cheat_st->cheats[i].code) + free(cheat_st->cheats[i].code); + + cheat_st->cheats[i].code = strdup(str); cheat_st->cheats[i].state = true; } @@ -391,84 +392,71 @@ static void cheat_manager_load_cb_first_pass(char *key, char *value) } } -static void cheat_manager_load_cb_second_pass(char *key, char *value) +static void cheat_manager_load_cb_second_pass(char *s, char *value) { - char cheat_num_str[20]; - unsigned cheat_num; - unsigned cheat_idx; - unsigned idx = 5; - size_t key_length = 0; + unsigned cheat_num, cheat_idx; + char *numend = NULL; cheat_manager_t *cheat_st = &cheat_manager_state; - errno = 0; - - if (strncmp(key, "cheat", 5) != 0) + if (strncmp(s, "cheat", 5) != 0 || s[5] == '\0') return; - key_length = strlen((const char*)key); - - while (idx < key_length && key[idx] >= '0' && key[idx] <= '9' && idx < 24) - { - cheat_num_str[idx - 5] = key[idx]; - idx++; - } - - cheat_num_str[idx - 5] = '\0'; - - cheat_num = (unsigned)strtoul(cheat_num_str, NULL, 0); + cheat_num = (unsigned)strtoul(&s[5], &numend, 10); + if (numend == &s[5] || *numend == '\0') + return; if (cheat_num + cheat_st->loading_cheat_offset >= cheat_st->size) return; - key = key + idx + 1; + s = numend + 1; cheat_idx = cheat_num + cheat_st->loading_cheat_offset; - if (string_is_equal(key, "address")) + if (string_is_equal(s, "address")) cheat_st->cheats[cheat_idx].address = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "address_bit_position")) + else if (string_is_equal(s, "address_bit_position")) cheat_st->cheats[cheat_idx].address_mask = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "big_endian")) + else if (string_is_equal(s, "big_endian")) cheat_st->cheats[cheat_idx].big_endian = (string_is_equal(value, "true") || string_is_equal(value, "1")); - else if (string_is_equal(key, "cheat_type")) + else if (string_is_equal(s, "cheat_type")) cheat_st->cheats[cheat_idx].cheat_type = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "code")) + else if (string_is_equal(s, "code")) cheat_st->cheats[cheat_idx].code = strdup(value); - else if (string_is_equal(key, "desc")) + else if (string_is_equal(s, "desc")) cheat_st->cheats[cheat_idx].desc = strdup(value); - else if (string_is_equal(key, "enable")) + else if (string_is_equal(s, "enable")) cheat_st->cheats[cheat_idx].state = (string_is_equal(value, "true") || string_is_equal(value, "1")); - else if (string_is_equal(key, "handler")) + else if (string_is_equal(s, "handler")) cheat_st->cheats[cheat_idx].handler = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "memory_search_size")) + else if (string_is_equal(s, "memory_search_size")) cheat_st->cheats[cheat_idx].memory_search_size = (unsigned)strtoul(value, NULL, 0); - else if (string_starts_with_size(key, "repeat_", STRLEN_CONST("repeat_"))) + else if (string_starts_with_size(s, "repeat_", STRLEN_CONST("repeat_"))) { - if (string_is_equal(key, "repeat_add_to_address")) + if (string_is_equal(s, "repeat_add_to_address")) cheat_st->cheats[cheat_idx].repeat_add_to_address = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "repeat_add_to_value")) + else if (string_is_equal(s, "repeat_add_to_value")) cheat_st->cheats[cheat_idx].repeat_add_to_value = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "repeat_count")) + else if (string_is_equal(s, "repeat_count")) cheat_st->cheats[cheat_idx].repeat_count = (unsigned)strtoul(value, NULL, 0); } - else if (string_starts_with_size(key, "rumble", STRLEN_CONST("rumble"))) + else if (string_starts_with_size(s, "rumble", STRLEN_CONST("rumble"))) { - if (string_is_equal(key, "rumble_port")) + if (string_is_equal(s, "rumble_port")) cheat_st->cheats[cheat_idx].rumble_port = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_primary_duration")) + else if (string_is_equal(s, "rumble_primary_duration")) cheat_st->cheats[cheat_idx].rumble_primary_duration = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_primary_strength")) + else if (string_is_equal(s, "rumble_primary_strength")) cheat_st->cheats[cheat_idx].rumble_primary_strength = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_secondary_duration")) + else if (string_is_equal(s, "rumble_secondary_duration")) cheat_st->cheats[cheat_idx].rumble_secondary_duration = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_secondary_strength")) + else if (string_is_equal(s, "rumble_secondary_strength")) cheat_st->cheats[cheat_idx].rumble_secondary_strength = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_type")) + else if (string_is_equal(s, "rumble_type")) cheat_st->cheats[cheat_idx].rumble_type = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_value")) + else if (string_is_equal(s, "rumble_value")) cheat_st->cheats[cheat_idx].rumble_value = (unsigned)strtoul(value, NULL, 0); } - else if (string_is_equal(key, "value")) + else if (string_is_equal(s, "value")) cheat_st->cheats[cheat_idx].value = (unsigned)strtoul(value, NULL, 0); } @@ -631,6 +619,7 @@ void cheat_manager_update(cheat_manager_t *handle, unsigned handle_idx) } void cheat_manager_toggle_index(bool apply_cheats_after_toggle, + bool notification_show_cheats_applied, unsigned i) { cheat_manager_t *cheat_st = &cheat_manager_state; @@ -641,17 +630,17 @@ void cheat_manager_toggle_index(bool apply_cheats_after_toggle, cheat_manager_update(cheat_st, i); if (apply_cheats_after_toggle) - cheat_manager_apply_cheats(); + cheat_manager_apply_cheats(notification_show_cheats_applied); } -void cheat_manager_toggle(void) +void cheat_manager_toggle(bool notification_show_cheats_applied) { cheat_manager_t *cheat_st = &cheat_manager_state; if (!cheat_st->cheats || cheat_st->size == 0) return; cheat_st->cheats[cheat_st->ptr].state ^= true; - cheat_manager_apply_cheats(); + cheat_manager_apply_cheats(notification_show_cheats_applied); cheat_manager_update(cheat_st, cheat_st->ptr); } @@ -703,42 +692,32 @@ bool cheat_manager_get_code_state(unsigned i) return cheat_st->cheats[i].state; } -static bool cheat_manager_get_game_specific_filename( +static size_t cheat_manager_get_game_specific_filename( char *s, size_t len, - const char *path_cheat_database, - bool saving) + const char *path_cheat_database, bool saving) { char s1[PATH_MAX_LENGTH]; struct retro_system_info sysinfo; runloop_state_t *runloop_st = runloop_state_get_ptr(); const char *core_name = NULL; const char *game_name = NULL; - if (!core_get_system_info(&sysinfo)) - return false; - + return 0; core_name = sysinfo.library_name; game_name = path_basename_nocompression(runloop_st->name.cheatfile); - if ( string_is_empty(path_cheat_database) || string_is_empty(core_name) || string_is_empty(game_name)) - return false; - - fill_pathname_join_special(s1, - path_cheat_database, core_name, + return 0; + fill_pathname_join_special(s1, path_cheat_database, core_name, sizeof(s1)); - if (saving) { /* Check if directory is valid, if not, create it */ if (!path_is_valid(s1)) path_mkdir(s1); } - - fill_pathname_join_special(s, s1, game_name, len); - - return true; + return fill_pathname_join_special(s, s1, game_name, len); } void cheat_manager_load_game_specific_cheats(const char *path_cheat_database) @@ -788,7 +767,7 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, size_t idx, bool w bool is_search_initialization = (setting != NULL); rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system; unsigned offset = 0; - cheat_manager_t *cheat_st = &cheat_manager_state; + cheat_manager_t *cheat_st = &cheat_manager_state; #ifdef HAVE_MENU struct menu_state *menu_st = menu_state_get_ptr(); #endif @@ -854,8 +833,9 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, size_t idx, bool w meminfo.id = RETRO_MEMORY_SYSTEM_RAM; if (!core_get_memory(&meminfo)) { - const char *_msg = msg_hash_to_str(MSG_CHEAT_INIT_FAIL); - runloop_msg_queue_push(_msg, strlen(_msg), 1, 180, true, NULL, + char msg[128]; + size_t _len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_INIT_FAIL), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -885,7 +865,6 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, size_t idx, bool w if (is_search_initialization) { - const char *msg = NULL; if (cheat_st->prev_memory_buf) { free(cheat_st->prev_memory_buf); @@ -897,8 +876,9 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, size_t idx, bool w if (!cheat_st->prev_memory_buf) { - const char *_msg = msg_hash_to_str(MSG_CHEAT_INIT_FAIL); - runloop_msg_queue_push(_msg, strlen(_msg), 1, 180, true, NULL, + char msg[128]; + size_t _len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_INIT_FAIL), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -914,10 +894,11 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, size_t idx, bool w if (!cheat_st->matches) { - const char *_msg = msg_hash_to_str(MSG_CHEAT_INIT_FAIL); + char msg[128]; + size_t _len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_INIT_FAIL), sizeof(msg)); free(cheat_st->prev_memory_buf); cheat_st->prev_memory_buf = NULL; - runloop_msg_queue_push(_msg, strlen(_msg), 1, 180, true, NULL, + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -934,9 +915,12 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, size_t idx, bool w offset += cheat_st->memory_size_list[i]; } - msg = msg_hash_to_str(MSG_CHEAT_INIT_SUCCESS); - runloop_msg_queue_push(msg, strlen(msg), 1, 180, true, NULL, - MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + { + char msg[128]; + size_t _len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_INIT_SUCCESS), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } cheat_st->memory_search_initialized = true; } @@ -1034,8 +1018,8 @@ static int cheat_manager_search(enum cheat_search_type search_type) if (cheat_st->num_memory_buffers == 0 || !prev || !cheat_st->matches) { - const char *msg = msg_hash_to_str(MSG_CHEAT_SEARCH_NOT_INITIALIZED); - runloop_msg_queue_push(msg, strlen(msg), 1, 180, true, NULL, + _len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_SEARCH_NOT_INITIALIZED), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -1241,8 +1225,8 @@ int cheat_manager_add_matches(const char *path, if (cheat_st->num_matches + cheat_st->size > 100) { - const char *_msg = msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY); - runloop_msg_queue_push(_msg, strlen(_msg), 1, 180, true, NULL, + _len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -1281,8 +1265,8 @@ int cheat_manager_add_matches(const char *path, if (!cheat_manager_add_new_code(cheat_st->search_bit_size, idx, (mask << (byte_part * bits)), cheat_st->big_endian, curr_val)) { - const char *_msg = msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL); - runloop_msg_queue_push(_msg, strlen(_msg), 1, 180, true, NULL, + _len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -1296,8 +1280,8 @@ int cheat_manager_add_matches(const char *path, if (!cheat_manager_add_new_code(cheat_st->search_bit_size, idx, 0xFF, cheat_st->big_endian, curr_val)) { - const char *_msg = msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL); - runloop_msg_queue_push(_msg, strlen(_msg), 1, 180, true, NULL, + _len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -1638,30 +1622,30 @@ void cheat_manager_match_action(enum cheat_match_action_type match_action, unsig switch (bytes_per_item) { - case 2: - curr_val = cheat_st->big_endian ? + case 2: + curr_val = cheat_st->big_endian ? (*(curr + idx - offset) * 256) + *(curr + idx + 1 - offset) : *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256); - if (prev) - prev_val = cheat_st->big_endian ? + if (prev) + prev_val = cheat_st->big_endian ? (*(prev + idx) * 256) + *(prev + idx + 1) : *(prev + idx) + (*(prev + idx + 1) * 256); - break; - case 4: - curr_val = cheat_st->big_endian ? + break; + case 4: + curr_val = cheat_st->big_endian ? (*(curr + idx - offset) * 256 * 256 * 256) + (*(curr + idx + 1 - offset) * 256 * 256) + (*(curr + idx + 2 - offset) * 256) + *(curr + idx + 3 - offset) : *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256) + (*(curr + idx + 2 - offset) * 256 * 256) + (*(curr + idx + 3 - offset) * 256 * 256 * 256); - if (prev) - prev_val = cheat_st->big_endian ? + if (prev) + prev_val = cheat_st->big_endian ? (*(prev + idx) * 256 * 256 * 256) + (*(prev + idx + 1) * 256 * 256) + (*(prev + idx + 2) * 256) + *(prev + idx + 3) : *(prev + idx) + (*(prev + idx + 1) * 256) + (*(prev + idx + 2) * 256 * 256) + (*(prev + idx + 3) * 256 * 256 * 256); - break; - case 1: - default: - curr_val = *(curr + idx - offset); - if (prev) - prev_val = *(prev + idx); - break; + break; + case 1: + default: + curr_val = *(curr + idx - offset); + if (prev) + prev_val = *(prev + idx); + break; } if (match_action == CHEAT_MATCH_ACTION_TYPE_BROWSE) diff --git a/cheat_manager.h b/cheat_manager.h index 9f52e115db..c3646a9e81 100644 --- a/cheat_manager.h +++ b/cheat_manager.h @@ -215,13 +215,14 @@ void cheat_manager_index_next(void); void cheat_manager_index_prev(void); -void cheat_manager_toggle(void); +void cheat_manager_toggle(bool notification_show_cheats_applied); -void cheat_manager_apply_cheats(void); +void cheat_manager_apply_cheats(bool notification_show_cheats_applied); void cheat_manager_update(cheat_manager_t *handle, unsigned handle_idx); void cheat_manager_toggle_index(bool apply_cheats_after_toggle, + bool notification_show_cheats_applied, unsigned i); unsigned cheat_manager_get_buf_size(void); diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index a71b0ca5c7..46ac200d18 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -87,7 +87,6 @@ static rcheevos_locals_t rcheevos_locals = {{0}},/* memory */ #ifdef HAVE_THREADS CMD_EVENT_NONE, /* queued_command */ - false, /* game_placard_requested */ #endif "", /* user_agent_prefix */ "", /* user_agent_core */ @@ -112,8 +111,8 @@ rcheevos_locals_t* get_rcheevos_locals(void) Supporting functions. *****************************************************************************/ -#define CMD_CHEEVOS_NON_COMMAND -1 -static void rcheevos_show_game_placard(void); +#define CMD_CHEEVOS_FINALIZE_LOAD -1 +static void rcheevos_finalize_game_load_on_ui_thread(void); #ifndef CHEEVOS_VERBOSE void rcheevos_log(const char* fmt, ...) @@ -243,7 +242,7 @@ static void rcheevos_show_mastery_placard(void) char msg[128]; char badge_name[32]; const char* displayname = rc_client_get_user_info(rcheevos_locals.client)->display_name; - const bool content_runtime_log = settings->bools.content_runtime_log; + const bool content_runtime_log = settings->bools.content_runtime_log; const bool content_runtime_log_aggr = settings->bools.content_runtime_log_aggregate; size_t __len = strlcpy(msg, displayname, sizeof(msg)); @@ -310,7 +309,7 @@ static void rcheevos_award_achievement(const rc_client_achievement_t* cheevo) strlcpy(title, msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), sizeof(title)); - snprintf(subtitle, sizeof(subtitle), "%s (%d)", cheevo->title, cheevo->points); + snprintf(subtitle, sizeof(subtitle), "%s (%lu)", cheevo->title, (unsigned long)cheevo->points); gfx_widgets_push_achievement(title, subtitle, cheevo->badge_name); } @@ -345,17 +344,19 @@ static void rcheevos_award_achievement(const rc_client_achievement_t* cheevo) if (shotname) { + const char *path_directory_screenshot = settings->paths.directory_screenshot; video_driver_state_t* video_st = video_state_get_ptr();; snprintf(shotname, shotname_len, "%s/%s-cheevo-%u", - settings->paths.directory_screenshot, + path_directory_screenshot, path_basename(path_get(RARCH_PATH_BASENAME)), (unsigned)cheevo->id); shotname[shotname_len - 1] = '\0'; - if (take_screenshot(settings->paths.directory_screenshot, + if (take_screenshot(path_directory_screenshot, shotname, true, - video_st->frame_cache_data && (video_st->frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID), + video_st->frame_cache_data + && (video_st->frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID), false, true)) CHEEVOS_LOG(RCHEEVOS_TAG @@ -372,7 +373,8 @@ static void rcheevos_award_achievement(const rc_client_achievement_t* cheevo) #endif } -static void rcheevos_lboard_submitted(const rc_client_leaderboard_t* lboard, const rc_client_leaderboard_scoreboard_t* scoreboard) +static void rcheevos_lboard_submitted(const rc_client_leaderboard_t* lboard, + const rc_client_leaderboard_scoreboard_t* scoreboard) { const settings_t* settings = config_get_ptr(); if (lboard && settings->bools.cheevos_visibility_lboard_submit) @@ -402,8 +404,9 @@ static void rcheevos_lboard_submitted(const rc_client_leaderboard_t* lboard, con static void rcheevos_lboard_canceled(const rc_client_leaderboard_t* lboard) { - const settings_t* settings = config_get_ptr(); - if (lboard && settings->bools.cheevos_visibility_lboard_cancel) + const settings_t* settings = config_get_ptr(); + bool cheevos_visibility_lboard_cancel = settings->bools.cheevos_visibility_lboard_cancel; + if (cheevos_visibility_lboard_cancel) { char buffer[256]; size_t _len = strlcpy(buffer, msg_hash_to_str(MSG_LEADERBOARD_FAILED), sizeof(buffer)); @@ -416,8 +419,9 @@ static void rcheevos_lboard_canceled(const rc_client_leaderboard_t* lboard) static void rcheevos_lboard_started(const rc_client_leaderboard_t* lboard) { - const settings_t* settings = config_get_ptr(); - if (settings->bools.cheevos_visibility_lboard_start) + const settings_t *settings = config_get_ptr(); + bool cheevos_visibility_lboard_start = settings->bools.cheevos_visibility_lboard_start; + if (cheevos_visibility_lboard_start) { char buffer[256]; size_t _len = strlcpy(buffer, msg_hash_to_str(MSG_LEADERBOARD_STARTED), @@ -465,7 +469,9 @@ static void rcheevos_progress_updated(rcheevos_locals_t* locals, const rc_client_achievement_t* cheevo) { settings_t* settings = config_get_ptr(); - if (cheevo && gfx_widgets_ready() && settings->bools.cheevos_visibility_progress_tracker) + if ( cheevo + && gfx_widgets_ready() + && settings->bools.cheevos_visibility_progress_tracker) gfx_widget_set_achievement_progress(cheevo->badge_name, cheevo->measured_progress); } @@ -674,7 +680,6 @@ void rcheevos_pause_hardcore(void) bool rcheevos_unload(void) { - settings_t* settings = config_get_ptr(); const bool was_loaded = rcheevos_is_game_loaded(); #ifdef HAVE_GFX_WIDGETS @@ -686,7 +691,6 @@ bool rcheevos_unload(void) #ifdef HAVE_THREADS rcheevos_locals.queued_command = CMD_EVENT_NONE; - rcheevos_locals.game_placard_requested = false; #endif if (rcheevos_locals.memory.count > 0) @@ -711,7 +715,7 @@ bool rcheevos_unload(void) rcheevos_locals.queued_command = CMD_EVENT_NONE; #endif - if (!settings->arrays.cheevos_token[0]) + if (!config_get_ptr()->arrays.cheevos_token[0]) { /* If the config-level token has been cleared, we need to re-login on * loading the next game. Easiest way to do that is to destroy the client */ @@ -727,31 +731,26 @@ bool rcheevos_unload(void) void rcheevos_leaderboard_trackers_visibility_changed(void) { #if defined(HAVE_GFX_WIDGETS) - const settings_t* settings = config_get_ptr(); - if (!settings->bools.cheevos_visibility_lboard_trackers) - { - /* Hide any visible trackers */ + bool cheevos_visibility_lboard_trackers = config_get_ptr()->bools.cheevos_visibility_lboard_trackers; + /* Hide any visible trackers */ + if (!cheevos_visibility_lboard_trackers) gfx_widgets_clear_leaderboard_displays(); - } - else - { - /* No way to immediately request trackers be reshown, but they - * will reappear the next time they're updated */ - } #endif } +/* Disable slowdown */ static void rcheevos_enforce_hardcore_settings(void) { - /* disable slowdown */ runloop_state_get_ptr()->flags &= ~RUNLOOP_FLAG_SLOWMOTION; } static void rcheevos_toggle_hardcore_active(rcheevos_locals_t* locals) { - settings_t* settings = config_get_ptr(); - bool rewind_enable = settings->bools.rewind_enable; - const bool was_enabled = rcheevos_hardcore_active(); + settings_t* settings = config_get_ptr(); + bool rewind_enable = settings->bools.rewind_enable; + const bool was_enabled = rcheevos_hardcore_active(); + bool notification_show_cheats_applied = + settings->bools.notification_show_cheats_applied; if (!was_enabled) { @@ -768,7 +767,7 @@ static void rcheevos_toggle_hardcore_active(rcheevos_locals_t* locals) #ifdef HAVE_CHEATS /* If one or more emulator managed cheats is active, abort */ - cheat_manager_apply_cheats(); + cheat_manager_apply_cheats(notification_show_cheats_applied); if (!locals->hardcore_allowed) { locals->hardcore_being_enabled = false; @@ -827,13 +826,17 @@ static void rcheevos_toggle_hardcore_active(rcheevos_locals_t* locals) command_event(CMD_EVENT_REWIND_INIT, NULL); } } + +#ifdef HAVE_NETWORKING + /* force sending a savestate to clients so they'll drop out of hardcore too */ + netplay_force_send_savestate(); +#endif } void rcheevos_toggle_hardcore_paused(void) { - settings_t* settings = config_get_ptr(); /* if hardcore mode is not enabled, we can't toggle whether its active */ - if (settings->bools.cheevos_hardcore_mode_enable) + if (config_get_ptr()->bools.cheevos_hardcore_mode_enable) rcheevos_toggle_hardcore_active(&rcheevos_locals); } @@ -863,13 +866,13 @@ void rcheevos_hardcore_enabled_changed(void) void rcheevos_validate_config_settings(void) { int i; + unsigned console_id; const rc_disallowed_setting_t *disallowed_settings = NULL; core_option_manager_t* coreopts = NULL; struct retro_system_info *sysinfo = &runloop_state_get_ptr()->system.info; const settings_t* settings = config_get_ptr(); - unsigned console_id; if (!rcheevos_hardcore_active()) return; @@ -880,10 +883,13 @@ void rcheevos_validate_config_settings(void) * it'll wait for the next vsync event, effectively halfing the fps. the * auto setting should achieve the most accurate frame rate anyway, so * disallow any manual values */ - if (!settings->bools.video_frame_delay_auto && settings->uints.video_frame_delay != 0) + if ( !settings->bools.video_frame_delay_auto + && settings->uints.video_frame_delay != 0) { - const char* error = msg_hash_to_str(MSG_CHEEVOS_HARDCORE_PAUSED_MANUAL_FRAME_DELAY); - CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", msg_hash_to_str_us(MSG_CHEEVOS_HARDCORE_PAUSED_MANUAL_FRAME_DELAY)); + const char* error = msg_hash_to_str( + MSG_CHEEVOS_HARDCORE_PAUSED_MANUAL_FRAME_DELAY); + CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", + msg_hash_to_str_us(MSG_CHEEVOS_HARDCORE_PAUSED_MANUAL_FRAME_DELAY)); rcheevos_pause_hardcore(); runloop_msg_queue_push(error, strlen(error), 0, 4 * 60, false, NULL, @@ -901,8 +907,10 @@ void rcheevos_validate_config_settings(void) * wouldn't know how to change it to auto. */ if (settings->uints.video_swap_interval > 1) { - const char* error = msg_hash_to_str(MSG_CHEEVOS_HARDCORE_PAUSED_VSYNC_SWAP_INTERVAL); - CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", msg_hash_to_str_us(MSG_CHEEVOS_HARDCORE_PAUSED_VSYNC_SWAP_INTERVAL)); + const char* error = msg_hash_to_str( + MSG_CHEEVOS_HARDCORE_PAUSED_VSYNC_SWAP_INTERVAL); + CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", + msg_hash_to_str_us(MSG_CHEEVOS_HARDCORE_PAUSED_VSYNC_SWAP_INTERVAL)); rcheevos_pause_hardcore(); runloop_msg_queue_push(error, strlen(error), 0, 4 * 60, false, NULL, @@ -914,8 +922,10 @@ void rcheevos_validate_config_settings(void) * can slow down the actual number of rendered frames per second. */ if (settings->uints.video_black_frame_insertion > 0) { - const char* error = msg_hash_to_str(MSG_CHEEVOS_HARDCORE_PAUSED_BLACK_FRAME_INSERTION); - CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", msg_hash_to_str_us(MSG_CHEEVOS_HARDCORE_PAUSED_BLACK_FRAME_INSERTION)); + const char* error = msg_hash_to_str( + MSG_CHEEVOS_HARDCORE_PAUSED_BLACK_FRAME_INSERTION); + CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", + msg_hash_to_str_us(MSG_CHEEVOS_HARDCORE_PAUSED_BLACK_FRAME_INSERTION)); rcheevos_pause_hardcore(); runloop_msg_queue_push(error, strlen(error), 0, 4 * 60, false, NULL, @@ -927,7 +937,8 @@ void rcheevos_validate_config_settings(void) return; disallowed_settings = rc_libretro_get_disallowed_settings(sysinfo->library_name); - if (disallowed_settings && retroarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts)) + if ( disallowed_settings + && retroarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts)) { for (i = 0; i < (int)coreopts->size; i++) { @@ -955,7 +966,8 @@ void rcheevos_validate_config_settings(void) console_id = game ? game->console_id : 0; } - if (console_id && !rc_libretro_is_system_allowed(sysinfo->library_name, console_id)) + if ( console_id + && !rc_libretro_is_system_allowed(sysinfo->library_name, console_id)) { char buffer[256]; size_t _len = snprintf(buffer, sizeof(buffer), @@ -978,16 +990,12 @@ void rcheevos_test(void) #ifdef HAVE_THREADS if (rcheevos_locals.queued_command != CMD_EVENT_NONE) { - if ((int)rcheevos_locals.queued_command != CMD_CHEEVOS_NON_COMMAND) + if (rcheevos_locals.queued_command == CMD_CHEEVOS_FINALIZE_LOAD) + rcheevos_finalize_game_load_on_ui_thread(); + else command_event(rcheevos_locals.queued_command, NULL); rcheevos_locals.queued_command = CMD_EVENT_NONE; - - if (rcheevos_locals.game_placard_requested) - { - rcheevos_locals.game_placard_requested = false; - rcheevos_show_game_placard(); - } } #endif @@ -1203,7 +1211,8 @@ static void rcheevos_show_game_placard(void) size_t _len; char msg[256]; rc_client_user_game_summary_t summary; - const settings_t* settings = config_get_ptr(); + const settings_t* settings = config_get_ptr(); + unsigned cheevos_visibility_summary = settings->uints.cheevos_visibility_summary; const rc_client_game_t* game = rc_client_get_game_info(rcheevos_locals.client); if (!game) /* Make sure there's actually a game loaded */ return; @@ -1213,7 +1222,8 @@ static void rcheevos_show_game_placard(void) if (summary.num_core_achievements == 0) { if (summary.num_unofficial_achievements == 0) - _len = snprintf(msg, sizeof(msg), "%s", msg_hash_to_str(MSG_CHEEVOS_GAME_HAS_NO_ACHIEVEMENTS)); + _len = strlcpy(msg, msg_hash_to_str(MSG_CHEEVOS_GAME_HAS_NO_ACHIEVEMENTS), + sizeof(msg)); else _len = snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_CHEEVOS_UNOFFICIAL_ACHIEVEMENTS_ACTIVATED), @@ -1251,8 +1261,8 @@ static void rcheevos_show_game_placard(void) msg[sizeof(msg) - 1] = 0; CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", msg); - if ( settings->uints.cheevos_visibility_summary == RCHEEVOS_SUMMARY_ALLGAMES - || (settings->uints.cheevos_visibility_summary == RCHEEVOS_SUMMARY_HASCHEEVOS + if ( cheevos_visibility_summary == RCHEEVOS_SUMMARY_ALLGAMES + || (cheevos_visibility_summary == RCHEEVOS_SUMMARY_HASCHEEVOS && (summary.num_core_achievements || summary.num_unofficial_achievements))) { #if defined (HAVE_GFX_WIDGETS) @@ -1346,7 +1356,6 @@ static void rcheevos_client_login_callback(int result, else { settings_t* settings = config_get_ptr(); - if (user->token[0]) { /* store the token, clear the password */ @@ -1373,7 +1382,16 @@ static void rcheevos_client_login_callback(int result, static void rcheevos_finalize_game_load(rc_client_t* client) { - rcheevos_client_download_achievement_badges(client); + settings_t* settings = config_get_ptr(); + bool want_badges = settings->bools.cheevos_badges_enable; +#if !defined(HAVE_GFX_WIDGETS) + /* Then badges are only needed for xmb and ozone menus */ + want_badges = want_badges && + ( string_is_equal(settings->arrays.menu_driver, "xmb") + || string_is_equal(settings->arrays.menu_driver, "ozone")); +#endif + if (want_badges) + rcheevos_client_download_achievement_badges(client); if (!rc_client_is_processing_required(client)) { @@ -1382,12 +1400,31 @@ static void rcheevos_finalize_game_load(rc_client_t* client) } } +static void rcheevos_finalize_game_load_on_ui_thread(void) +{ + rcheevos_show_game_placard(); + +#if HAVE_REWIND + if (!rcheevos_hardcore_active()) + { + /* Re-enable rewind. Additional space will be + * allocated for the achievement state data */ + if (config_get_ptr()->bools.rewind_enable) + command_event(CMD_EVENT_REWIND_REINIT, NULL); + } +#endif + +#ifdef HAVE_NETWORKING + netplay_reinit_serialization(); +#endif +} + static void rcheevos_client_load_game_callback(int result, const char* error_message, rc_client_t* client, void* userdata) { - const settings_t* settings = config_get_ptr(); - const rc_client_game_t* game = rc_client_get_game_info(client); char msg[256]; + const settings_t *settings = config_get_ptr(); + const rc_client_game_t *game = rc_client_get_game_info(client); #if defined(HAVE_GFX_WIDGETS) gfx_widget_set_cheevos_set_loading(false); @@ -1431,7 +1468,8 @@ static void rcheevos_client_load_game_callback(int result, if (settings && settings->bools.cheevos_verbose_enable) { - const char *_msg = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE); + const char *_msg = msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE); runloop_msg_queue_push(_msg, strlen(_msg), 0, 4 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_WARNING); @@ -1446,47 +1484,26 @@ static void rcheevos_client_load_game_callback(int result, rc_client_set_read_memory_function(client, rcheevos_client_read_memory); } -#ifdef HAVE_THREADS - if (!video_driver_is_threaded() && !task_is_on_main_thread()) - { - /* have to "schedule" this. game image should not be loaded on background thread */ - rcheevos_locals.queued_command = CMD_CHEEVOS_NON_COMMAND; - rcheevos_locals.game_placard_requested = true; - } - else -#endif - rcheevos_show_game_placard(); - rcheevos_finalize_game_load(client); + /* Hardcore is active. we're going to start processing + * achievements. make sure restrictions are enforced */ if (rcheevos_hardcore_active()) { - /* hardcore is active. we're going to start processing - * achievements. make sure restrictions are enforced */ rcheevos_validate_config_settings(); rcheevos_enforce_hardcore_settings(); } - else - { -#if HAVE_REWIND - /* Re-enable rewind. Additional space will be allocated for the achievement state data */ - if (settings->bools.rewind_enable) - { -#ifdef HAVE_THREADS - if (!task_is_on_main_thread()) - { - /* Have to "schedule" this. CMD_EVENT_REWIND_REINIT should - * only be called on the main thread */ - rcheevos_locals.queued_command = CMD_EVENT_REWIND_REINIT; - } - else -#endif - command_event(CMD_EVENT_REWIND_REINIT, NULL); - } -#endif - } rcheevos_spectating_changed(); /* synchronize spectating state */ + +#ifdef HAVE_THREADS + /* Have to "schedule" this. Game image should not be + * loaded into memory on background thread */ + if (!task_is_on_main_thread()) + rcheevos_locals.queued_command = CMD_CHEEVOS_FINALIZE_LOAD; + else +#endif + rcheevos_finalize_game_load_on_ui_thread(); } static rc_clock_t rcheevos_client_get_time_millisecs(const rc_client_t* client) @@ -1494,8 +1511,6 @@ static rc_clock_t rcheevos_client_get_time_millisecs(const rc_client_t* client) return cpu_features_get_time_usec() / 1000; } - - bool rcheevos_load(const void *data) { const struct retro_game_info *info = (const struct retro_game_info*)data; @@ -1533,9 +1548,7 @@ bool rcheevos_load(const void *data) sizeof(rcheevos_locals.user_agent_core)); if (rcheevos_locals.client) - { rc_client_unload_game(rcheevos_locals.client); - } else { rcheevos_locals.client = rc_client_create(rcheevos_client_read_memory, rcheevos_client_server_call); @@ -1574,23 +1587,17 @@ bool rcheevos_load(const void *data) { /* user not logged in, do so now */ if (settings->arrays.cheevos_token[0]) - { rc_client_begin_login_with_token(rcheevos_locals.client, settings->arrays.cheevos_username, settings->arrays.cheevos_token, rcheevos_client_login_callback, NULL); - } else - { rc_client_begin_login_with_password(rcheevos_locals.client, settings->arrays.cheevos_username, settings->arrays.cheevos_password, rcheevos_client_login_callback, NULL); - } } if (rcheevos_hardcore_active()) - { rcheevos_enforce_hardcore_settings(); - } /* provide hooks for reading files */ rc_hash_reset_cdreader_hooks(); @@ -1603,8 +1610,6 @@ bool rcheevos_load(const void *data) rc_client_begin_identify_and_load_game(rcheevos_locals.client, RC_CONSOLE_UNKNOWN, info->path, (const uint8_t*)info->data, info->size, rcheevos_client_load_game_callback, NULL); - - return true; } diff --git a/cheevos/cheevos_client.c b/cheevos/cheevos_client.c index 1f8e480d1f..1b8c95fdb4 100644 --- a/cheevos/cheevos_client.c +++ b/cheevos/cheevos_client.c @@ -17,12 +17,6 @@ #include "cheevos.h" -#include "../configuration.h" -#include "../file_path_special.h" -#include "../paths.h" -#include "../retroarch.h" -#include "../version.h" - #include #include #include @@ -31,6 +25,11 @@ #include "../frontend/frontend_driver.h" #include "../tasks/tasks_internal.h" +#include "../file_path_special.h" +#include "../paths.h" +#include "../runloop.h" +#include "../version.h" + #ifdef HAVE_PRESENCE #include "../network/presence.h" #endif @@ -289,20 +288,20 @@ static void rcheevos_client_http_task_save_callback(retro_task_t* task, void rcheevos_client_http_load_response(const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data) { - size_t size = 0; char* contents; - FILE* file = fopen(CHEEVOS_JSON_OVERRIDE, "rb"); + size_t _len = 0; + FILE* file = fopen(CHEEVOS_JSON_OVERRIDE, "rb"); fseek(file, 0, SEEK_END); - size = ftell(file); + _len = ftell(file); fseek(file, 0, SEEK_SET); - contents = (char*)malloc(size + 1); - fread((void*)contents, 1, size, file); + contents = (char*)malloc(_len + 1); + fread((void*)contents, 1, _len, file); fclose(file); - contents[size] = 0; - CHEEVOS_LOG(RCHEEVOS_TAG "Loaded game info. Read %u bytes to %s\n", size, CHEEVOS_JSON_OVERRIDE); + contents[_len] = 0; + CHEEVOS_LOG(RCHEEVOS_TAG "Loaded game info. Read %u bytes to %s\n", _len, CHEEVOS_JSON_OVERRIDE); callback(contents, 200, callback_data); } @@ -598,25 +597,13 @@ void rcheevos_client_download_game_badge(const rc_client_game_t* game) void rcheevos_client_download_achievement_badges(rc_client_t* client) { - rc_client_download_queue_t* queue; uint32_t i; + rc_client_download_queue_t *queue = (rc_client_download_queue_t*) + calloc(1, sizeof(*queue)); -#if !defined(HAVE_GFX_WIDGETS) /* we always want badges if widgets are enabled */ - settings_t* settings = config_get_ptr(); - /* User has explicitly disabled badges */ - if (!settings->bools.cheevos_badges_enable) - return; - - /* badges are only needed for xmb and ozone menus */ - if (!string_is_equal(settings->arrays.menu_driver, "xmb") && - !string_is_equal(settings->arrays.menu_driver, "ozone")) - return; -#endif /* !defined(HAVE_GFX_WIDGETS) */ - - queue = (rc_client_download_queue_t*)calloc(1, sizeof(*queue)); queue->client = client; - queue->game = rc_client_get_game_info(client); - queue->list = rc_client_create_achievement_list(client, + queue->game = rc_client_get_game_info(client); + queue->list = rc_client_create_achievement_list(client, RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL, RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_PROGRESS); queue->outstanding_requests = RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS; diff --git a/cheevos/cheevos_locals.h b/cheevos/cheevos_locals.h index 16907a5fac..74caf86e46 100644 --- a/cheevos/cheevos_locals.h +++ b/cheevos/cheevos_locals.h @@ -86,7 +86,6 @@ typedef struct rcheevos_locals_t #ifdef HAVE_THREADS enum event_command queued_command; /* action queued by background thread to be run on main thread */ - bool game_placard_requested; /* request to display game placard */ #endif char user_agent_prefix[128]; /* RetroArch/OS version information */ diff --git a/cheevos/cheevos_menu.c b/cheevos/cheevos_menu.c index a9cb09423b..d7ec053c2b 100644 --- a/cheevos/cheevos_menu.c +++ b/cheevos/cheevos_menu.c @@ -45,55 +45,49 @@ #if HAVE_MENU -bool rcheevos_menu_get_state(unsigned menu_offset, char* buffer, size_t buffer_size) +size_t rcheevos_menu_get_state(unsigned menu_offset, char *s, size_t len) { const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals(); if (menu_offset < rcheevos_locals->menuitem_count) { - const rcheevos_menuitem_t* menuitem = &rcheevos_locals->menuitems[menu_offset]; + const rcheevos_menuitem_t* menuitem = &rcheevos_locals->menuitems[menu_offset]; const rc_client_achievement_t* cheevo = menuitem->achievement; if (cheevo) { + size_t _len; if (cheevo->state != RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE) - strlcpy(buffer, msg_hash_to_str(menuitem->state_label_idx), buffer_size); + _len = strlcpy(s, msg_hash_to_str(menuitem->state_label_idx), len); else { - const char* missable = cheevo->type == RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE ? "[m] " : ""; - size_t _len = strlcpy(buffer, missable, buffer_size); - _len += strlcpy(buffer + _len, msg_hash_to_str(menuitem->state_label_idx), buffer_size - _len); + const char* missable = (cheevo->type == RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE) ? "[m] " : ""; + _len = strlcpy(s, missable, len); + _len += strlcpy(s + _len, msg_hash_to_str(menuitem->state_label_idx), len - _len); if (cheevo->measured_progress[0]) { - _len += strlcpy(buffer + _len, " - ", buffer_size - _len); - strlcpy(buffer + _len, cheevo->measured_progress, buffer_size - _len); + _len += strlcpy(s + _len, " - ", len - _len); + _len += strlcpy(s + _len, cheevo->measured_progress, len - _len); } } - return true; + return _len; } } - - if (buffer) - buffer[0] = '\0'; - - return false; + if (s) + s[0] = '\0'; + return 0; } -bool rcheevos_menu_get_sublabel(unsigned menu_offset, char* buffer, size_t buffer_size) +size_t rcheevos_menu_get_sublabel(unsigned menu_offset, char *s, size_t len) { const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals(); - if (menu_offset < rcheevos_locals->menuitem_count && buffer) + if (menu_offset < rcheevos_locals->menuitem_count && s) { const rcheevos_menuitem_t* menuitem = &rcheevos_locals->menuitems[menu_offset]; if (menuitem->achievement) - { - strlcpy(buffer, menuitem->achievement->description, buffer_size); - return true; - } + return strlcpy(s, menuitem->achievement->description, len); } - - if (buffer) - buffer[0] = '\0'; - - return false; + if (s) + s[0] = '\0'; + return 0; } void rcheevos_menu_reset_badges(void) @@ -250,12 +244,10 @@ uintptr_t rcheevos_menu_get_badge_texture(unsigned menu_offset) return 0; } -void rcheevos_menu_populate_hardcore_pause_submenu(void* data) +void rcheevos_menu_populate_hardcore_pause_submenu(void* data, bool cheevos_hardcore_mode_enable) { const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals(); - menu_displaylist_info_t* info = (menu_displaylist_info_t*)data; - const settings_t* settings = config_get_ptr(); - const bool cheevos_hardcore_mode_enable = settings->bools.cheevos_hardcore_mode_enable; + menu_displaylist_info_t* info = (menu_displaylist_info_t*)data; if (cheevos_hardcore_mode_enable && rc_client_get_game_info(rcheevos_locals->client)) { @@ -288,12 +280,12 @@ void rcheevos_menu_populate_hardcore_pause_submenu(void* data) } } -void rcheevos_menu_populate(void* data) +void rcheevos_menu_populate(void* data, bool cheevos_enable, + bool cheevos_hardcore_mode_enable) { menu_displaylist_info_t* info = (menu_displaylist_info_t*)data; rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals(); const rc_client_game_t* game = rc_client_get_game_info(rcheevos_locals->client); - const settings_t* settings = config_get_ptr(); rc_client_achievement_list_t* list = rc_client_create_achievement_list(rcheevos_locals->client, RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL, @@ -303,7 +295,7 @@ void rcheevos_menu_populate(void* data) rcheevos_menu_reset_badges(); rcheevos_locals->menuitem_count = 0; - if (rcheevos_locals->client->state.disconnect) + if (rcheevos_locals->client && rcheevos_locals->client->state.disconnect) { menu_entries_append(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_SERVER_UNREACHABLE), @@ -314,8 +306,10 @@ void rcheevos_menu_populate(void* data) if (game && game->id != 0) { - /* first menu item is the Pause/Resume Hardcore option (unless hardcore is completely disabled) */ - if (settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable) + /* First menu item is the Pause/Resume Hardcore option + * (unless hardcore is completely disabled) */ + if ( cheevos_enable + && cheevos_hardcore_mode_enable) { if (rc_client_get_hardcore_enabled(rcheevos_locals->client)) menu_entries_append(info->list, diff --git a/cheevos/cheevos_menu.h b/cheevos/cheevos_menu.h index 9813557299..64725ebda7 100644 --- a/cheevos/cheevos_menu.h +++ b/cheevos/cheevos_menu.h @@ -28,10 +28,11 @@ RETRO_BEGIN_DECLS -void rcheevos_menu_populate(void* data); -void rcheevos_menu_populate_hardcore_pause_submenu(void* data); -bool rcheevos_menu_get_state(unsigned menu_offset, char* buffer, size_t buffer_size); -bool rcheevos_menu_get_sublabel(unsigned menu_offset, char* buffer, size_t buffer_size); +void rcheevos_menu_populate(void* data, bool cheevos_enable, + bool cheevos_hardcore_mode_enable); +void rcheevos_menu_populate_hardcore_pause_submenu(void* data, bool cheevos_hardcore_mode_enable); +size_t rcheevos_menu_get_state(unsigned menu_offset, char *s, size_t len); +size_t rcheevos_menu_get_sublabel(unsigned menu_offset, char *s, size_t len); uintptr_t rcheevos_menu_get_badge_texture(unsigned menu_offset); void rcheevos_menu_reset_badges(void); diff --git a/command.c b/command.c index 1f33a6a008..009b1867b8 100644 --- a/command.c +++ b/command.c @@ -67,7 +67,7 @@ #include "version.h" #include "version_git.h" -#define CMD_BUF_SIZE 4096 +#define CMD_BUF_SIZE 4096 static void command_post_state_loaded(void) { @@ -84,11 +84,10 @@ static void command_post_state_loaded(void) netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL); #endif { - settings_t *settings = config_get_ptr(); video_driver_state_t *video_st = video_state_get_ptr(); bool frame_time_counter_reset_after_load_state = - settings->bools.frame_time_counter_reset_after_load_state; + config_get_ptr()->bools.frame_time_counter_reset_after_load_state; if (frame_time_counter_reset_after_load_state) video_st->frame_time_count = 0; } @@ -160,8 +159,7 @@ static void command_parse_sub_msg(command_t *handle, const char *tok) RARCH_WARN(msg_hash_to_str(MSG_UNRECOGNIZED_COMMAND), tok); } -static void command_parse_msg( - command_t *handle, char *buf) +static void command_parse_msg(command_t *handle, char *buf) { char *save = NULL; const char *tok = strtok_r(buf, "\n", &save); @@ -184,13 +182,12 @@ typedef struct socklen_t cmd_source_len; } command_network_t; -static void network_command_reply( - command_t *cmd, - const char * data, size_t len) +static void network_command_reply(command_t *cmd, + const char *s, size_t len) { command_network_t *netcmd = (command_network_t*)cmd->userptr; /* Respond (fire and forget since it's UDP) */ - sendto(netcmd->net_fd, data, len, 0, + sendto(netcmd->net_fd, s, len, 0, (struct sockaddr*)&netcmd->cmd_source, netcmd->cmd_source_len); } @@ -235,8 +232,8 @@ command_t* command_network_new(uint16_t port) command_t *cmd = (command_t*)calloc(1, sizeof(*cmd)); command_network_t *netcmd = (command_network_t*)calloc( 1, sizeof(command_network_t)); - int fd = socket_init( - (void**)&res, port, NULL, SOCKET_TYPE_DATAGRAM, AF_INET); + int fd = socket_init((void**)&res, port, NULL, + SOCKET_TYPE_DATAGRAM, AF_INET); RARCH_LOG("[NetCMD]: %s %hu.\n", msg_hash_to_str(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT), @@ -281,12 +278,11 @@ typedef struct char stdin_buf[CMD_BUF_SIZE]; } command_stdin_t; -static void stdin_command_reply( - command_t *cmd, - const char * data, size_t len) +static void stdin_command_reply(command_t *cmd, + const char *s, size_t len) { /* Just write to stdout! */ - fwrite(data, 1, len, stdout); + fwrite(s, 1, len, stdout); fflush(stdout); } @@ -341,7 +337,7 @@ command_t* command_stdin_new(void) command_t *cmd; command_stdin_t *stdincmd; -#ifndef _WIN32 +#if !(defined(_WIN32) || defined(EMSCRIPTEN)) #ifdef HAVE_NETWORKING if (!socket_nonblock(STDIN_FILENO)) return NULL; @@ -367,6 +363,58 @@ command_t* command_stdin_new(void) } #endif +#if defined(EMSCRIPTEN) +#include "frontend/drivers/platform_emscripten.h" +typedef struct +{ + char command_buf[CMD_BUF_SIZE]; +} command_emscripten_t; + +static void emscripten_command_reply(command_t *_cmd, + const char *s, size_t len) +{ + platform_emscripten_command_reply(s, len); +} + +static void emscripten_command_free(command_t *handle) +{ + free(handle->userptr); + free(handle); +} + +static void command_emscripten_poll(command_t *handle) +{ + command_emscripten_t *emscriptencmd = (command_emscripten_t*)handle->userptr; + ptrdiff_t msg_len = platform_emscripten_command_read((char **)(&emscriptencmd->command_buf), CMD_BUF_SIZE); + if (msg_len == 0) + return; + command_parse_msg(handle, emscriptencmd->command_buf); +} + +command_t* command_emscripten_new(void) +{ + command_t *cmd; + command_emscripten_t *emscriptencmd; + + cmd = (command_t*)calloc(1, sizeof(command_t)); + emscriptencmd = (command_emscripten_t*)calloc(1, sizeof(command_emscripten_t)); + + if (!cmd) + return NULL; + if (!emscriptencmd) + { + free(cmd); + return NULL; + } + cmd->userptr = emscriptencmd; + cmd->poll = command_emscripten_poll; + cmd->replier = emscripten_command_reply; + cmd->destroy = emscripten_command_free; + + return cmd; +} +#endif + bool command_get_config_param(command_t *cmd, const char* arg) { size_t _len; @@ -446,12 +494,11 @@ typedef struct int last_fd; } command_uds_t; -static void uds_command_reply( - command_t *cmd, - const char * data, size_t len) +static void uds_command_reply(command_t *cmd, + const char *s, size_t len) { command_uds_t *subcmd = (command_uds_t*)cmd->userptr; - write(subcmd->last_fd, data, len); + write(subcmd->last_fd, s, len); } static void uds_command_free(command_t *handle) @@ -693,13 +740,12 @@ bool command_show_osd_msg(command_t *cmd, const char* arg) bool command_load_state_slot(command_t *cmd, const char *arg) { - char state_path[16384]; + char state_path[PATH_MAX_LENGTH] = ""; size_t _len = 0; char reply[128] = ""; unsigned int slot = (unsigned int)strtoul(arg, NULL, 10); bool savestates_enabled = core_info_current_supports_savestate(); bool ret = false; - state_path[0] = '\0'; _len = strlcpy(reply, "LOAD_STATE_SLOT ", sizeof(reply)); _len += snprintf(reply + _len, sizeof(reply) - _len, "%d", slot); if (savestates_enabled) @@ -943,7 +989,7 @@ bool command_get_status(command_t *cmd, const char* arg) _len += strlcpy(reply + _len, path_basename(path_get(RARCH_PATH_BASENAME)), sizeof(reply) - _len); _len += snprintf(reply + _len, sizeof(reply) - _len, - ",crc32=%x\n", content_get_crc()); + ",crc32=%lx\n", (unsigned long)content_get_crc()); } else _len = strlcpy(reply, "GET_STATUS CONTENTLESS", sizeof(reply)); @@ -1166,8 +1212,8 @@ void command_event_init_controllers(rarch_system_info_t *sys_info, } #ifdef HAVE_CONFIGFILE -static size_t command_event_save_config( - const char *config_path, char *s, size_t len) +static size_t command_event_save_config(const char *config_path, + char *s, size_t len) { size_t _len = 0; bool path_exists = !string_is_empty(config_path); @@ -1239,8 +1285,8 @@ static size_t command_event_undo_load_state(char *s, size_t len) bool command_event_resize_windowed_scale(settings_t *settings, unsigned window_scale) { - unsigned idx = 0; - bool video_fullscreen = settings->bools.video_fullscreen; + unsigned idx = 0; + bool video_fullscreen = settings->bools.video_fullscreen; if (window_scale == 0) return false; @@ -1255,35 +1301,31 @@ bool command_event_resize_windowed_scale(settings_t *settings, return true; } -bool command_event_save_auto_state(void) +size_t command_event_save_auto_state(void) { size_t _len; runloop_state_t *runloop_st = runloop_state_get_ptr(); + const char *name_savestate = runloop_st->name.savestate; char savestate_name_auto[PATH_MAX_LENGTH]; - - if (runloop_st->entry_state_slot) - return false; + if (runloop_st->entry_state_slot > -1) + return 0; if (!core_info_current_supports_savestate()) - return false; + return 0; if (string_is_empty(path_basename(path_get(RARCH_PATH_BASENAME)))) - return false; - - _len = strlcpy(savestate_name_auto, - runloop_st->name.savestate, + return 0; + _len = strlcpy(savestate_name_auto, name_savestate, sizeof(savestate_name_auto)); - strlcpy(savestate_name_auto + _len, ".auto", - sizeof(savestate_name_auto) - _len); - + _len += strlcpy(savestate_name_auto + _len, ".auto", + sizeof(savestate_name_auto) - _len); if (content_auto_save_state((const char*)savestate_name_auto)) - RARCH_LOG("%s \"%s\" %s.\n", + RARCH_LOG("[State]: %s \"%s\" %s.\n", msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO), savestate_name_auto, "succeeded"); else - RARCH_LOG("%s \"%s\" %s.\n", + RARCH_LOG("[State]: %s \"%s\" %s.\n", msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO), savestate_name_auto, "failed"); - - return true; + return _len; } #ifdef HAVE_CHEATS @@ -1309,13 +1351,14 @@ void command_event_init_cheats( cheat_manager_load_game_specific_cheats(path_cheat_db); if (apply_cheats_after_load) - cheat_manager_apply_cheats(); + cheat_manager_apply_cheats( + config_get_ptr()->bools.notification_show_cheats_applied); } #endif bool command_event_load_entry_state(settings_t *settings) { - char entry_state_path[PATH_MAX_LENGTH]; + char entry_state_path[PATH_MAX_LENGTH] = ""; int entry_path_stats; runloop_state_t *runloop_st = runloop_state_get_ptr(); bool ret = false; @@ -1332,12 +1375,18 @@ bool command_event_load_entry_state(settings_t *settings) return false; #endif - entry_state_path[0] = '\0'; - if (!runloop_get_entry_state_path( + entry_state_path, sizeof(entry_state_path), + runloop_st->entry_state_slot)) + return false; + + if (!path_is_valid(entry_state_path)) + { + if (!runloop_get_savestate_path( entry_state_path, sizeof(entry_state_path), runloop_st->entry_state_slot)) - return false; + return false; + } entry_path_stats = path_stat(entry_state_path); @@ -1366,6 +1415,7 @@ void command_event_load_auto_state(void) size_t _len; char savestate_name_auto[PATH_MAX_LENGTH]; runloop_state_t *runloop_st = runloop_state_get_ptr(); + const char *name_savestate = runloop_st->name.savestate; if (!core_info_current_supports_savestate()) return; @@ -1379,8 +1429,7 @@ void command_event_load_auto_state(void) return; #endif - _len = strlcpy(savestate_name_auto, - runloop_st->name.savestate, + _len = strlcpy(savestate_name_auto, name_savestate, sizeof(savestate_name_auto)); strlcpy(savestate_name_auto + _len, ".auto", sizeof(savestate_name_auto) - _len); @@ -1411,7 +1460,10 @@ void command_event_load_auto_state(void) * @param last_index Return value for load slot. * @param @s Return value for file name that should be removed. */ -static void scan_states(settings_t *settings, +static void command_scan_states( + bool show_hidden_files, + unsigned savestate_max_keep, + int curr_state_slot, unsigned *last_index, char *s) { /* Base name of 128 may be too short for some (<<1%) of the @@ -1420,9 +1472,7 @@ static void scan_states(settings_t *settings, char state_base[128]; char state_dir[DIR_MAX_LENGTH]; runloop_state_t *runloop_st = runloop_state_get_ptr(); - bool show_hidden_files = settings->bools.show_hidden_files; - unsigned savestate_max_keep = settings->uints.savestate_max_keep; - int curr_state_slot = settings->ints.state_slot; + const char *name_savestate = runloop_st->name.savestate; unsigned max_idx = 0; unsigned loa_idx = 0; @@ -1438,15 +1488,14 @@ static void scan_states(settings_t *settings, size_t i, cnt = 0; size_t cnt_in_range = 0; - fill_pathname_basedir(state_dir, runloop_st->name.savestate, + fill_pathname_basedir(state_dir, name_savestate, sizeof(state_dir)); if (!(dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL, show_hidden_files))) return; - fill_pathname_base(state_base, runloop_st->name.savestate, - sizeof(state_base)); + fill_pathname_base(state_base, name_savestate, sizeof(state_base)); for (i = 0; i < dir_list->size; i++) { @@ -1460,7 +1509,8 @@ static void scan_states(settings_t *settings, if (string_is_empty(dir_elem)) continue; - _len = fill_pathname_base(elem_base, dir_elem, sizeof(elem_base)); + _len = strlen(dir_elem); + fill_pathname_base(elem_base, dir_elem, sizeof(elem_base)); /* Only consider files with a '.state' extension * > i.e. Ignore '.state.auto', '.state.bak', etc. */ @@ -1581,8 +1631,8 @@ static void scan_states(settings_t *settings, loa_idx = gap_idx - 1; } - RARCH_DBG("[State]: savestate scanning finished, used slots (in range): " - "%d (%d), max:%d, load index %d, gap index %d, delete index %d\n", + RARCH_DBG("[State]: Save state scanning finished, used slots (in range): " + "%d (%d), max:%d, load index %d, gap index %d, delete index %d.\n", cnt, cnt_in_range, max_idx, loa_idx, gap_idx, del_idx); if (last_index) @@ -1632,10 +1682,17 @@ void command_event_set_savestate_auto_index(settings_t *settings) unsigned max_idx = 0; bool savestate_auto_index = settings->bools.savestate_auto_index; if (!savestate_auto_index) + { + /* Reset savestate index to 0 when loading content. */ + configuration_set_int(settings, settings->ints.state_slot, 0); return; - scan_states(settings, &max_idx, NULL); + } + command_scan_states( + settings->bools.show_hidden_files, + settings->uints.savestate_max_keep, + settings->ints.state_slot, &max_idx, NULL); configuration_set_int(settings, settings->ints.state_slot, max_idx); - RARCH_LOG("[State]: %s: #%d\n", + RARCH_LOG("[State]: %s: #%d.\n", msg_hash_to_str(MSG_FOUND_LAST_STATE_SLOT), max_idx); } @@ -1649,7 +1706,10 @@ static void command_event_set_savestate_garbage_collect(settings_t *settings) { size_t i; char state_to_delete[PATH_MAX_LENGTH] = {0}; - scan_states(settings, NULL, state_to_delete); + command_scan_states( + settings->bools.show_hidden_files, + settings->uints.savestate_max_keep, + settings->ints.state_slot, NULL, state_to_delete); /* Only delete one save state per save action * > Conservative behaviour, designed to minimise * the risk of deleting multiple incorrect files @@ -1657,50 +1717,50 @@ static void command_event_set_savestate_garbage_collect(settings_t *settings) if (!string_is_empty(state_to_delete)) { filestream_delete(state_to_delete); - RARCH_DBG("[State]: garbage collect, deleting \"%s\" \n",state_to_delete); + RARCH_DBG("[State]: Garbage collect, deleting \"%s\".\n",state_to_delete); /* Construct the save state thumbnail name * and delete that one as well. */ i = strlen(state_to_delete); strlcpy(state_to_delete + i,".png",STRLEN_CONST(".png")+1); filestream_delete(state_to_delete); - RARCH_DBG("[State]: garbage collect, deleting \"%s\" \n",state_to_delete); + RARCH_DBG("[State]: Garbage collect, deleting \"%s\".\n",state_to_delete); } } void command_event_set_replay_auto_index(settings_t *settings) { size_t i; + char elem_base[128]; char state_base[128]; char state_dir[DIR_MAX_LENGTH]; struct string_list *dir_list = NULL; unsigned max_idx = 0; runloop_state_t *runloop_st = runloop_state_get_ptr(); + const char *name_replay = runloop_st->name.replay; bool replay_auto_index = settings->bools.replay_auto_index; bool show_hidden_files = settings->bools.show_hidden_files; if (!replay_auto_index) return; - /* Find the file in the same directory as runloop_st->names.replay + /* Find the file in the same directory as runloop_st->name.replay * with the largest numeral suffix. * * E.g. /foo/path/content.replay will try to find * /foo/path/content.replay%d, where %d is the largest number available. */ - fill_pathname_basedir(state_dir, runloop_st->name.replay, + fill_pathname_basedir(state_dir, name_replay, sizeof(state_dir)); if (!(dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL, show_hidden_files))) return; - fill_pathname_base(state_base, runloop_st->name.replay, - sizeof(state_base)); + fill_pathname_base(state_base, name_replay, sizeof(state_base)); for (i = 0; i < dir_list->size; i++) { unsigned idx; - char elem_base[128] = {0}; const char *end = NULL; const char *dir_elem = dir_list->elems[i].data; size_t _len = fill_pathname_base(elem_base, dir_elem, sizeof(elem_base)); @@ -1735,25 +1795,22 @@ void command_event_set_replay_garbage_collect( { /* TODO: debugme */ size_t i, cnt = 0; - char state_base[128]; - char state_dir[DIR_MAX_LENGTH]; + char tmp[DIR_MAX_LENGTH]; runloop_state_t *runloop_st = runloop_state_get_ptr(); - + const char *name_replay = runloop_st->name.replay; struct string_list *dir_list = NULL; unsigned min_idx = UINT_MAX; const char *oldest_save = NULL; /* Similar to command_event_set_replay_auto_index(), * this will find the lowest numbered replay */ - fill_pathname_basedir(state_dir, runloop_st->name.replay, - sizeof(state_dir)); + fill_pathname_basedir(tmp, name_replay, sizeof(tmp)); - if (!(dir_list = dir_list_new_special(state_dir, + if (!(dir_list = dir_list_new_special(tmp, DIR_LIST_PLAIN, NULL, show_hidden_files))) return; - fill_pathname_base(state_base, runloop_st->name.replay, - sizeof(state_base)); + fill_pathname_base(tmp, name_replay, sizeof(tmp)); for (i = 0; i < dir_list->size; i++) { @@ -1778,7 +1835,7 @@ void command_event_set_replay_garbage_collect( /* Check whether this file is associated with * the current content */ - if (!string_starts_with(elem_base, state_base)) + if (!string_starts_with(elem_base, tmp)) continue; /* This looks like a valid save */ @@ -1961,17 +2018,11 @@ void command_event_save_current_config(enum override_type type) else { if (runloop_st->flags & RUNLOOP_FLAG_OVERRIDES_ACTIVE) - { _len = strlcpy(msg, msg_hash_to_str(MSG_OVERRIDES_ACTIVE_NOT_SAVING), sizeof(msg)); - runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, - MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - } else - { _len = command_event_save_config(path_get(RARCH_PATH_CONFIG), msg, sizeof(msg)); - runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, - MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - } + runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } break; @@ -2055,15 +2106,13 @@ void command_event_remove_current_config(enum override_type type) bool command_event_main_state(unsigned cmd) { - char msg[128]; - char state_path[16384]; + char msg[128] = ""; + char state_path[PATH_MAX_LENGTH] = ""; size_t _len = 0; settings_t *settings = config_get_ptr(); bool savestates_enabled = core_info_current_supports_savestate(); bool ret = false; - state_path[0] = msg[0] = '\0'; - if (savestates_enabled) { size_t info_size; @@ -2076,8 +2125,13 @@ bool command_event_main_state(unsigned cmd) /* TODO: Load state should act in one of three ways: - [X] Not during recording or playback: normally - - [-] During playback: If the state is part of this replay, go back to that state and rewind the replay (not yet implemented); otherwise halt playback and go to that state normally. - - [-] During recording: If the state is part of this replay, go back to that state and rewind the replay, clobbering the stuff in between then and now (not yet implemented); if the state is not part of the replay, do nothing and log a warning. + - [-] During playback: If the state is part of this replay, go back to + that state and rewind the replay (not yet implemented); otherwise + halt playback and go to that state normally. + - [-] During recording: If the state is part of this replay, go back to + that state and rewind the replay, clobbering the stuff in between + then and now (not yet implemented); if the state is not part of + the replay, do nothing and log a warning. */ @@ -2088,7 +2142,8 @@ bool command_event_main_state(unsigned cmd) case CMD_EVENT_SAVE_STATE: case CMD_EVENT_SAVE_STATE_TO_RAM: { - /* TODO: Saving state during recording should associate the state with the replay. */ + /* TODO: Saving state during recording should associate + * the state with the replay. */ video_driver_state_t *video_st = video_state_get_ptr(); bool savestate_auto_index = @@ -2131,17 +2186,21 @@ bool command_event_main_state(unsigned cmd) break; case CMD_EVENT_UNDO_LOAD_STATE: { - /* TODO: To support this through re-recording would take some care around moving the replay recording forward to the time when the undo happened, which would need undo support for replays. For now, forbid it during recording and halt playback. */ + /* TODO: To support this through re-recording would take some + * care around moving the replay recording forward to the time + * when the undo happened, which would need undo support for + * replays. For now, forbid it during recording and halt + * playback. */ #ifdef HAVE_BSV_MOVIE input_driver_state_t *input_st = input_state_get_ptr(); if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_RECORDING) { - RARCH_ERR("[Load] [Movie] Can't undo load state during movie record\n"); + RARCH_ERR("[State]: Can't undo load state during movie record.\n"); return false; } if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_PLAYBACK) { - RARCH_LOG("[Load] [Movie] Undo load state during movie playback, halting playback\n"); + RARCH_LOG("[State]: Undo load state during movie playback, halting playback.\n"); movie_stop(input_st); } #endif @@ -2174,8 +2233,8 @@ bool command_event_disk_control_append_image( { runloop_state_t *runloop_st = runloop_state_get_ptr(); rarch_system_info_t *sys_info = runloop_st ? (rarch_system_info_t*)&runloop_st->system : NULL; - if ( !sys_info || - !disk_control_append_image(&sys_info->disk_control, path)) + if ( !sys_info + || !disk_control_append_image(&sys_info->disk_control, path)) return false; #ifdef HAVE_THREADS @@ -2225,12 +2284,11 @@ void command_event_reinit(const int flags) video_driver_reinit(flags); /* Poll input to avoid possibly stale data to corrupt things. */ - if ( joypad && joypad->poll) + if (joypad && joypad->poll) joypad->poll(); - if ( sec_joypad && sec_joypad->poll) + if (sec_joypad && sec_joypad->poll) sec_joypad->poll(); - if ( input_st->current_driver && - input_st->current_driver->poll) + if (input_st->current_driver && input_st->current_driver->poll) input_st->current_driver->poll(input_st->current_data); command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd); diff --git a/command.h b/command.h index 5beb361cc5..dd08854284 100644 --- a/command.h +++ b/command.h @@ -41,6 +41,7 @@ RETRO_BEGIN_DECLS enum event_command { + CMD_SPECIAL = -1, CMD_EVENT_NONE = 0, /* Resets RetroArch. */ CMD_EVENT_RESET, @@ -228,6 +229,8 @@ enum event_command CMD_EVENT_DISK_APPEND_IMAGE, /* Stops rumbling. */ CMD_EVENT_RUMBLE_STOP, + /* Toggles turbo fire. */ + CMD_EVENT_TURBO_FIRE_TOGGLE, /* Toggles mouse grab. */ CMD_EVENT_GRAB_MOUSE_TOGGLE, /* Toggles game focus. */ @@ -260,6 +263,7 @@ enum event_command CMD_EVENT_PRESENCE_UPDATE, CMD_EVENT_OVERLAY_NEXT, CMD_EVENT_OSK_TOGGLE, + CMD_EVENT_RELOAD_CONFIG, #ifdef HAVE_MICROPHONE /* Stops all enabled microphones. */ CMD_EVENT_MICROPHONE_STOP, @@ -328,11 +332,20 @@ struct rarch_state; bool command_event(enum event_command action, void *data); /* Constructors for the supported drivers */ +#ifdef HAVE_NETWORK_CMD command_t* command_network_new(uint16_t port); -command_t* command_stdin_new(void); -command_t* command_uds_new(void); - bool command_network_send(const char *cmd_); +#endif +#ifdef HAVE_STDIN_CMD +command_t* command_stdin_new(void); +#endif +#ifdef LAKKA +command_t* command_uds_new(void); +#endif +#ifdef EMSCRIPTEN +command_t* command_emscripten_new(void); +#endif + void command_event_set_mixer_volume( settings_t *settings, @@ -341,7 +354,7 @@ void command_event_set_mixer_volume( bool command_event_resize_windowed_scale(settings_t *settings, unsigned window_scale); -bool command_event_save_auto_state(void); +size_t command_event_save_auto_state(void); /** * event_set_volume: @@ -480,6 +493,7 @@ static const struct cmd_map map[] = { { "RECORDING_TOGGLE", RARCH_RECORDING_TOGGLE }, { "STREAMING_TOGGLE", RARCH_STREAMING_TOGGLE }, + { "TURBO_FIRE_TOGGLE", RARCH_TURBO_FIRE_TOGGLE }, { "GRAB_MOUSE_TOGGLE", RARCH_GRAB_MOUSE_TOGGLE }, { "GAME_FOCUS_TOGGLE", RARCH_GAME_FOCUS_TOGGLE }, { "FULLSCREEN_TOGGLE", RARCH_FULLSCREEN_TOGGLE_KEY }, diff --git a/config.def.h b/config.def.h index 602db4dd52..b88c618b29 100644 --- a/config.def.h +++ b/config.def.h @@ -764,6 +764,9 @@ #define DEFAULT_MENU_TICKER_SPEED 2.0f #define DEFAULT_MENU_TICKER_SMOOTH true +/* Don't skip rendering assets based on the absence of other assets */ +#define DEFAULT_MENU_IGNORE_MISSING_ASSETS false + #if defined(HAVE_THREADS) #define DEFAULT_MENU_SAVESTATE_RESUME true #else @@ -805,14 +808,10 @@ #endif #endif -/* Specifies 'add content' visibility when using - * menus WITH a dedicated 'Import Content' tab */ -#define DEFAULT_MENU_CONTENT_SHOW_ADD true -/* Specifies 'add content' visibility when using - * menus WITHOUT a dedicated 'Import Content' tab */ -#define DEFAULT_MENU_CONTENT_SHOW_ADD_ENTRY MENU_ADD_CONTENT_ENTRY_DISPLAY_PLAYLISTS_TAB +#define DEFAULT_MENU_CONTENT_SHOW_ADD_ENTRY MENU_ADD_CONTENT_ENTRY_DISPLAY_MAIN_TAB #define DEFAULT_CONTENT_SHOW_PLAYLISTS true +#define DEFAULT_CONTENT_SHOW_PLAYLIST_TABS true #if defined(HAVE_LIBRETRODB) #define DEFAULT_MENU_CONTENT_SHOW_EXPLORE true @@ -927,7 +926,11 @@ #define DEFAULT_INPUT_BACKTOUCH_TOGGLE false #endif +#if defined(ANDROID) || defined(IOS) #define DEFAULT_OVERLAY_ENABLE_AUTOPREFERRED true +#else +#define DEFAULT_OVERLAY_ENABLE_AUTOPREFERRED false +#endif #if defined(HAVE_OVERLAY) #if defined(RARCH_MOBILE) @@ -1089,6 +1092,10 @@ #define DEFAULT_NOTIFICATION_SHOW_AUTOCONFIG true #endif +/* Display a notification when controller + * autoconfiguration fails. */ +#define DEFAULT_NOTIFICATION_SHOW_AUTOCONFIG_FAILS true + /* Display a notification when cheats are being * applied */ #define DEFAULT_NOTIFICATION_SHOW_CHEATS_APPLIED true @@ -1169,7 +1176,7 @@ /* Desired audio latency in milliseconds. Might not be honored * if driver can't provide given latency. */ -#if defined(ANDROID) || defined(EMSCRIPTEN) || defined(RETROFW) || defined(MIYOO) +#if defined(ANDROID) || defined(RETROFW) || defined(MIYOO) || (defined(EMSCRIPTEN) && !defined(HAVE_AUDIOWORKLET)) /* For most Android devices, 64ms is way too low. */ #define DEFAULT_OUT_LATENCY 128 #define DEFAULT_IN_LATENCY 128 @@ -1215,12 +1222,12 @@ #define DEFAULT_AUDIO_RESPECT_SILENT_MODE true #endif -/* Automatically mute audio when fast forward - * is enabled */ +/* Automatically mute audio when fast forward is enabled. */ #define DEFAULT_AUDIO_FASTFORWARD_MUTE false -/* Speed up audio to match fast-forward speed up. - * Avoids crackling */ +/* Speed up audio to match fast forward speed up. */ #define DEFAULT_AUDIO_FASTFORWARD_SPEEDUP false +/* Automatically mute audio when rewind is enabled. */ +#define DEFAULT_AUDIO_REWIND_MUTE false #ifdef HAVE_MICROPHONE /* Microphone support */ @@ -1562,11 +1569,13 @@ #define DEFAULT_ANALOG_SENSITIVITY 1.0f /* Describes speed of which turbo-enabled buttons toggle. */ +#define DEFAULT_TURBO_ENABLE true #define DEFAULT_TURBO_PERIOD 6 -#define DEFAULT_TURBO_DUTY_CYCLE 3 +#define DEFAULT_TURBO_DUTY_CYCLE 0 #define DEFAULT_TURBO_MODE 0 -#define DEFAULT_TURBO_DEFAULT_BTN RETRO_DEVICE_ID_JOYPAD_B -#define DEFAULT_ALLOW_TURBO_DPAD false +#define DEFAULT_TURBO_BIND -1 +#define DEFAULT_TURBO_BUTTON RETRO_DEVICE_ID_JOYPAD_B +#define DEFAULT_TURBO_ALLOW_DPAD false /* Enable automatic mouse grab by default * only on Android */ @@ -1612,7 +1621,11 @@ #endif #define DEFAULT_INPUT_BIND_TIMEOUT 3 +#if defined(ANDROID) +#define DEFAULT_INPUT_BIND_HOLD 1 +#else #define DEFAULT_INPUT_BIND_HOLD 0 +#endif #define DEFAULT_INPUT_POLL_TYPE_BEHAVIOR 2 #define DEFAULT_INPUT_HOTKEY_BLOCK_DELAY 5 #define DEFAULT_INPUT_HOTKEY_DEVICE_MERGE false @@ -1832,7 +1845,11 @@ #define DEFAULT_BUILDBOT_SERVER_URL "" #endif +#ifdef EMSCRIPTEN +#define DEFAULT_BUILDBOT_ASSETS_SERVER_URL "https://buildbot.libretro.com/assets/" +#else #define DEFAULT_BUILDBOT_ASSETS_SERVER_URL "http://buildbot.libretro.com/assets/" +#endif #define DEFAULT_DISCORD_APP_ID "475456035851599874" diff --git a/config.def.keybinds.h b/config.def.keybinds.h index d86c8b6413..f4d6a6bb28 100644 --- a/config.def.keybinds.h +++ b/config.def.keybinds.h @@ -25,624 +25,631 @@ static const struct retro_keybind retro_keybinds_1[] = { #ifdef __QNX__ { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, RETROK_k, RETRO_DEVICE_ID_JOYPAD_B, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, RETROK_i, RETRO_DEVICE_ID_JOYPAD_Y, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, RETROK_v, RETRO_DEVICE_ID_JOYPAD_SELECT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, RETROK_b, RETRO_DEVICE_ID_JOYPAD_START, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, RETROK_e, RETRO_DEVICE_ID_JOYPAD_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, RETROK_s, RETRO_DEVICE_ID_JOYPAD_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, RETROK_w, RETRO_DEVICE_ID_JOYPAD_LEFT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, RETROK_d, RETRO_DEVICE_ID_JOYPAD_RIGHT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, RETROK_l, RETRO_DEVICE_ID_JOYPAD_A, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, RETROK_o, RETRO_DEVICE_ID_JOYPAD_X, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, RETROK_f, RETRO_DEVICE_ID_JOYPAD_L, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, RETROK_j, RETRO_DEVICE_ID_JOYPAD_R, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, RETROK_r, RETRO_DEVICE_ID_JOYPAD_L2, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, RETROK_u, RETRO_DEVICE_ID_JOYPAD_R2, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, RETROK_g, RETRO_DEVICE_ID_JOYPAD_L3, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, RETROK_h, RETRO_DEVICE_ID_JOYPAD_R3, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_X_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_X_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_Y_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_Y_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_X_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_X_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_Y_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_Y_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, RETROK_UNKNOWN, RARCH_LIGHTGUN_TRIGGER, RETRO_DEVICE_ID_MOUSE_LEFT, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, RETROK_UNKNOWN, RARCH_LIGHTGUN_RELOAD, RETRO_DEVICE_ID_MOUSE_RIGHT, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_A, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_B, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_C, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, RETROK_UNKNOWN, RARCH_LIGHTGUN_START, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, RETROK_UNKNOWN, RARCH_LIGHTGUN_SELECT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_LEFT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_RIGHT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, RETROK_UNKNOWN, + AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, RETROK_UNKNOWN, RARCH_TURBO_ENABLE, NO_BTN, NO_BTN, 0, true }, /* Hotkeys */ { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, RETROK_UNKNOWN, RARCH_ENABLE_HOTKEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, RETROK_SPACE, RARCH_MENU_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, RETROK_UNKNOWN, RARCH_QUIT_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CLOSE_CONTENT_KEY, RETROK_UNKNOWN, RARCH_CLOSE_CONTENT_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, RETROK_UNKNOWN, RARCH_RESET, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, RETROK_UNKNOWN, RARCH_FAST_FORWARD_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, RETROK_UNKNOWN, RARCH_FAST_FORWARD_HOLD_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY, RETROK_UNKNOWN, RARCH_SLOWMOTION_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY, RETROK_UNKNOWN, RARCH_SLOWMOTION_HOLD_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, RETROK_UNKNOWN, RARCH_REWIND, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, RETROK_UNKNOWN, RARCH_PAUSE_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, RETROK_UNKNOWN, RARCH_FRAMEADVANCE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, RETROK_UNKNOWN, RARCH_MUTE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, RETROK_UNKNOWN, RARCH_VOLUME_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, RETROK_UNKNOWN, RARCH_VOLUME_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, RETROK_UNKNOWN, RARCH_LOAD_STATE_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, RETROK_UNKNOWN, RARCH_SAVE_STATE_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, RETROK_UNKNOWN, RARCH_STATE_SLOT_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, RETROK_UNKNOWN, RARCH_STATE_SLOT_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, RETROK_UNKNOWN, RARCH_PLAY_REPLAY_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, RETROK_UNKNOWN, RARCH_RECORD_REPLAY_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, RETROK_UNKNOWN, RARCH_HALT_REPLAY_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, RETROK_UNKNOWN, RARCH_REPLAY_SLOT_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, RETROK_UNKNOWN, RARCH_REPLAY_SLOT_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, RETROK_UNKNOWN, RARCH_DISK_EJECT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, RETROK_UNKNOWN, RARCH_DISK_NEXT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, RETROK_UNKNOWN, RARCH_DISK_PREV, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_TOGGLE, RETROK_UNKNOWN, RARCH_SHADER_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, RETROK_UNKNOWN, RARCH_SHADER_NEXT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, RETROK_UNKNOWN, RARCH_SHADER_PREV, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, RETROK_UNKNOWN, RARCH_CHEAT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, RETROK_UNKNOWN, RARCH_CHEAT_INDEX_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, RETROK_UNKNOWN, RARCH_CHEAT_INDEX_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, RETROK_UNKNOWN, RARCH_SCREENSHOT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE, RETROK_UNKNOWN, RARCH_RECORDING_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE, RETROK_UNKNOWN, RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, RETROK_UNKNOWN, + RARCH_TURBO_FIRE_TOGGLE, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, RETROK_UNKNOWN, RARCH_GRAB_MOUSE_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, RETROK_UNKNOWN, RARCH_GAME_FOCUS_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, RETROK_UNKNOWN, RARCH_FULLSCREEN_TOGGLE_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, RETROK_UNKNOWN, RARCH_UI_COMPANION_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE, RETROK_UNKNOWN, RARCH_VRR_RUNLOOP_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE, RETROK_UNKNOWN, RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE, RETROK_UNKNOWN, RARCH_PREEMPT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE, RETROK_UNKNOWN, RARCH_FPS_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATISTICS_TOGGLE, RETROK_UNKNOWN, RARCH_STATISTICS_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE, RETROK_UNKNOWN, RARCH_AI_SERVICE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_PING_TOGGLE, RETROK_UNKNOWN, RARCH_NETPLAY_PING_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_HOST_TOGGLE, RETROK_UNKNOWN, RARCH_NETPLAY_HOST_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, RETROK_UNKNOWN, RARCH_NETPLAY_GAME_WATCH, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_PLAYER_CHAT, RETROK_UNKNOWN, RARCH_NETPLAY_PLAYER_CHAT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FADE_CHAT_TOGGLE, RETROK_UNKNOWN, RARCH_NETPLAY_FADE_CHAT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, RETROK_UNKNOWN, RARCH_OVERLAY_NEXT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, RETROK_UNKNOWN, RARCH_OSK, NO_BTN, NO_BTN, 0, true @@ -651,7 +658,7 @@ static const struct retro_keybind retro_keybinds_1[] = { /* Deprecated */ { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SEND_DEBUG_INFO, RETROK_UNKNOWN, RARCH_SEND_DEBUG_INFO, NO_BTN, NO_BTN, 0, true @@ -660,624 +667,631 @@ static const struct retro_keybind retro_keybinds_1[] = { #elif defined(DINGUX) { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, RETROK_LALT, RETRO_DEVICE_ID_JOYPAD_B, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, RETROK_LSHIFT, RETRO_DEVICE_ID_JOYPAD_Y, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, RETROK_ESCAPE, RETRO_DEVICE_ID_JOYPAD_SELECT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, RETROK_RETURN, RETRO_DEVICE_ID_JOYPAD_START, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, RETROK_UP, RETRO_DEVICE_ID_JOYPAD_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, RETROK_DOWN, RETRO_DEVICE_ID_JOYPAD_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, RETROK_LEFT, RETRO_DEVICE_ID_JOYPAD_LEFT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, RETROK_RIGHT, RETRO_DEVICE_ID_JOYPAD_RIGHT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, RETROK_LCTRL, RETRO_DEVICE_ID_JOYPAD_A, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, RETROK_SPACE, RETRO_DEVICE_ID_JOYPAD_X, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, RETROK_TAB, RETRO_DEVICE_ID_JOYPAD_L, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, RETROK_BACKSPACE, RETRO_DEVICE_ID_JOYPAD_R, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, RETROK_PAGEUP, RETRO_DEVICE_ID_JOYPAD_L2, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, RETROK_PAGEDOWN, RETRO_DEVICE_ID_JOYPAD_R2, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, RETROK_KP_DIVIDE, RETRO_DEVICE_ID_JOYPAD_L3, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, RETROK_KP_PERIOD, RETRO_DEVICE_ID_JOYPAD_R3, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_X_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_X_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_Y_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_Y_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_X_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_X_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_Y_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_Y_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, RETROK_UNKNOWN, RARCH_LIGHTGUN_TRIGGER, RETRO_DEVICE_ID_MOUSE_LEFT, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, RETROK_UNKNOWN, RARCH_LIGHTGUN_RELOAD, RETRO_DEVICE_ID_MOUSE_RIGHT, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_A, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_B, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_C, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, RETROK_UNKNOWN, RARCH_LIGHTGUN_START, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, RETROK_UNKNOWN, RARCH_LIGHTGUN_SELECT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_LEFT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_RIGHT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, RETROK_UNKNOWN, + AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, RETROK_UNKNOWN, RARCH_TURBO_ENABLE, NO_BTN, NO_BTN, 0, true }, /* Hotkeys */ { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, RETROK_UNKNOWN, RARCH_ENABLE_HOTKEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, RETROK_HOME, RARCH_MENU_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, RETROK_UNKNOWN, RARCH_QUIT_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CLOSE_CONTENT_KEY, RETROK_UNKNOWN, RARCH_CLOSE_CONTENT_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, RETROK_UNKNOWN, RARCH_RESET, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, RETROK_UNKNOWN, RARCH_FAST_FORWARD_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, RETROK_UNKNOWN, RARCH_FAST_FORWARD_HOLD_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY, RETROK_UNKNOWN, RARCH_SLOWMOTION_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY, RETROK_UNKNOWN, RARCH_SLOWMOTION_HOLD_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, RETROK_UNKNOWN, RARCH_REWIND, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, RETROK_UNKNOWN, RARCH_PAUSE_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, RETROK_UNKNOWN, RARCH_FRAMEADVANCE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, RETROK_UNKNOWN, RARCH_MUTE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, RETROK_UNKNOWN, RARCH_VOLUME_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, RETROK_UNKNOWN, RARCH_VOLUME_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, RETROK_UNKNOWN, RARCH_LOAD_STATE_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, RETROK_UNKNOWN, RARCH_SAVE_STATE_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, RETROK_UNKNOWN, RARCH_STATE_SLOT_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, RETROK_UNKNOWN, RARCH_STATE_SLOT_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, RETROK_UNKNOWN, RARCH_PLAY_REPLAY_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, RETROK_UNKNOWN, RARCH_RECORD_REPLAY_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, RETROK_UNKNOWN, RARCH_HALT_REPLAY_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, RETROK_UNKNOWN, RARCH_REPLAY_SLOT_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, RETROK_UNKNOWN, RARCH_REPLAY_SLOT_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, RETROK_UNKNOWN, RARCH_DISK_EJECT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, RETROK_UNKNOWN, RARCH_DISK_NEXT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, RETROK_UNKNOWN, RARCH_DISK_PREV, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_TOGGLE, RETROK_UNKNOWN, RARCH_SHADER_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, RETROK_UNKNOWN, RARCH_SHADER_NEXT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, RETROK_UNKNOWN, RARCH_SHADER_PREV, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, RETROK_UNKNOWN, RARCH_CHEAT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, RETROK_UNKNOWN, RARCH_CHEAT_INDEX_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, RETROK_UNKNOWN, RARCH_CHEAT_INDEX_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, RETROK_UNKNOWN, RARCH_SCREENSHOT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE, RETROK_UNKNOWN, RARCH_RECORDING_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE, RETROK_UNKNOWN, RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, RETROK_UNKNOWN, + RARCH_TURBO_FIRE_TOGGLE, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, RETROK_UNKNOWN, RARCH_GRAB_MOUSE_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, RETROK_UNKNOWN, RARCH_GAME_FOCUS_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, RETROK_UNKNOWN, RARCH_FULLSCREEN_TOGGLE_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, RETROK_UNKNOWN, RARCH_UI_COMPANION_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE, RETROK_UNKNOWN, RARCH_VRR_RUNLOOP_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE, RETROK_UNKNOWN, RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE, RETROK_UNKNOWN, RARCH_PREEMPT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE, RETROK_UNKNOWN, RARCH_FPS_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATISTICS_TOGGLE, RETROK_UNKNOWN, RARCH_STATISTICS_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE, RETROK_UNKNOWN, RARCH_AI_SERVICE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_PING_TOGGLE, RETROK_UNKNOWN, RARCH_NETPLAY_PING_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_HOST_TOGGLE, RETROK_UNKNOWN, RARCH_NETPLAY_HOST_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, RETROK_UNKNOWN, RARCH_NETPLAY_GAME_WATCH, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_PLAYER_CHAT, RETROK_UNKNOWN, RARCH_NETPLAY_PLAYER_CHAT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FADE_CHAT_TOGGLE, RETROK_UNKNOWN, RARCH_NETPLAY_FADE_CHAT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, RETROK_UNKNOWN, RARCH_OVERLAY_NEXT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, RETROK_UNKNOWN, RARCH_OSK, NO_BTN, NO_BTN, 0, true @@ -1286,7 +1300,7 @@ static const struct retro_keybind retro_keybinds_1[] = { /* Deprecated */ { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SEND_DEBUG_INFO, RETROK_UNKNOWN, RARCH_SEND_DEBUG_INFO, NO_BTN, NO_BTN, 0, true @@ -1295,267 +1309,267 @@ static const struct retro_keybind retro_keybinds_1[] = { #else { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, RETROK_z, RETRO_DEVICE_ID_JOYPAD_B, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, RETROK_a, RETRO_DEVICE_ID_JOYPAD_Y, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, RETROK_RSHIFT, RETRO_DEVICE_ID_JOYPAD_SELECT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, RETROK_RETURN, RETRO_DEVICE_ID_JOYPAD_START, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, RETROK_UP, RETRO_DEVICE_ID_JOYPAD_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, RETROK_DOWN, RETRO_DEVICE_ID_JOYPAD_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, RETROK_LEFT, RETRO_DEVICE_ID_JOYPAD_LEFT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, RETROK_RIGHT, RETRO_DEVICE_ID_JOYPAD_RIGHT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, RETROK_x, RETRO_DEVICE_ID_JOYPAD_A, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, RETROK_s, RETRO_DEVICE_ID_JOYPAD_X, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, RETROK_q, RETRO_DEVICE_ID_JOYPAD_L, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, RETROK_w, RETRO_DEVICE_ID_JOYPAD_R, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_L2, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_R2, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_L3, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_R3, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_X_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_X_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_Y_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_Y_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_X_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_X_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_Y_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_Y_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, RETROK_UNKNOWN, RARCH_LIGHTGUN_TRIGGER, RETRO_DEVICE_ID_MOUSE_LEFT, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, RETROK_UNKNOWN, RARCH_LIGHTGUN_RELOAD, RETRO_DEVICE_ID_MOUSE_RIGHT, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_A, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_B, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_C, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, RETROK_UNKNOWN, RARCH_LIGHTGUN_START, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, RETROK_UNKNOWN, RARCH_LIGHTGUN_SELECT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_LEFT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_RIGHT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, RETROK_UNKNOWN, + AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, RETROK_UNKNOWN, RARCH_TURBO_ENABLE, NO_BTN, NO_BTN, 0, true }, /* Hotkeys */ { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, RETROK_UNKNOWN, RARCH_ENABLE_HOTKEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, RETROK_F1, RARCH_MENU_TOGGLE, NO_BTN, NO_BTN, 0, true @@ -1563,7 +1577,7 @@ static const struct retro_keybind retro_keybinds_1[] = { #ifdef HAVE_LAKKA { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RESTART_KEY, RETROK_ESCAPE, RARCH_QUIT_KEY, NO_BTN, NO_BTN, 0, true @@ -1571,7 +1585,7 @@ static const struct retro_keybind retro_keybinds_1[] = { #else { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, RETROK_ESCAPE, RARCH_QUIT_KEY, NO_BTN, NO_BTN, 0, true @@ -1579,350 +1593,357 @@ static const struct retro_keybind retro_keybinds_1[] = { #endif { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CLOSE_CONTENT_KEY, RETROK_UNKNOWN, RARCH_CLOSE_CONTENT_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, RETROK_h, RARCH_RESET, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, RETROK_SPACE, RARCH_FAST_FORWARD_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, RETROK_l, RARCH_FAST_FORWARD_HOLD_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY, RETROK_UNKNOWN, RARCH_SLOWMOTION_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY, RETROK_e, RARCH_SLOWMOTION_HOLD_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, RETROK_r, RARCH_REWIND, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, RETROK_p, RARCH_PAUSE_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, RETROK_k, RARCH_FRAMEADVANCE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, RETROK_F9, RARCH_MUTE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, RETROK_KP_PLUS, RARCH_VOLUME_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, RETROK_KP_MINUS, RARCH_VOLUME_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, RETROK_F4, RARCH_LOAD_STATE_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, RETROK_F2, RARCH_SAVE_STATE_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, RETROK_F7, RARCH_STATE_SLOT_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, RETROK_F6, RARCH_STATE_SLOT_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, RETROK_UNKNOWN, RARCH_PLAY_REPLAY_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, RETROK_UNKNOWN, RARCH_RECORD_REPLAY_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, RETROK_UNKNOWN, RARCH_HALT_REPLAY_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, RETROK_UNKNOWN, RARCH_REPLAY_SLOT_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, RETROK_UNKNOWN, RARCH_REPLAY_SLOT_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, RETROK_UNKNOWN, RARCH_DISK_EJECT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, RETROK_UNKNOWN, RARCH_DISK_NEXT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, RETROK_UNKNOWN, RARCH_DISK_PREV, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_TOGGLE, RETROK_COMMA, RARCH_SHADER_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, RETROK_m, RARCH_SHADER_NEXT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, RETROK_n, RARCH_SHADER_PREV, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, RETROK_u, RARCH_CHEAT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, RETROK_y, RARCH_CHEAT_INDEX_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, RETROK_t, RARCH_CHEAT_INDEX_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, RETROK_F8, RARCH_SCREENSHOT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE, RETROK_UNKNOWN, RARCH_RECORDING_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE, RETROK_UNKNOWN, RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, RETROK_UNKNOWN, + RARCH_TURBO_FIRE_TOGGLE, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, RETROK_F11, RARCH_GRAB_MOUSE_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, RETROK_SCROLLOCK, RARCH_GAME_FOCUS_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, RETROK_f, RARCH_FULLSCREEN_TOGGLE_KEY, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, RETROK_F5, RARCH_UI_COMPANION_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE, RETROK_UNKNOWN, RARCH_VRR_RUNLOOP_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE, RETROK_UNKNOWN, RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE, RETROK_UNKNOWN, RARCH_PREEMPT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE, RETROK_F3, RARCH_FPS_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATISTICS_TOGGLE, RETROK_UNKNOWN, RARCH_STATISTICS_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE, RETROK_UNKNOWN, RARCH_AI_SERVICE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_PING_TOGGLE, RETROK_UNKNOWN, RARCH_NETPLAY_PING_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_HOST_TOGGLE, RETROK_UNKNOWN, RARCH_NETPLAY_HOST_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, RETROK_i, RARCH_NETPLAY_GAME_WATCH, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_PLAYER_CHAT, RETROK_BACKQUOTE, RARCH_NETPLAY_PLAYER_CHAT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FADE_CHAT_TOGGLE, RETROK_UNKNOWN, RARCH_NETPLAY_FADE_CHAT_TOGGLE, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, RETROK_UNKNOWN, RARCH_OVERLAY_NEXT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, RETROK_UNKNOWN, RARCH_OSK, NO_BTN, NO_BTN, 0, true @@ -1931,7 +1952,7 @@ static const struct retro_keybind retro_keybinds_1[] = { /* Deprecated */ { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_META_SEND_DEBUG_INFO, RETROK_UNKNOWN, RARCH_SEND_DEBUG_INFO, NO_BTN, NO_BTN, 0, true @@ -1944,253 +1965,253 @@ static const struct retro_keybind retro_keybinds_1[] = { static const struct retro_keybind retro_keybinds_rest[] = { { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_B, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_Y, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_SELECT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_START, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_LEFT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_RIGHT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_A, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_X, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_L, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_R, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_L2, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_R2, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_L3, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, RETROK_UNKNOWN, RETRO_DEVICE_ID_JOYPAD_R3, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_X_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_X_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_Y_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_LEFT_Y_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_X_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_X_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_Y_PLUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, RETROK_UNKNOWN, RARCH_ANALOG_RIGHT_Y_MINUS, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, RETROK_UNKNOWN, RARCH_LIGHTGUN_TRIGGER, RETRO_DEVICE_ID_MOUSE_LEFT, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, RETROK_UNKNOWN, RARCH_LIGHTGUN_RELOAD, RETRO_DEVICE_ID_MOUSE_RIGHT, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_A, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_B, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C, RETROK_UNKNOWN, RARCH_LIGHTGUN_AUX_C, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START, RETROK_UNKNOWN, RARCH_LIGHTGUN_START, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT, RETROK_UNKNOWN, RARCH_LIGHTGUN_SELECT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_UP, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_DOWN, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_LEFT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, + AXIS_NONE, AXIS_NONE, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, RETROK_UNKNOWN, RARCH_LIGHTGUN_DPAD_RIGHT, NO_BTN, NO_BTN, 0, true }, { NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, RETROK_UNKNOWN, + AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, RETROK_UNKNOWN, RARCH_TURBO_ENABLE, NO_BTN, NO_BTN, 0, true }, diff --git a/config.features.h b/config.features.h index b0f36bd706..8961c58e66 100644 --- a/config.features.h +++ b/config.features.h @@ -350,6 +350,12 @@ #define SUPPORTS_NETPLAY false #endif +#ifdef HAVE_SSL +#define SUPPORTS_SSL true +#else +#define SUPPORTS_SSL false +#endif + #if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) #define SUPPORTS_COCOA true #else diff --git a/configuration.c b/configuration.c index 2681f3d2c5..5126b0e15f 100644 --- a/configuration.c +++ b/configuration.c @@ -145,6 +145,7 @@ enum audio_driver_enum AUDIO_WII, AUDIO_WIIU, AUDIO_RWEBAUDIO, + AUDIO_AUDIOWORKLET, AUDIO_PSP, AUDIO_PS2, AUDIO_CTR, @@ -233,6 +234,8 @@ enum camera_driver_enum CAMERA_RWEBCAM, CAMERA_ANDROID, CAMERA_AVFOUNDATION, + CAMERA_PIPEWIRE, + CAMERA_FFMPEG, CAMERA_NULL }; @@ -276,6 +279,7 @@ enum menu_driver_enum enum record_driver_enum { RECORD_FFMPEG = MENU_NULL + 1, + RECORD_WAV, RECORD_NULL }; @@ -283,6 +287,7 @@ enum midi_driver_enum { MIDI_WINMM = RECORD_NULL + 1, MIDI_ALSA, + MIDI_COREMIDI, MIDI_NULL }; @@ -327,7 +332,7 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = { DECLARE_BIND(gun_dpad_left, RARCH_LIGHTGUN_DPAD_LEFT, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT), DECLARE_BIND(gun_dpad_right, RARCH_LIGHTGUN_DPAD_RIGHT, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT), - DECLARE_BIND(turbo, RARCH_TURBO_ENABLE, MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE), + DECLARE_BIND(turbo, RARCH_TURBO_ENABLE, MENU_ENUM_LABEL_VALUE_INPUT_TURBO), DECLARE_META_BIND(2, enable_hotkey, RARCH_ENABLE_HOTKEY, MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY), #ifdef HAVE_MENU @@ -379,6 +384,7 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = { DECLARE_META_BIND(2, recording_toggle, RARCH_RECORDING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE), DECLARE_META_BIND(2, streaming_toggle, RARCH_STREAMING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE), + DECLARE_META_BIND(2, turbo_fire_toggle, RARCH_TURBO_FIRE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE), DECLARE_META_BIND(2, grab_mouse_toggle, RARCH_GRAB_MOUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE), DECLARE_META_BIND(2, game_focus_toggle, RARCH_GAME_FOCUS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE), DECLARE_META_BIND(2, toggle_fullscreen, RARCH_FULLSCREEN_TOGGLE_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY), @@ -544,7 +550,9 @@ static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_DSOUND; static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_AL; #elif defined(HAVE_SL) static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_SL; -#elif defined(EMSCRIPTEN) +#elif defined(HAVE_AUDIOWORKLET) +static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_AUDIOWORKLET; +#elif defined(HAVE_RWEBAUDIO) static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_RWEBAUDIO; #elif defined(HAVE_SDL) static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_SDL; @@ -590,11 +598,13 @@ static const enum audio_resampler_driver_enum AUDIO_DEFAULT_RESAMPLER_DRIVER = A #if defined(HAVE_FFMPEG) static const enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_FFMPEG; #else -static const enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_NULL; +static const enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_WAV; #endif #ifdef HAVE_WINMM static const enum midi_driver_enum MIDI_DEFAULT_DRIVER = MIDI_WINMM; +#elif defined(HAVE_COREMIDI) +static const enum midi_driver_enum MIDI_DEFAULT_DRIVER = MIDI_COREMIDI; #elif defined(HAVE_ALSA) && !defined(HAVE_HAKCHI) && !defined(HAVE_SEGAM) && !defined(DINGUX) static const enum midi_driver_enum MIDI_DEFAULT_DRIVER = MIDI_ALSA; #else @@ -717,6 +727,12 @@ static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_V4L2; static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_RWEBCAM; #elif defined(ANDROID) static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_ANDROID; +#elif defined(HAVE_PIPEWIRE) +static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_PIPEWIRE; +#elif defined(HAVE_FFMPEG) +static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_FFMPEG; +#elif defined(HAVE_AVF) +static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_AVFOUNDATION; #else static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_NULL; #endif @@ -739,6 +755,8 @@ static const enum wifi_driver_enum WIFI_DEFAULT_DRIVER = WIFI_NULL; #if defined(ANDROID) static const enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_ANDROID; +#elif defined(HAVE_CORELOCATION) +static const enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_CORELOCATION; #else static const enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_NULL; #endif @@ -959,6 +977,8 @@ const char *config_get_default_audio(void) #endif case AUDIO_RWEBAUDIO: return "rwebaudio"; + case AUDIO_AUDIOWORKLET: + return "audioworklet"; case AUDIO_JACK: return "jack"; case AUDIO_NULL: @@ -1009,6 +1029,8 @@ const char *config_get_default_record(void) { case RECORD_FFMPEG: return "ffmpeg"; + case RECORD_WAV: + return "wav"; case RECORD_NULL: break; } @@ -1299,6 +1321,10 @@ const char *config_get_default_camera(void) return "android"; case CAMERA_AVFOUNDATION: return "avfoundation"; + case CAMERA_PIPEWIRE: + return "pipewire"; + case CAMERA_FFMPEG: + return "ffmpeg"; case CAMERA_NULL: break; } @@ -1447,6 +1473,8 @@ const char *config_get_default_midi(void) return "winmm"; case MIDI_ALSA: return "alsa"; + case MIDI_COREMIDI: + return "coremidi"; case MIDI_NULL: break; } @@ -1830,6 +1858,7 @@ static struct config_bool_setting *populate_settings_bool( #endif SETTING_BOOL("audio_fastforward_mute", &settings->bools.audio_fastforward_mute, true, DEFAULT_AUDIO_FASTFORWARD_MUTE, false); SETTING_BOOL("audio_fastforward_speedup", &settings->bools.audio_fastforward_speedup, true, DEFAULT_AUDIO_FASTFORWARD_SPEEDUP, false); + SETTING_BOOL("audio_rewind_mute", &settings->bools.audio_rewind_mute, true, DEFAULT_AUDIO_REWIND_MUTE, false); #ifdef HAVE_WASAPI SETTING_BOOL("audio_wasapi_exclusive_mode", &settings->bools.audio_wasapi_exclusive_mode, true, DEFAULT_WASAPI_EXCLUSIVE_MODE, false); @@ -1896,6 +1925,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("menu_widget_scale_auto", &settings->bools.menu_widget_scale_auto, true, DEFAULT_MENU_WIDGET_SCALE_AUTO, false); SETTING_BOOL("menu_show_load_content_animation", &settings->bools.menu_show_load_content_animation, true, DEFAULT_MENU_SHOW_LOAD_CONTENT_ANIMATION, false); SETTING_BOOL("notification_show_autoconfig", &settings->bools.notification_show_autoconfig, true, DEFAULT_NOTIFICATION_SHOW_AUTOCONFIG, false); + SETTING_BOOL("notification_show_autoconfig_fails", &settings->bools.notification_show_autoconfig_fails, true, DEFAULT_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, false); SETTING_BOOL("notification_show_cheats_applied", &settings->bools.notification_show_cheats_applied, true, DEFAULT_NOTIFICATION_SHOW_CHEATS_APPLIED, false); SETTING_BOOL("notification_show_patch_applied", &settings->bools.notification_show_patch_applied, true, DEFAULT_NOTIFICATION_SHOW_PATCH_APPLIED, false); SETTING_BOOL("notification_show_remap_load", &settings->bools.notification_show_remap_load, true, DEFAULT_NOTIFICATION_SHOW_REMAP_LOAD, false); @@ -1935,6 +1965,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("menu_dynamic_wallpaper_enable", &settings->bools.menu_dynamic_wallpaper_enable, true, DEFAULT_MENU_DYNAMIC_WALLPAPER_ENABLE, false); SETTING_BOOL("menu_ticker_smooth", &settings->bools.menu_ticker_smooth, true, DEFAULT_MENU_TICKER_SMOOTH, false); SETTING_BOOL("menu_scroll_fast", &settings->bools.menu_scroll_fast, true, DEFAULT_MENU_SCROLL_FAST, false); + SETTING_BOOL("menu_ignore_missing_assets", &settings->bools.menu_ignore_missing_assets, true, DEFAULT_MENU_IGNORE_MISSING_ASSETS, false); SETTING_BOOL("settings_show_drivers", &settings->bools.settings_show_drivers, true, DEFAULT_SETTINGS_SHOW_DRIVERS, false); SETTING_BOOL("settings_show_video", &settings->bools.settings_show_video, true, DEFAULT_SETTINGS_SHOW_VIDEO, false); @@ -2002,8 +2033,8 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("content_show_netplay", &settings->bools.menu_content_show_netplay, true, DEFAULT_CONTENT_SHOW_NETPLAY, false); #endif SETTING_BOOL("content_show_history", &settings->bools.menu_content_show_history, true, DEFAULT_CONTENT_SHOW_HISTORY, false); - SETTING_BOOL("content_show_add", &settings->bools.menu_content_show_add, true, DEFAULT_MENU_CONTENT_SHOW_ADD, false); SETTING_BOOL("content_show_playlists", &settings->bools.menu_content_show_playlists, true, DEFAULT_CONTENT_SHOW_PLAYLISTS, false); + SETTING_BOOL("content_show_playlist_tabs", &settings->bools.menu_content_show_playlist_tabs, true, DEFAULT_CONTENT_SHOW_PLAYLIST_TABS, false); #if defined(HAVE_LIBRETRODB) SETTING_BOOL("content_show_explore", &settings->bools.menu_content_show_explore, true, DEFAULT_MENU_CONTENT_SHOW_EXPLORE, false); #endif @@ -2135,7 +2166,8 @@ static struct config_bool_setting *populate_settings_bool( #endif SETTING_BOOL("keyboard_gamepad_enable", &settings->bools.input_keyboard_gamepad_enable, true, DEFAULT_INPUT_KEYBOARD_GAMEPAD_ENABLE, false); SETTING_BOOL("input_autodetect_enable", &settings->bools.input_autodetect_enable, true, DEFAULT_INPUT_AUTODETECT_ENABLE, false); - SETTING_BOOL("input_allow_turbo_dpad", &settings->bools.input_allow_turbo_dpad, true, DEFAULT_ALLOW_TURBO_DPAD, false); + SETTING_BOOL("input_turbo_enable", &settings->bools.input_turbo_enable, true, DEFAULT_TURBO_ENABLE, false); + SETTING_BOOL("input_turbo_allow_dpad", &settings->bools.input_turbo_allow_dpad, true, DEFAULT_TURBO_ALLOW_DPAD, false); SETTING_BOOL("input_auto_mouse_grab", &settings->bools.input_auto_mouse_grab, true, DEFAULT_INPUT_AUTO_MOUSE_GRAB, false); SETTING_BOOL("input_remap_binds_enable", &settings->bools.input_remap_binds_enable, true, true, false); SETTING_BOOL("input_remap_sort_by_controller_enable", &settings->bools.input_remap_sort_by_controller_enable, true, false, false); @@ -2229,6 +2261,10 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("gcdwebserver_alert", &settings->bools.gcdwebserver_alert, true, true, false); #endif +#ifdef HAVE_GAME_AI + SETTING_BOOL("quick_menu_show_game_ai", &settings->bools.quick_menu_show_game_ai, true, 1, false); +#endif + *size = count; return tmp; @@ -2492,9 +2528,9 @@ static struct config_uint_setting *populate_settings_uint( SETTING_UINT("input_bind_timeout", &settings->uints.input_bind_timeout, true, DEFAULT_INPUT_BIND_TIMEOUT, false); SETTING_UINT("input_bind_hold", &settings->uints.input_bind_hold, true, DEFAULT_INPUT_BIND_HOLD, false); SETTING_UINT("input_turbo_period", &settings->uints.input_turbo_period, true, DEFAULT_TURBO_PERIOD, false); - SETTING_UINT("input_duty_cycle", &settings->uints.input_turbo_duty_cycle, true, DEFAULT_TURBO_DUTY_CYCLE, false); - SETTING_UINT("input_turbo_mode", &settings->uints.input_turbo_mode, true, DEFAULT_TURBO_MODE, false); - SETTING_UINT("input_turbo_default_button", &settings->uints.input_turbo_default_button, true, DEFAULT_TURBO_DEFAULT_BTN, false); + SETTING_UINT("input_turbo_duty_cycle", &settings->uints.input_turbo_duty_cycle, true, DEFAULT_TURBO_DUTY_CYCLE, false); + SETTING_UINT("input_turbo_mode", &settings->uints.input_turbo_mode, true, DEFAULT_TURBO_MODE, false); + SETTING_UINT("input_turbo_button", &settings->uints.input_turbo_button, true, DEFAULT_TURBO_BUTTON, false); SETTING_UINT("input_max_users", &settings->uints.input_max_users, true, DEFAULT_INPUT_MAX_USERS, false); SETTING_UINT("input_menu_toggle_gamepad_combo", &settings->uints.input_menu_toggle_gamepad_combo, true, DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO, false); SETTING_UINT("input_poll_type_behavior", &settings->uints.input_poll_type_behavior, true, DEFAULT_INPUT_POLL_TYPE_BEHAVIOR, false); @@ -2681,6 +2717,7 @@ static struct config_int_setting *populate_settings_int( #ifdef HAVE_OVERLAY SETTING_INT("input_overlay_lightgun_port", &settings->ints.input_overlay_lightgun_port, true, DEFAULT_INPUT_OVERLAY_LIGHTGUN_PORT, false); #endif + SETTING_INT("input_turbo_bind", &settings->ints.input_turbo_bind, true, DEFAULT_TURBO_BIND, false); *size = count; @@ -3570,6 +3607,14 @@ static bool config_load_file(global_t *global, { unsigned i; char tmp_str[PATH_MAX_LENGTH]; + char* libretro_directory = NULL; + char* libretro_assets_directory = NULL; + char* libretro_autoconfig_directory = NULL; + char* libretro_cheats_directory = NULL; + char* libretro_database_directory = NULL; + char* libretro_system_directory = NULL; + char* libretro_video_filter_directory = NULL; + char* libretro_video_shader_directory = NULL; static bool first_load = true; bool without_overrides = false; unsigned msg_color = 0; @@ -3716,6 +3761,14 @@ static bool config_load_file(global_t *global, } #endif + /* Special case for perfcnt_enable */ + { + bool tmp = false; + config_get_bool(conf, "perfcnt_enable", &tmp); + if (tmp) + retroarch_ctl(RARCH_CTL_SET_PERFCNT_ENABLE, NULL); + } + /* Overrides */ if (rarch_flags & RARCH_FLAGS_HAS_SET_USERNAME) @@ -3864,6 +3917,38 @@ static bool config_load_file(global_t *global, /* Post-settings load */ + libretro_directory = getenv("LIBRETRO_DIRECTORY"); + if (libretro_directory) { + configuration_set_string(settings, + settings->paths.directory_libretro, libretro_directory); + configuration_set_string(settings, + settings->paths.path_libretro_info, libretro_directory); + } + + libretro_autoconfig_directory = getenv("LIBRETRO_AUTOCONFIG_DIRECTORY"); + if (libretro_autoconfig_directory) /* override configuration value */ + configuration_set_string(settings, + settings->paths.directory_autoconfig, + libretro_autoconfig_directory); + + libretro_cheats_directory = getenv("LIBRETRO_CHEATS_DIRECTORY"); + if (libretro_cheats_directory) /* override configuration value */ + configuration_set_string(settings, + settings->paths.path_cheat_database, + libretro_cheats_directory); + + libretro_database_directory = getenv("LIBRETRO_DATABASE_DIRECTORY"); + if (libretro_database_directory) /* override configuration value */ + configuration_set_string(settings, + settings->paths.path_content_database, + libretro_database_directory); + + libretro_system_directory = getenv("LIBRETRO_SYSTEM_DIRECTORY"); + if (libretro_system_directory) /* override configuration value */ + configuration_set_string(settings, + settings->paths.directory_system, + libretro_system_directory); + if ( (rarch_flags & RARCH_FLAGS_HAS_SET_USERNAME) && (override_username)) { @@ -4028,15 +4113,27 @@ static bool config_load_file(global_t *global, *settings->paths.path_menu_wallpaper = '\0'; if (string_is_equal(settings->paths.path_rgui_theme_preset, "default")) *settings->paths.path_rgui_theme_preset = '\0'; - if (string_is_equal(settings->paths.directory_video_shader, "default")) + libretro_video_shader_directory = getenv("LIBRETRO_VIDEO_SHADER_DIRECTORY"); + if (libretro_video_shader_directory) { /* override configuration value */ + configuration_set_string(settings, settings->paths.directory_video_shader, + libretro_video_shader_directory); + } else if (string_is_equal(settings->paths.directory_video_shader, "default")) *settings->paths.directory_video_shader = '\0'; - if (string_is_equal(settings->paths.directory_video_filter, "default")) + libretro_video_filter_directory = getenv("LIBRETRO_VIDEO_FILTER_DIRECTORY"); + if (libretro_video_filter_directory) { /* override configuration value */ + configuration_set_string(settings, settings->paths.directory_video_filter, + libretro_video_filter_directory); + } else if (string_is_equal(settings->paths.directory_video_filter, "default")) *settings->paths.directory_video_filter = '\0'; if (string_is_equal(settings->paths.directory_audio_filter, "default")) *settings->paths.directory_audio_filter = '\0'; if (string_is_equal(settings->paths.directory_core_assets, "default")) *settings->paths.directory_core_assets = '\0'; - if (string_is_equal(settings->paths.directory_assets, "default")) + libretro_assets_directory = getenv("LIBRETRO_ASSETS_DIRECTORY"); + if (libretro_assets_directory) { /* override configuration value */ + configuration_set_string(settings, + settings->paths.directory_assets, libretro_assets_directory); + } else if (string_is_equal(settings->paths.directory_assets, "default")) *settings->paths.directory_assets = '\0'; #ifdef _3DS if (string_is_equal(settings->paths.directory_bottom_assets, "default")) @@ -4385,7 +4482,7 @@ bool config_load_override(void *data) char tmp_path[PATH_MAX_LENGTH]; size_t _len = strlcpy(tmp_path, path_get(RARCH_PATH_CONFIG_OVERRIDE), - sizeof(tmp_path)); + sizeof(tmp_path) - 2); tmp_path[ _len] = '|'; tmp_path[++_len] = '\0'; strlcpy(tmp_path + _len, core_path, sizeof(tmp_path) - _len); @@ -4413,7 +4510,7 @@ bool config_load_override(void *data) char tmp_path[PATH_MAX_LENGTH]; size_t _len = strlcpy(tmp_path, path_get(RARCH_PATH_CONFIG_OVERRIDE), - sizeof(tmp_path)); + sizeof(tmp_path) - 2); tmp_path[ _len] = '|'; tmp_path[++_len] = '\0'; strlcpy(tmp_path + _len, content_path, sizeof(tmp_path) - _len); @@ -4439,7 +4536,7 @@ bool config_load_override(void *data) char tmp_path[PATH_MAX_LENGTH]; size_t _len = strlcpy(tmp_path, path_get(RARCH_PATH_CONFIG_OVERRIDE), - sizeof(tmp_path)); + sizeof(tmp_path) - 2); tmp_path[ _len] = '|'; tmp_path[++_len] = '\0'; strlcpy(tmp_path + _len, game_path, sizeof(tmp_path) - _len); @@ -4471,8 +4568,9 @@ bool config_load_override(void *data) if (settings->bools.notification_show_config_override_load && show_notification) { - const char *_msg = msg_hash_to_str(MSG_CONFIG_OVERRIDE_LOADED); - runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, false, NULL, + char msg[128]; + size_t _len = strlcpy(msg, msg_hash_to_str(MSG_CONFIG_OVERRIDE_LOADED), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 100, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } @@ -4490,29 +4588,15 @@ bool config_load_override(void *data) bool config_load_override_file(const char *config_path) { - char config_directory[DIR_MAX_LENGTH]; - bool should_append = false; - bool show_notification = true; - settings_t *settings = config_st; - - config_directory[0] = '\0'; + settings_t *settings = config_st; path_clear(RARCH_PATH_CONFIG_OVERRIDE); - /* Get base config directory */ - fill_pathname_application_special(config_directory, - sizeof(config_directory), - APPLICATION_SPECIAL_DIRECTORY_CONFIG); - - if (path_is_valid(config_path)) - { - path_set(RARCH_PATH_CONFIG_OVERRIDE, config_path); - should_append = true; - } - - if (!should_append) + if (!path_is_valid(config_path)) return false; + path_set(RARCH_PATH_CONFIG_OVERRIDE, config_path); + /* Re-load the configuration with any overrides * that might have been found */ @@ -4524,11 +4608,11 @@ bool config_load_override_file(const char *config_path) path_get(RARCH_PATH_CONFIG), settings)) return false; - if (settings->bools.notification_show_config_override_load - && show_notification) + if (settings->bools.notification_show_config_override_load) { - const char *_msg = msg_hash_to_str(MSG_CONFIG_OVERRIDE_LOADED); - runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, false, NULL, + char msg[128]; + size_t _len = strlcpy(msg, msg_hash_to_str(MSG_CONFIG_OVERRIDE_LOADED), sizeof(msg)); + runloop_msg_queue_push(msg, _len, 1, 100, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } @@ -4737,8 +4821,9 @@ bool config_load_remap(const char *directory_input_remapping, success: if (notification_show_remap_load) { - const char *_msg = msg_hash_to_str(msg_remap_loaded); - runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, false, NULL, + char _msg[128]; + size_t _len = strlcpy(_msg, msg_hash_to_str(msg_remap_loaded), sizeof(_msg)); + runloop_msg_queue_push(_msg, _len, 1, 100, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } return true; @@ -4838,6 +4923,7 @@ static void save_keybind_axis(config_file_t *conf, const struct retro_keybind *bind, bool save_empty) { char key[64]; + char config[16]; size_t _len = fill_pathname_join_delim(key, prefix, base, '_', sizeof(key)); strlcpy(key + _len, "_axis", sizeof(key) - _len); @@ -4845,25 +4931,20 @@ static void save_keybind_axis(config_file_t *conf, { if (save_empty) config_set_string(conf, key, "nul"); + return; } - else if (AXIS_NEG_GET(bind->joyaxis) != AXIS_DIR_NONE) + + if (AXIS_NEG_GET(bind->joyaxis) != AXIS_DIR_NONE) { - char config[16]; - config[0] = '-'; - config[1] = '\0'; - snprintf(config + 1, sizeof(config) - 1, "%u", - AXIS_NEG_GET(bind->joyaxis)); - config_set_string(conf, key, config); + snprintf(config, sizeof(config), "-%lu", + (unsigned long)AXIS_NEG_GET(bind->joyaxis)); } else if (AXIS_POS_GET(bind->joyaxis) != AXIS_DIR_NONE) { - char config[16]; - config[0] = '+'; - config[1] = '\0'; - snprintf(config + 1, sizeof(config) - 1, "%u", - AXIS_POS_GET(bind->joyaxis)); - config_set_string(conf, key, config); + snprintf(config, sizeof(config), "+%lu", + (unsigned long)AXIS_POS_GET(bind->joyaxis)); } + config_set_string(conf, key, config); } static void save_keybind_mbutton(config_file_t *conf, @@ -5879,11 +5960,15 @@ bool input_remapping_load_file(void *data, const char *path) config_file_t *conf = (config_file_t*)data; settings_t *settings = config_st; runloop_state_t *runloop_st = runloop_state_get_ptr(); - char key_strings[RARCH_FIRST_CUSTOM_BIND + 8][8] = { - "b", "y", "select", "start", - "up", "down", "left", "right", - "a", "x", "l", "r", "l2", "r2", - "l3", "r3", "l_x+", "l_x-", "l_y+", "l_y-", "r_x+", "r_x-", "r_y+", "r_y-" }; + char key_strings[RARCH_FIRST_CUSTOM_BIND + 8][8] = + { + "b", "y", "select", "start", + "up", "down", "left", "right", + "a", "x", "l", "r", + "l2", "r2", "l3", "r3", + "l_x+", "l_x-", "l_y+", "l_y-", + "r_x+", "r_x-", "r_y+", "r_y-" + }; if ( !conf || string_is_empty(path)) @@ -5974,17 +6059,39 @@ bool input_remapping_load_file(void *data, const char *path) } } - _len = strlcpy(s1, prefix, sizeof(s1)); - strlcpy(s1 + _len, "_analog_dpad_mode", sizeof(s1) - _len); - CONFIG_GET_INT_BASE(conf, settings, uints.input_analog_dpad_mode[i], s1); - _len = strlcpy(s1, "input_libretro_device_p", sizeof(s1)); strlcpy(s1 + _len, formatted_number, sizeof(s1) - _len); CONFIG_GET_INT_BASE(conf, settings, uints.input_libretro_device[i], s1); + _len = strlcpy(s1, prefix, sizeof(s1)); + strlcpy(s1 + _len, "_analog_dpad_mode", sizeof(s1) - _len); + CONFIG_GET_INT_BASE(conf, settings, uints.input_analog_dpad_mode[i], s1); + _len = strlcpy(s1, "input_remap_port_p", sizeof(s1)); strlcpy(s1 + _len, formatted_number, sizeof(s1) - _len); CONFIG_GET_INT_BASE(conf, settings, uints.input_remap_ports[i], s1); + + /* Turbo fire settings */ + _len = strlcpy(s1, "input_turbo_enable", sizeof(s1)); + CONFIG_GET_BOOL_BASE(conf, settings, bools.input_turbo_enable, s1); + + _len = strlcpy(s1, "input_turbo_allow_dpad", sizeof(s1)); + CONFIG_GET_BOOL_BASE(conf, settings, bools.input_turbo_allow_dpad, s1); + + _len = strlcpy(s1, "input_turbo_mode", sizeof(s1)); + CONFIG_GET_INT_BASE(conf, settings, uints.input_turbo_mode, s1); + + _len = strlcpy(s1, "input_turbo_bind", sizeof(s1)); + CONFIG_GET_INT_BASE(conf, settings, ints.input_turbo_bind, s1); + + _len = strlcpy(s1, "input_turbo_button", sizeof(s1)); + CONFIG_GET_INT_BASE(conf, settings, uints.input_turbo_button, s1); + + _len = strlcpy(s1, "input_turbo_period", sizeof(s1)); + CONFIG_GET_INT_BASE(conf, settings, uints.input_turbo_period, s1); + + _len = strlcpy(s1, "input_turbo_duty_cycle", sizeof(s1)); + CONFIG_GET_INT_BASE(conf, settings, uints.input_turbo_duty_cycle, s1); } input_remapping_update_port_map(); @@ -6073,7 +6180,11 @@ bool input_remapping_save_file(const char *path) if (skip_port) continue; - snprintf(formatted_number, sizeof(formatted_number), "%u", i + 1); + _len = snprintf(formatted_number, sizeof(formatted_number), "%u", i + 1); + if (_len >= sizeof(formatted_number)) { + RARCH_ERR("[Config]: unexpectedly high number of users"); + break; + } _len = strlcpy(prefix, "input_player", sizeof(prefix)); strlcpy(prefix + _len, formatted_number, sizeof(prefix) - _len); _len = strlcpy(s1, prefix, sizeof(s1)); @@ -6099,7 +6210,12 @@ bool input_remapping_save_file(const char *path) else { if (remap_id == RARCH_UNMAPPED) - config_set_int(conf, _ident, -1); + { + if (string_is_empty(runloop_st->system.input_desc_btn[i][j])) + config_unset(conf, _ident); + else + config_set_int(conf, _ident, -1); + } else config_set_int(conf, _ident, settings->uints.input_remap_ids[i][j]); @@ -6132,7 +6248,12 @@ bool input_remapping_save_file(const char *path) else { if (remap_id == RARCH_UNMAPPED) - config_set_int(conf, _ident, -1); + { + if (string_is_empty(runloop_st->system.input_desc_btn[i][j])) + config_unset(conf, _ident); + else + config_set_int(conf, _ident, -1); + } else config_set_int(conf, _ident, settings->uints.input_remap_ids[i][j]); @@ -6160,6 +6281,28 @@ bool input_remapping_save_file(const char *path) _len = strlcpy(s1, "input_remap_port_p", sizeof(s1)); strlcpy(s1 + _len, formatted_number, sizeof(s1) - _len); config_set_int(conf, s1, settings->uints.input_remap_ports[i]); + + /* Turbo fire settings */ + _len = strlcpy(s1, "input_turbo_enable", sizeof(s1)); + config_set_string(conf, s1, settings->bools.input_turbo_enable ? "true" : "false"); + + _len = strlcpy(s1, "input_turbo_allow_dpad", sizeof(s1)); + config_set_string(conf, s1, settings->bools.input_turbo_allow_dpad ? "true" : "false"); + + _len = strlcpy(s1, "input_turbo_mode", sizeof(s1)); + config_set_int(conf, s1, settings->uints.input_turbo_mode); + + _len = strlcpy(s1, "input_turbo_bind", sizeof(s1)); + config_set_int(conf, s1, settings->ints.input_turbo_bind); + + _len = strlcpy(s1, "input_turbo_button", sizeof(s1)); + config_set_int(conf, s1, settings->uints.input_turbo_button); + + _len = strlcpy(s1, "input_turbo_period", sizeof(s1)); + config_set_int(conf, s1, settings->uints.input_turbo_period); + + _len = strlcpy(s1, "input_turbo_duty_cycle", sizeof(s1)); + config_set_int(conf, s1, settings->uints.input_turbo_duty_cycle); } ret = config_file_write(conf, path, true); @@ -6204,12 +6347,10 @@ static bool config_file_salamander_get_path(char *s, size_t len) void config_load_file_salamander(void) { - config_file_t *config = NULL; char config_path[PATH_MAX_LENGTH]; - char libretro_path[PATH_MAX_LENGTH]; + config_file_t *config = NULL; config_path[0] = '\0'; - libretro_path[0] = '\0'; /* Get config file path */ if (!config_file_salamander_get_path( @@ -6226,10 +6367,10 @@ void config_load_file_salamander(void) config_path); if (config_get_path(config, "libretro_path", - libretro_path, sizeof(libretro_path)) - && !string_is_empty(libretro_path) - && !string_is_equal(libretro_path, "builtin")) - path_set(RARCH_PATH_CORE, libretro_path); + config_path, sizeof(config_path)) + && !string_is_empty(config_path) + && !string_is_equal(config_path, "builtin")) + path_set(RARCH_PATH_CORE, config_path); config_file_free(config); } @@ -6451,7 +6592,6 @@ void input_config_parse_joy_axis( { char tmp[64]; char key[64]; - char key_label[64]; config_file_t *conf = (config_file_t*)conf_data; struct retro_keybind *bind = (struct retro_keybind*)bind_data; struct config_entry_list *tmp_a = NULL; @@ -6460,8 +6600,6 @@ void input_config_parse_joy_axis( fill_pathname_join_delim(key, s, "axis", '_', sizeof(key)); - fill_pathname_join_delim(key_label, s, - "axis_label", '_', sizeof(key_label)); if (config_get_array(conf, key, tmp, sizeof(tmp))) { @@ -6483,12 +6621,12 @@ void input_config_parse_joy_axis( else bind->joyaxis = AXIS_NEG(i_axis); } - - /* Ensure that D-pad emulation doesn't screw this over. */ - bind->orig_joyaxis = bind->joyaxis; } - tmp_a = config_get_entry(conf, key_label); + fill_pathname_join_delim(key, s, + "axis_label", '_', sizeof(key)); + + tmp_a = config_get_entry(conf, key); if (tmp_a && (!string_is_empty(tmp_a->value))) { @@ -6542,7 +6680,6 @@ void input_config_parse_joy_button( { char tmp[64]; char key[64]; - char key_label[64]; config_file_t *conf = (config_file_t*)data; struct retro_keybind *bind = (struct retro_keybind*)bind_data; struct config_entry_list *tmp_a = NULL; @@ -6551,8 +6688,6 @@ void input_config_parse_joy_button( fill_pathname_join_delim(key, s, "btn", '_', sizeof(key)); - fill_pathname_join_delim(key_label, s, - "btn_label", '_', sizeof(key_label)); if (config_get_array(conf, key, tmp, sizeof(tmp))) { @@ -6583,7 +6718,10 @@ void input_config_parse_joy_button( } } - tmp_a = config_get_entry(conf, key_label); + fill_pathname_join_delim(key, s, + "btn_label", '_', sizeof(key)); + + tmp_a = config_get_entry(conf, key); if (tmp_a && !string_is_empty(tmp_a->value)) { diff --git a/configuration.h b/configuration.h index ddfa98b46a..e9d09c0a0c 100644 --- a/configuration.h +++ b/configuration.h @@ -144,6 +144,7 @@ typedef struct settings #ifdef HAVE_OVERLAY int input_overlay_lightgun_port; #endif + int input_turbo_bind; } ints; struct @@ -194,7 +195,7 @@ typedef struct settings unsigned input_turbo_period; unsigned input_turbo_duty_cycle; unsigned input_turbo_mode; - unsigned input_turbo_default_button; + unsigned input_turbo_button; unsigned input_bind_timeout; unsigned input_bind_hold; @@ -664,6 +665,7 @@ typedef struct settings bool audio_rate_control; bool audio_fastforward_mute; bool audio_fastforward_speedup; + bool audio_rewind_mute; #ifdef IOS bool audio_respect_silent_mode; #endif @@ -711,7 +713,8 @@ typedef struct settings bool input_small_keyboard_enable; bool input_keyboard_gamepad_enable; bool input_auto_mouse_grab; - bool input_allow_turbo_dpad; + bool input_turbo_enable; + bool input_turbo_allow_dpad; bool input_hotkey_device_merge; #if defined(HAVE_DINPUT) || defined(HAVE_WINRAWINPUT) bool input_nowinkey_enable; @@ -734,6 +737,7 @@ typedef struct settings bool menu_enable_widgets; bool menu_show_load_content_animation; bool notification_show_autoconfig; + bool notification_show_autoconfig_fails; bool notification_show_cheats_applied; bool notification_show_patch_applied; bool notification_show_remap_load; @@ -825,6 +829,7 @@ typedef struct settings bool menu_content_show_history; bool menu_content_show_add; bool menu_content_show_playlists; + bool menu_content_show_playlist_tabs; bool menu_content_show_explore; bool menu_use_preferred_system_color_theme; bool menu_preferred_system_color_theme_set; @@ -834,6 +839,7 @@ typedef struct settings bool menu_disable_left_analog; bool menu_disable_right_analog; bool menu_ticker_smooth; + bool menu_ignore_missing_assets; bool settings_show_drivers; bool settings_show_video; bool settings_show_audio; @@ -1097,6 +1103,14 @@ typedef struct settings #if defined(HAVE_COCOATOUCH) bool gcdwebserver_alert; #endif + +#ifdef HAVE_GAME_AI + bool quick_menu_show_game_ai; + bool game_ai_override_p1; + bool game_ai_override_p2; + bool game_ai_show_debug; +#endif + } bools; uint8_t flags; @@ -1263,8 +1277,7 @@ bool config_load_remap(const char *directory_input_remapping, **/ void config_get_autoconf_profile_filename( - const char *device_name, unsigned user, - char *buf, size_t len_buf); + const char *device_name, unsigned user, char *s, size_t len); /** * config_save_autoconf_profile: * @device_name : Input device name diff --git a/content.h b/content.h index 776126cf51..612bc4e185 100644 --- a/content.h +++ b/content.h @@ -135,7 +135,7 @@ char* content_get_subsystem_rom(unsigned index); bool content_set_subsystem_by_name(const char* subsystem_name); /* Get the current subsystem "friendly name" */ -void content_get_subsystem_friendly_name(const char* subsystem_name, char* subsystem_friendly_name, size_t len); +size_t content_get_subsystem_friendly_name(const char* subsystem_name, char *s, size_t len); /* Sets overrides which modify frontend handling of * specific content file types */ diff --git a/core_backup.c b/core_backup.c index 59979f6110..6fd267b492 100644 --- a/core_backup.c +++ b/core_backup.c @@ -49,7 +49,7 @@ struct core_backup_list static bool core_backup_get_backup_dir( const char *dir_libretro, const char *dir_core_assets, const char *core_filename, - char *backup_dir, size_t len) + char *s, size_t len) { char tmp[PATH_MAX_LENGTH]; char core_file_id[NAME_MAX_LENGTH]; @@ -87,18 +87,18 @@ static bool core_backup_get_backup_dir( : dir_core_assets, "core_backups", sizeof(tmp)); - fill_pathname_join_special(backup_dir, tmp, + fill_pathname_join_special(s, tmp, core_file_id, len); - if (string_is_empty(backup_dir)) + if (string_is_empty(s)) return false; /* > Create directory, if required */ - if (!path_is_directory(backup_dir)) + if (!path_is_directory(s)) { - if (!path_mkdir(backup_dir)) + if (!path_mkdir(s)) { - RARCH_ERR("[core backup] Failed to create backup directory: %s.\n", backup_dir); + RARCH_ERR("[core backup] Failed to create backup directory: %s.\n", s); return false; } } @@ -112,7 +112,7 @@ bool core_backup_get_backup_path( const char *core_path, uint32_t crc, enum core_backup_mode backup_mode, const char *dir_core_assets, - char *backup_path, size_t len) + char *s, size_t len) { time_t current_time; struct tm time_info; @@ -162,7 +162,7 @@ bool core_backup_get_backup_path( FILE_PATH_CORE_BACKUP_EXTENSION); /* Build final path */ - fill_pathname_join_special(backup_path, backup_dir, + fill_pathname_join_special(s, backup_dir, backup_filename, len); return true; @@ -239,27 +239,25 @@ error: /* Fetches crc value of specified core backup file. * Returns true if successful */ -bool core_backup_get_backup_crc(char *backup_path, uint32_t *crc) +bool core_backup_get_backup_crc(char *s, uint32_t *crc) { enum core_backup_type backup_type; struct string_list *metadata_list = NULL; - if (string_is_empty(backup_path) || !crc) + if (string_is_empty(s) || !crc) return false; /* Get backup type */ - backup_type = core_backup_get_backup_type(backup_path); + backup_type = core_backup_get_backup_type(s); switch (backup_type) { case CORE_BACKUP_TYPE_ARCHIVE: { - const char *backup_filename = NULL; const char *crc_str = NULL; - /* Split the backup filename into its various * metadata components */ - backup_filename = path_basename(backup_path); + const char *backup_filename = path_basename(s); if (string_is_empty(backup_filename)) goto error; @@ -293,7 +291,7 @@ bool core_backup_get_backup_crc(char *backup_path, uint32_t *crc) /* Open backup file */ backup_file = intfstream_open_file( - backup_path, RETRO_VFS_FILE_ACCESS_READ, + s, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); if (backup_file) @@ -334,7 +332,7 @@ error: * arguments are otherwise invalid */ enum core_backup_type core_backup_get_core_path( const char *backup_path, const char *dir_libretro, - char *core_path, size_t len) + char *s, size_t len) { const char *backup_filename = NULL; @@ -378,14 +376,14 @@ enum core_backup_type core_backup_get_core_path( } /* All good - build core path */ - fill_pathname_join_special(core_path, dir_libretro, + fill_pathname_join_special(s, dir_libretro, core_filename, len); free(core_filename); } return CORE_BACKUP_TYPE_ARCHIVE; case CORE_BACKUP_TYPE_LIB: /* This is a plain dynamic library file */ - fill_pathname_join_special(core_path, dir_libretro, + fill_pathname_join_special(s, dir_libretro, backup_filename, len); return CORE_BACKUP_TYPE_LIB; default: diff --git a/core_info.c b/core_info.c index edb68971f6..d9f561c116 100644 --- a/core_info.c +++ b/core_info.c @@ -100,11 +100,11 @@ static core_info_state_t core_info_st = { /* JSON Handlers START */ static bool CCJSONObjectMemberHandler(void *context, - const char *pValue, size_t length) + const char *pValue, size_t len) { CCJSONContext *pCtx = (CCJSONContext *)context; - if (length) + if (len) { switch (pCtx->array_depth) { @@ -262,12 +262,12 @@ static bool CCJSONObjectMemberHandler(void *context, } static bool CCJSONStringHandler(void *context, - const char *pValue, size_t length) + const char *pValue, size_t len) { CCJSONContext *pCtx = (CCJSONContext*)context; if ( pCtx->current_string_val - && length + && len && !string_is_empty(pValue)) { if (*pCtx->current_string_val) @@ -290,7 +290,7 @@ static bool CCJSONStringHandler(void *context, } static bool CCJSONNumberHandler(void *context, - const char *pValue, size_t length) + const char *pValue, size_t len) { CCJSONContext *pCtx = (CCJSONContext*)context; @@ -849,8 +849,7 @@ static bool core_info_cache_write(core_info_cache_list_t *list, const char *info sizeof(file_path)); #if defined(CORE_INFO_CACHE_COMPRESS) - file = intfstream_open_rzip_file(file_path, - RETRO_VFS_FILE_ACCESS_WRITE); + file = intfstream_open_rzip_file(file_path, RETRO_VFS_FILE_ACCESS_WRITE); #else file = intfstream_open_file(file_path, RETRO_VFS_FILE_ACCESS_WRITE, @@ -1255,10 +1254,8 @@ bool core_info_cache_force_refresh(const char *path_info) * if required */ if (!path_is_valid(file_path)) { - RFILE *refresh_file = filestream_open( - file_path, - RETRO_VFS_FILE_ACCESS_WRITE, - RETRO_VFS_FILE_ACCESS_HINT_NONE); + RFILE *refresh_file = filestream_open(file_path, + RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE); if (!refresh_file) return false; @@ -1402,8 +1399,7 @@ static core_path_list_t *core_info_path_list_new(const char *core_dir, /* Fetch core directory listing */ dir_list_ok = dir_list_append(path_list->dir_list, - core_dir, exts, false, show_hidden_files, - false, false); + core_dir, exts, false, show_hidden_files, false, false); #if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP { @@ -1497,18 +1493,15 @@ static bool core_info_path_is_locked( core_aux_file_path_list_t *lock_list, const char *core_file_name) { - size_t i, len; + size_t i; uint32_t hash; char lock_filename[NAME_MAX_LENGTH]; if (lock_list->size < 1) return false; - len = strlcpy(lock_filename, core_file_name, - sizeof(lock_filename)); - strlcpy(lock_filename + len, - ".lck", - sizeof(lock_filename) - len); + fill_pathname(lock_filename, core_file_name, + ".lck", sizeof(lock_filename)); hash = core_info_hash_string(lock_filename); @@ -1528,18 +1521,15 @@ static bool core_info_path_is_standalone_exempt( core_aux_file_path_list_t *exempt_list, const char *core_file_name) { - size_t i, len; + size_t i; uint32_t hash; char exempt_filename[NAME_MAX_LENGTH]; if (exempt_list->size < 1) return false; - len = strlcpy(exempt_filename, core_file_name, - sizeof(exempt_filename)); - strlcpy(exempt_filename + len, - ".lsae", - sizeof(exempt_filename) - len); + fill_pathname(exempt_filename, core_file_name, + ".lsae", sizeof(exempt_filename)); hash = core_info_hash_string(exempt_filename); @@ -2202,19 +2192,15 @@ static bool core_info_does_support_file( const core_info_t *core, const char *path) { const char *basename, *ext; - if (!core || !core->supported_extensions_list) return false; if (string_is_empty(path)) return false; - basename = path_basename(path); - /* if a core has / in its list of supported extensions, the core supports loading of directories on the host file system */ if (string_is_empty(basename)) return string_list_find_elem(core->supported_extensions_list, "/"); - ext = strrchr(basename, '.'); return string_list_find_elem_prefix( core->supported_extensions_list, ".", (ext ? ext + 1 : "")); @@ -2232,12 +2218,11 @@ static int core_info_qsort_cmp(const void *a_, const void *b_) int support_b = core_info_does_support_file(b, p_coreinfo->tmp_path); #ifdef HAVE_COMPRESSION - support_a = support_a || - core_info_does_support_any_file(a, p_coreinfo->tmp_list); - support_b = support_b || - core_info_does_support_any_file(b, p_coreinfo->tmp_list); + support_a = support_a + || core_info_does_support_any_file(a, p_coreinfo->tmp_list); + support_b = support_b + || core_info_does_support_any_file(b, p_coreinfo->tmp_list); #endif - if (support_a != support_b) return support_b - support_a; return strcasecmp(a->display_name, b->display_name); @@ -2799,72 +2784,64 @@ void core_info_qsort(core_info_list_t *core_info_list, bool core_info_current_supports_savestate(void) { - core_info_state_t *p_coreinfo = &core_info_st; - settings_t *settings = config_get_ptr(); - - if (settings->bools.core_info_savestate_bypass) + core_info_state_t *p_coreinfo = &core_info_st; + settings_t *settings = config_get_ptr(); + bool core_info_savestate_bypass = settings->bools.core_info_savestate_bypass; + if (core_info_savestate_bypass) return true; - /* If no core is currently loaded, assume * by default that all savestate functionality * is supported */ if (!p_coreinfo->current) return true; - return p_coreinfo->current->savestate_support_level >= CORE_INFO_SAVESTATE_BASIC; } bool core_info_current_supports_rewind(void) { - core_info_state_t *p_coreinfo = &core_info_st; - settings_t *settings = config_get_ptr(); - - if (settings->bools.core_info_savestate_bypass) + core_info_state_t *p_coreinfo = &core_info_st; + settings_t *settings = config_get_ptr(); + bool core_info_savestate_bypass = settings->bools.core_info_savestate_bypass; + if (core_info_savestate_bypass) return true; - /* If no core is currently loaded, assume * by default that all savestate functionality * is supported */ if (!p_coreinfo->current) return true; - return p_coreinfo->current->savestate_support_level >= CORE_INFO_SAVESTATE_SERIALIZED; } bool core_info_current_supports_netplay(void) { - core_info_state_t *p_coreinfo = &core_info_st; - settings_t *settings = config_get_ptr(); - - if (settings->bools.core_info_savestate_bypass) + core_info_state_t *p_coreinfo = &core_info_st; + settings_t *settings = config_get_ptr(); + bool core_info_savestate_bypass = settings->bools.core_info_savestate_bypass; + if (core_info_savestate_bypass) return true; - /* If no core is currently loaded, assume * by default that all savestate functionality * is supported */ if (!p_coreinfo->current) return true; - return p_coreinfo->current->savestate_support_level >= CORE_INFO_SAVESTATE_DETERMINISTIC; } bool core_info_current_supports_runahead(void) { - core_info_state_t *p_coreinfo = &core_info_st; - settings_t *settings = config_get_ptr(); - - if (settings->bools.core_info_savestate_bypass) + core_info_state_t *p_coreinfo = &core_info_st; + settings_t *settings = config_get_ptr(); + bool core_info_savestate_bypass = settings->bools.core_info_savestate_bypass; + if (core_info_savestate_bypass) return true; - /* If no core is currently loaded, assume * by default that all savestate functionality * is supported */ if (!p_coreinfo->current) return true; - return p_coreinfo->current->savestate_support_level >= CORE_INFO_SAVESTATE_DETERMINISTIC; } @@ -2912,7 +2889,6 @@ static bool core_info_update_core_aux_file(const char *path, bool create) * core info list this is *not* thread safe */ bool core_info_set_core_lock(const char *core_path, bool lock) { - size_t _len; core_info_t *core_info = NULL; char lock_file_path[PATH_MAX_LENGTH]; @@ -2931,11 +2907,8 @@ bool core_info_set_core_lock(const char *core_path, bool lock) return false; /* Get lock file path */ - _len = strlcpy(lock_file_path, core_info->path, - sizeof(lock_file_path)); - strlcpy(lock_file_path + _len, - ".lck", - sizeof(lock_file_path) - _len); + fill_pathname(lock_file_path, core_info->path, + ".lck", sizeof(lock_file_path)); /* Create or delete lock file, as required */ if (!core_info_update_core_aux_file(lock_file_path, lock)) @@ -2959,7 +2932,6 @@ bool core_info_set_core_lock(const char *core_path, bool lock) * must be checked externally */ bool core_info_get_core_lock(const char *core_path, bool validate_path) { - size_t _len; core_info_t *core_info = NULL; const char *core_file_path = NULL; bool is_locked = false; @@ -2990,11 +2962,8 @@ bool core_info_get_core_lock(const char *core_path, bool validate_path) return false; /* Get lock file path */ - _len = strlcpy(lock_file_path, core_file_path, - sizeof(lock_file_path)); - strlcpy(lock_file_path + _len, - ".lck", - sizeof(lock_file_path) - _len); + fill_pathname(lock_file_path, core_file_path, + ".lck", sizeof(lock_file_path)); /* Check whether lock file exists */ is_locked = path_is_valid(lock_file_path); @@ -3022,7 +2991,6 @@ bool core_info_set_core_standalone_exempt(const char *core_path, bool exempt) /* Static platforms do not support the contentless * cores menu */ #if defined(HAVE_DYNAMIC) - size_t _len; core_info_t *core_info = NULL; char exempt_file_path[PATH_MAX_LENGTH]; @@ -3034,11 +3002,8 @@ bool core_info_set_core_standalone_exempt(const char *core_path, bool exempt) return false; /* Get 'standalone exempt' file path */ - _len = strlcpy(exempt_file_path, core_info->path, - sizeof(exempt_file_path)); - strlcpy(exempt_file_path + _len, - ".lsae", - sizeof(exempt_file_path) - _len); + fill_pathname(exempt_file_path, core_info->path, + ".lsae", sizeof(exempt_file_path)); /* Create or delete 'standalone exempt' file, as required */ if (core_info_update_core_aux_file(exempt_file_path, exempt)) @@ -3062,7 +3027,6 @@ bool core_info_get_core_standalone_exempt(const char *core_path) /* Static platforms do not support the contentless * cores menu */ #if defined(HAVE_DYNAMIC) - size_t _len; core_info_t *core_info = NULL; char exempt_file_path[PATH_MAX_LENGTH]; @@ -3074,11 +3038,8 @@ bool core_info_get_core_standalone_exempt(const char *core_path) return false; /* Get 'standalone exempt' file path */ - _len = strlcpy(exempt_file_path, core_info->path, - sizeof(exempt_file_path)); - strlcpy(exempt_file_path + _len, - ".lsae", - sizeof(exempt_file_path) - _len); + fill_pathname(exempt_file_path, core_info->path, + ".lsae", sizeof(exempt_file_path)); /* Check whether 'standalone exempt' file exists */ if (path_is_valid(exempt_file_path)) diff --git a/core_option_manager.c b/core_option_manager.c index ec7e56b982..d0f6896d95 100644 --- a/core_option_manager.c +++ b/core_option_manager.c @@ -754,8 +754,8 @@ static bool core_option_manager_parse_variable( const char *value = option->vals->elems[i].data; uint32_t value_hash = *((uint32_t*)option->vals->elems[i].userdata); - if ((value_hash == entry_value_hash) && - string_is_equal(value, entry->value)) + if ( (value_hash == entry_value_hash) + && string_is_equal(value, entry->value)) { option->index = i; break; @@ -798,7 +798,7 @@ core_option_manager_t *core_option_manager_new_vars( const struct retro_variable *vars) { const struct retro_variable *var = NULL; - size_t size = 0; + size_t _len = 0; config_file_t *config_src = NULL; core_option_manager_t *opt = NULL; @@ -837,29 +837,29 @@ core_option_manager_t *core_option_manager_new_vars( /* Get number of variables */ for (var = vars; var->key && var->value; var++) - size++; + _len++; - if (size == 0) + if (_len == 0) goto error; /* Create options array */ - if (!(opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts)))) + if (!(opt->opts = (struct core_option*)calloc(_len, sizeof(*opt->opts)))) goto error; - opt->size = size; - size = 0; + opt->size = _len; + _len = 0; /* Parse each variable */ - for (var = vars; var->key && var->value; size++, var++) + for (var = vars; var->key && var->value; _len++, var++) { - if (core_option_manager_parse_variable(opt, size, var, config_src)) + if (core_option_manager_parse_variable(opt, _len, var, config_src)) { - size_t _len = 0; + size_t __len = 0; /* If variable is read correctly, add it to * the map */ char address[256]; - address[ _len] = '#'; - address[++_len] = '\0'; + address[ __len] = '#'; + address[++__len] = '\0'; /* Address string is normally: * @@ -869,10 +869,10 @@ core_option_manager_t *core_option_manager_new_vars( * so we could just set the address to * - but for consistency with * 'modern' options, we apply the tag regardless */ - strlcpy(address + _len, var->key, sizeof(address) - _len); + strlcpy(address + __len, var->key, sizeof(address) - __len); if (!nested_list_add_item(opt->option_map, - address, NULL, (const void*)&opt->opts[size])) + address, NULL, (const void*)&opt->opts[_len])) goto error; } else @@ -928,9 +928,9 @@ static bool core_option_manager_parse_option( * match an entry in the categories array * > Category key cannot contain a map delimiter * character */ - if (opt->cats && - !string_is_empty(category_key) && - !strstr(category_key, ":")) + if ( opt->cats + && !string_is_empty(category_key) + && !strstr(category_key, ":")) { for (i = 0; i < opt->cats_size; i++) { @@ -960,8 +960,8 @@ static bool core_option_manager_parse_option( { /* If option has a category, option key * cannot contain a map delimiter character */ - if (!string_is_empty(option->category_key) && - strstr(key, ":")) + if ( !string_is_empty(option->category_key) + && strstr(key, ":")) return false; option->key = strdup(key); @@ -1085,12 +1085,12 @@ core_option_manager_t *core_option_manager_new( struct retro_core_option_v2_category *option_cats = NULL; struct retro_core_option_v2_definition *option_defs = NULL; size_t cats_size = 0; - size_t size = 0; + size_t _len = 0; config_file_t *config_src = NULL; core_option_manager_t *opt = NULL; - if (!options_v2 || - !options_v2->definitions) + if ( !options_v2 + || !options_v2->definitions) return NULL; option_cats = options_v2->categories; @@ -1139,15 +1139,15 @@ core_option_manager_t *core_option_manager_new( for (option_def = option_defs; option_def->key && option_def->desc && option_def->values[0].value; option_def++) - size++; + _len++; - if (size == 0) + if (_len == 0) goto error; /* Create categories array */ if (cats_size > 0) { - if (!(opt->cats = (struct core_category*)calloc(size, + if (!(opt->cats = (struct core_category*)calloc(_len, sizeof(*opt->cats)))) goto error; @@ -1171,23 +1171,23 @@ core_option_manager_t *core_option_manager_new( } /* Create options array */ - if (!(opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts)))) + if (!(opt->opts = (struct core_option*)calloc(_len, sizeof(*opt->opts)))) goto error; - opt->size = size; - size = 0; + opt->size = _len; + _len = 0; /* Parse each option * > Note: 'option_def->info == NULL' is valid */ for (option_def = option_defs; option_def->key && option_def->desc && option_def->values[0].value; - size++, option_def++) + _len++, option_def++) { - if (core_option_manager_parse_option(opt, size, option_def, config_src)) + if (core_option_manager_parse_option(opt, _len, option_def, config_src)) { /* If option is read correctly, add it to * the map */ - const char *category_key = opt->opts[size].category_key; + const char *category_key = opt->opts[_len].category_key; char address[256]; /* Address string is nominally: @@ -1197,23 +1197,23 @@ core_option_manager_t *core_option_manager_new( * collisions */ if (string_is_empty(category_key)) { - size_t _len = 0; - address[ _len] = '#'; - address[++_len] = '\0'; - strlcpy(address + _len, option_def->key, sizeof(address) - _len); + size_t __len = 0; + address[ __len] = '#'; + address[++__len] = '\0'; + strlcpy(address + __len, option_def->key, sizeof(address) - __len); } else { - size_t _len = strlcpy(address, category_key, sizeof(address)); - address[ _len] = ':'; - address[++_len] = '#'; - address[++_len] = '\0'; - strlcpy(address + _len, option_def->key, sizeof(address) - _len); + size_t __len = strlcpy(address, category_key, sizeof(address) - 3); + address[ __len] = ':'; + address[++__len] = '#'; + address[++__len] = '\0'; + strlcpy(address + __len, option_def->key, sizeof(address) - __len); } if (!nested_list_add_item(opt->option_map, address, ":", - (const void*)&opt->opts[size])) + (const void*)&opt->opts[_len])) goto error; } else diff --git a/core_updater_list.c b/core_updater_list.c index 08af5e02e2..baec5f3989 100644 --- a/core_updater_list.c +++ b/core_updater_list.c @@ -330,7 +330,7 @@ bool core_updater_list_get_core( static bool core_updater_list_set_date( core_updater_list_entry_t *entry, const char *date_str) { - char *tok, *save; + char *tok, *save = NULL; char *elem0 = NULL; char *elem1 = NULL; char *elem2 = NULL; @@ -784,7 +784,7 @@ bool core_updater_list_parse_network_data( const char *network_buildbot_url, const char *data, size_t len) { - char *tok, *save; + char *tok, *save = NULL; unsigned list_size = 0; char *data_buf = NULL; @@ -817,12 +817,12 @@ bool core_updater_list_parse_network_data( for (tok = strtok_r(data_buf, "\n", &save); tok; tok = strtok_r(NULL, "\n", &save)) { - char *tok2, *save2; - char *elem0 = NULL; - char *elem1 = NULL; - char *elem2 = NULL; - char *line_cpy = NULL; - const char *line = tok; + char *tok2, *save2 = NULL; + char *elem0 = NULL; + char *elem1 = NULL; + char *elem2 = NULL; + char *line_cpy = NULL; + const char *line = tok; if (string_is_empty(line)) continue; diff --git a/cores/dynamic_dummy.c b/cores/dynamic_dummy.c index fc23656bfd..e1c2fbdb48 100644 --- a/cores/dynamic_dummy.c +++ b/cores/dynamic_dummy.c @@ -54,8 +54,8 @@ void retro_unload_game(void) { libretro_dummy_retro_unload_game(); } unsigned retro_get_region(void) { return libretro_dummy_retro_get_region(); } bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num) { return libretro_dummy_retro_load_game_special(type, info, num); } size_t retro_serialize_size(void) { return libretro_dummy_retro_serialize_size(); } -bool retro_serialize(void *data, size_t size) { return libretro_dummy_retro_serialize(data, size); } -bool retro_unserialize(const void *data, size_t size) { return libretro_dummy_retro_unserialize(data, size); } +bool retro_serialize(void *data, size_t len) { return libretro_dummy_retro_serialize(data, len); } +bool retro_unserialize(const void *data, size_t len) { return libretro_dummy_retro_unserialize(data, len); } void *retro_get_memory_data(unsigned id) { return libretro_dummy_retro_get_memory_data(id); } size_t retro_get_memory_size(unsigned id) { return libretro_dummy_retro_get_memory_size(id); } void retro_cheat_reset(void) { libretro_dummy_retro_cheat_reset(); } @@ -119,13 +119,6 @@ unsigned libretro_dummy_retro_api_version(void) return RETRO_API_VERSION; } -void libretro_dummy_retro_set_controller_port_device( - unsigned port, unsigned device) -{ - (void)port; - (void)device; -} - void libretro_dummy_retro_get_system_info( struct retro_system_info *info) { @@ -197,9 +190,6 @@ void libretro_dummy_retro_set_video_refresh(retro_video_refresh_t cb) dummy_video_cb = cb; } -void libretro_dummy_retro_reset(void) -{} - void libretro_dummy_retro_run(void) { dummy_input_poll_cb(); @@ -209,66 +199,22 @@ void libretro_dummy_retro_run(void) /* This should never be called, it's only used as a placeholder. */ bool libretro_dummy_retro_load_game(const struct retro_game_info *info) { - (void)info; return false; } -void libretro_dummy_retro_unload_game(void) -{} - -unsigned libretro_dummy_retro_get_region(void) -{ - return RETRO_REGION_NTSC; -} - +void libretro_dummy_retro_set_controller_port_device( + unsigned port, unsigned device) { } +void libretro_dummy_retro_reset(void) { } +unsigned libretro_dummy_retro_get_region(void) { return RETRO_REGION_NTSC; } +void libretro_dummy_retro_unload_game(void) { } bool libretro_dummy_retro_load_game_special(unsigned type, - const struct retro_game_info *info, size_t num) -{ - (void)type; - (void)info; - (void)num; - return false; -} - -size_t libretro_dummy_retro_serialize_size(void) -{ - return 0; -} - -bool libretro_dummy_retro_serialize(void *data, size_t size) -{ - (void)data; - (void)size; - return false; -} - + const struct retro_game_info *info, size_t num) { return false; } +size_t libretro_dummy_retro_serialize_size(void) { return 0; } +bool libretro_dummy_retro_serialize(void *data, size_t len) { return false; } bool libretro_dummy_retro_unserialize(const void *data, - size_t size) -{ - (void)data; - (void)size; - return false; -} - -void *libretro_dummy_retro_get_memory_data(unsigned id) -{ - (void)id; - return NULL; -} - -size_t libretro_dummy_retro_get_memory_size(unsigned id) -{ - (void)id; - return 0; -} - -void libretro_dummy_retro_cheat_reset(void) -{} - + size_t len) { return false; } +void *libretro_dummy_retro_get_memory_data(unsigned id) { return NULL; } +size_t libretro_dummy_retro_get_memory_size(unsigned id) { return 0; } +void libretro_dummy_retro_cheat_reset(void) { } void libretro_dummy_retro_cheat_set(unsigned idx, - bool enabled, const char *code) -{ - (void)idx; - (void)enabled; - (void)code; -} + bool enabled, const char *code) { } diff --git a/cores/internal_cores.h b/cores/internal_cores.h index 08e916d63e..d5f9ba0125 100644 --- a/cores/internal_cores.h +++ b/cores/internal_cores.h @@ -59,9 +59,9 @@ void libretro_dummy_retro_run(void); size_t libretro_dummy_retro_serialize_size(void); -bool libretro_dummy_retro_serialize(void *data, size_t size); +bool libretro_dummy_retro_serialize(void *s, size_t len); -bool libretro_dummy_retro_unserialize(const void *data, size_t size); +bool libretro_dummy_retro_unserialize(const void *s, size_t len); void libretro_dummy_retro_cheat_reset(void); @@ -113,9 +113,9 @@ void libretro_ffmpeg_retro_run(void); size_t libretro_ffmpeg_retro_serialize_size(void); -bool libretro_ffmpeg_retro_serialize(void *data, size_t size); +bool libretro_ffmpeg_retro_serialize(void *s, size_t len); -bool libretro_ffmpeg_retro_unserialize(const void *data, size_t size); +bool libretro_ffmpeg_retro_unserialize(const void *s, size_t len); void libretro_ffmpeg_retro_cheat_reset(void); @@ -169,9 +169,9 @@ void libretro_mpv_retro_run(void); size_t libretro_mpv_retro_serialize_size(void); -bool libretro_mpv_retro_serialize(void *data, size_t size); +bool libretro_mpv_retro_serialize(void *data, size_t len); -bool libretro_mpv_retro_unserialize(const void *data, size_t size); +bool libretro_mpv_retro_unserialize(const void *data, size_t len); void libretro_mpv_retro_cheat_reset(void); @@ -225,9 +225,9 @@ void libretro_imageviewer_retro_run(void); size_t libretro_imageviewer_retro_serialize_size(void); -bool libretro_imageviewer_retro_serialize(void *data, size_t size); +bool libretro_imageviewer_retro_serialize(void *data, size_t len); -bool libretro_imageviewer_retro_unserialize(const void *data, size_t size); +bool libretro_imageviewer_retro_unserialize(const void *data, size_t len); void libretro_imageviewer_retro_cheat_reset(void); @@ -281,9 +281,9 @@ void libretro_netretropad_retro_run(void); size_t libretro_netretropad_retro_serialize_size(void); -bool libretro_netretropad_retro_serialize(void *data, size_t size); +bool libretro_netretropad_retro_serialize(void *data, size_t len); -bool libretro_netretropad_retro_unserialize(const void *data, size_t size); +bool libretro_netretropad_retro_unserialize(const void *data, size_t len); void libretro_netretropad_retro_cheat_reset(void); @@ -337,9 +337,9 @@ void libretro_videoprocessor_retro_run(void); size_t libretro_videoprocessor_retro_serialize_size(void); -bool libretro_videoprocessor_retro_serialize(void *data, size_t size); +bool libretro_videoprocessor_retro_serialize(void *data, size_t len); -bool libretro_videoprocessor_retro_unserialize(const void *data, size_t size); +bool libretro_videoprocessor_retro_unserialize(const void *data, size_t len); void libretro_videoprocessor_retro_cheat_reset(void); diff --git a/cores/libretro-ffmpeg/ffmpeg_core.c b/cores/libretro-ffmpeg/ffmpeg_core.c index 03a1525c95..374d0a7072 100644 --- a/cores/libretro-ffmpeg/ffmpeg_core.c +++ b/cores/libretro-ffmpeg/ffmpeg_core.c @@ -222,14 +222,14 @@ static void ass_msg_cb(int level, const char *fmt, va_list args, void *data) } #endif -static void append_attachment(const uint8_t *data, size_t size) +static void append_attachment(const uint8_t *data, size_t len) { attachments = (struct attachment*)av_realloc( attachments, (attachments_size + 1) * sizeof(*attachments)); - attachments[attachments_size].data = (uint8_t*)av_malloc(size); - attachments[attachments_size].size = size; - memcpy(attachments[attachments_size].data, data, size); + attachments[attachments_size].data = (uint8_t*)av_malloc(len); + attachments[attachments_size].size = len; + memcpy(attachments[attachments_size].data, data, len); attachments_size++; } @@ -2278,41 +2278,12 @@ size_t CORE_PREFIX(retro_serialize_size)(void) return 0; } -bool CORE_PREFIX(retro_serialize)(void *data, size_t size) -{ - (void)data; - (void)size; - return false; -} - -bool CORE_PREFIX(retro_unserialize)(const void *data, size_t size) -{ - (void)data; - (void)size; - return false; -} - -void *CORE_PREFIX(retro_get_memory_data)(unsigned id) -{ - (void)id; - return NULL; -} - -size_t CORE_PREFIX(retro_get_memory_size)(unsigned id) -{ - (void)id; - return 0; -} - -void CORE_PREFIX(retro_cheat_reset)(void) -{} - -void CORE_PREFIX(retro_cheat_set)(unsigned index, bool enabled, const char *code) -{ - (void)index; - (void)enabled; - (void)code; -} +bool CORE_PREFIX(retro_serialize)(void *data, size_t len) { return false; } +bool CORE_PREFIX(retro_unserialize)(const void *data, size_t len) { return false; } +void *CORE_PREFIX(retro_get_memory_data)(unsigned id) { return NULL; } +size_t CORE_PREFIX(retro_get_memory_size)(unsigned id) { return 0; } +void CORE_PREFIX(retro_cheat_reset)(void) { } +void CORE_PREFIX(retro_cheat_set)(unsigned a, bool b, const char *c) { } #if defined(LIBRETRO_SWITCH) diff --git a/cores/libretro-imageviewer/image_core.c b/cores/libretro-imageviewer/image_core.c index f8fc8f5cc5..d9f92c7966 100644 --- a/cores/libretro-imageviewer/image_core.c +++ b/cores/libretro-imageviewer/image_core.c @@ -181,10 +181,6 @@ void IMAGE_CORE_PREFIX(retro_set_video_refresh)(retro_video_refresh_t cb) IMAGE_CORE_PREFIX(video_cb) = cb; } -void IMAGE_CORE_PREFIX(retro_set_audio_sample)(retro_audio_sample_t unused) -{ -} - void IMAGE_CORE_PREFIX(retro_set_audio_sample_batch)(retro_audio_sample_batch_t cb) { IMAGE_CORE_PREFIX(audio_batch_cb) = cb; @@ -200,41 +196,14 @@ void IMAGE_CORE_PREFIX(retro_set_input_state)(retro_input_state_t cb) IMAGE_CORE_PREFIX(input_state_cb) = cb; } -void IMAGE_CORE_PREFIX(retro_set_controller_port_device)(unsigned a, unsigned b) -{ -} - -void IMAGE_CORE_PREFIX(retro_reset)(void) -{ - image_uploaded = false; -} - -size_t IMAGE_CORE_PREFIX(retro_serialize_size)(void) -{ - return 0; -} - -bool IMAGE_CORE_PREFIX(retro_serialize)(void *data, size_t size) -{ - (void)data; - (void)size; - return false; -} - -bool IMAGE_CORE_PREFIX(retro_unserialize)(const void *data, size_t size) -{ - (void)data; - (void)size; - return false; -} - -void IMAGE_CORE_PREFIX(retro_cheat_reset)(void) -{ -} - -void IMAGE_CORE_PREFIX(retro_cheat_set)(unsigned a, bool b, const char * c) -{ -} +void IMAGE_CORE_PREFIX(retro_set_audio_sample)(retro_audio_sample_t unused) { } +void IMAGE_CORE_PREFIX(retro_set_controller_port_device)(unsigned a, unsigned b) { } +void IMAGE_CORE_PREFIX(retro_reset)(void) { image_uploaded = false; } +size_t IMAGE_CORE_PREFIX(retro_serialize_size)(void) { return 0; } +bool IMAGE_CORE_PREFIX(retro_serialize)(void *data, size_t len) { return false; } +bool IMAGE_CORE_PREFIX(retro_unserialize)(const void *s, size_t len) { return false; } +void IMAGE_CORE_PREFIX(retro_cheat_reset)(void) { } +void IMAGE_CORE_PREFIX(retro_cheat_set)(unsigned a, bool b, const char * c) { } static bool imageviewer_load(const char *path, int image_index) { @@ -307,10 +276,12 @@ bool IMAGE_CORE_PREFIX(retro_load_game)(const struct retro_game_info *info) return true; } -bool IMAGE_CORE_PREFIX(retro_load_game_special)(unsigned a, const struct retro_game_info *b, size_t c) -{ - return false; -} +bool IMAGE_CORE_PREFIX(retro_load_game_special)(unsigned a, + const struct retro_game_info *b, size_t c) { return false; } +unsigned IMAGE_CORE_PREFIX(retro_get_region)(void) { return RETRO_REGION_NTSC; } +void *IMAGE_CORE_PREFIX(retro_get_memory_data)(unsigned id) { return NULL; } +size_t IMAGE_CORE_PREFIX(retro_get_memory_size)(unsigned id) { return 0; } + void IMAGE_CORE_PREFIX(retro_unload_game)(void) { @@ -319,21 +290,6 @@ void IMAGE_CORE_PREFIX(retro_unload_game)(void) image_height = 0; } -unsigned IMAGE_CORE_PREFIX(retro_get_region)(void) -{ - return RETRO_REGION_NTSC; -} - -void *IMAGE_CORE_PREFIX(retro_get_memory_data)(unsigned id) -{ - return NULL; -} - -size_t IMAGE_CORE_PREFIX(retro_get_memory_size)(unsigned id) -{ - return 0; -} - void IMAGE_CORE_PREFIX(retro_run)(void) { bool first_image = false; diff --git a/cores/libretro-mpv/mpv-libretro.c b/cores/libretro-mpv/mpv-libretro.c index ffb5212a52..9c7f2960cf 100644 --- a/cores/libretro-mpv/mpv-libretro.c +++ b/cores/libretro-mpv/mpv-libretro.c @@ -61,7 +61,7 @@ static char *filepath = NULL; static volatile int frame_queue = 0; -void on_mpv_redraw(void *cb_ctx) +static void on_mpv_redraw(void *cb_ctx) { frame_queue++; } @@ -395,10 +395,6 @@ void CORE_PREFIX(retro_set_video_refresh)(retro_video_refresh_t cb) CORE_PREFIX(video_cb) = cb; } -void CORE_PREFIX(retro_reset)(void) -{ -} - static void audio_callback(double fps) { /* Obtain len samples to reduce lag. */ @@ -587,20 +583,9 @@ void CORE_PREFIX(retro_run)(void) } /* No save-state support */ -size_t CORE_PREFIX(retro_serialize_size)(void) -{ - return 0; -} - -bool CORE_PREFIX(retro_serialize)(void *data_, size_t size) -{ - return true; -} - -bool CORE_PREFIX(retro_unserialize)(const void *data_, size_t size) -{ - return true; -} +size_t CORE_PREFIX(retro_serialize_size)(void) { return 0; } +bool CORE_PREFIX(retro_serialize)(void *s, size_t len) { return true; } +bool CORE_PREFIX(retro_unserialize)(const void *s, size_t len) { return true; } bool CORE_PREFIX(retro_load_game)(const struct retro_game_info *info) { @@ -654,39 +639,17 @@ bool CORE_PREFIX(retro_load_game)(const struct retro_game_info *info) return true; } -bool CORE_PREFIX(retro_load_game_special)(unsigned type, const struct retro_game_info *info, - size_t num) -{ - return false; -} - void CORE_PREFIX(retro_unload_game)(void) { free(filepath); filepath = NULL; } -unsigned CORE_PREFIX(retro_get_region)(void) -{ - return RETRO_REGION_NTSC; -} - -void *CORE_PREFIX(retro_get_memory_data)(unsigned id) -{ - return NULL; -} - -size_t CORE_PREFIX(retro_get_memory_size)(unsigned id) -{ - return 0; -} - -void CORE_PREFIX(retro_cheat_reset)(void) -{} - -void CORE_PREFIX(retro_cheat_set)(unsigned index, bool enabled, const char *code) -{ - (void)index; - (void)enabled; - (void)code; -} +bool CORE_PREFIX(retro_load_game_special)(unsigned type, const struct retro_game_info *info, + size_t num) { return false; } +unsigned CORE_PREFIX(retro_get_region)(void) { return RETRO_REGION_NTSC; } +void *CORE_PREFIX(retro_get_memory_data)(unsigned id) { return NULL; } +size_t CORE_PREFIX(retro_get_memory_size)(unsigned id) { return 0; } +void CORE_PREFIX(retro_cheat_reset)(void) { } +void CORE_PREFIX(retro_cheat_set)(unsigned a, bool b, const char *c) { } +void CORE_PREFIX(retro_reset)(void) { } diff --git a/cores/libretro-net-retropad/net_retropad_core.c b/cores/libretro-net-retropad/net_retropad_core.c index 4584cf0a28..4eacb44191 100644 --- a/cores/libretro-net-retropad/net_retropad_core.c +++ b/cores/libretro-net-retropad/net_retropad_core.c @@ -255,7 +255,7 @@ typedef struct char *message; } ITifJSONContext; -static bool ITifJSONObjectEndHandler(void* context) +static bool ITifJSONObjectEndHandler(void *context) { ITifJSONContext *pCtx = (ITifJSONContext*)context; @@ -278,7 +278,7 @@ static bool ITifJSONObjectEndHandler(void* context) return true; } -static bool ITifJSONObjectMemberHandler(void* context, const char *pValue, size_t length) +static bool ITifJSONObjectMemberHandler(void* context, const char *s, size_t len) { ITifJSONContext *pCtx = (ITifJSONContext*)context; @@ -286,41 +286,41 @@ static bool ITifJSONObjectMemberHandler(void* context, const char *pValue, size_ if (pCtx->current_entry_str_val) return false; - if (length) + if (len) { - if (string_is_equal(pValue, "expected_button")) - pCtx->current_entry_uint_val = &pCtx->expected_button; - else if (string_is_equal(pValue, "message")) - pCtx->current_entry_str_val = &pCtx->message; /* ignore unknown members */ + if (string_is_equal(s, "expected_button")) + pCtx->current_entry_uint_val = &pCtx->expected_button; + else if (string_is_equal(s, "message")) + pCtx->current_entry_str_val = &pCtx->message; } return true; } -static bool ITifJSONNumberHandler(void* context, const char *pValue, size_t length) +static bool ITifJSONNumberHandler(void* context, const char *s, size_t len) { ITifJSONContext *pCtx = (ITifJSONContext*)context; - if (pCtx->current_entry_uint_val && length && !string_is_empty(pValue)) - *pCtx->current_entry_uint_val = string_to_unsigned(pValue); /* ignore unknown members */ + if (pCtx->current_entry_uint_val && len && !string_is_empty(s)) + *pCtx->current_entry_uint_val = string_to_unsigned(s); pCtx->current_entry_uint_val = NULL; return true; } -static bool ITifJSONStringHandler(void* context, const char *pValue, size_t length) +static bool ITifJSONStringHandler(void* context, const char *s, size_t len) { ITifJSONContext *pCtx = (ITifJSONContext*)context; - if (pCtx->current_entry_str_val && length && !string_is_empty(pValue)) + if (pCtx->current_entry_str_val && len && !string_is_empty(s)) { if (*pCtx->current_entry_str_val) free(*pCtx->current_entry_str_val); - *pCtx->current_entry_str_val = strdup(pValue); + *pCtx->current_entry_str_val = strdup(s); } /* ignore unknown members */ @@ -430,7 +430,6 @@ end: static void sensors_init(void) { - struct retro_sensor_interface sensor_interface = {0}; if (NETRETROPAD_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE, &sensor_interface)) { @@ -563,11 +562,7 @@ unsigned NETRETROPAD_CORE_PREFIX(retro_api_version)(void) } void NETRETROPAD_CORE_PREFIX(retro_set_controller_port_device)( - unsigned port, unsigned device) -{ - (void)port; - (void)device; -} + unsigned port, unsigned device) { } void NETRETROPAD_CORE_PREFIX(retro_get_system_info)( struct retro_system_info *info) @@ -593,7 +588,7 @@ void NETRETROPAD_CORE_PREFIX(retro_get_system_av_info)( } static void NETRETROPAD_CORE_PREFIX(update_keyboard_cb)(bool down, unsigned keycode, - uint32_t character, uint16_t key_modifiers) + uint32_t character, uint16_t key_modifiers) { struct retro_message message; char buf[NAME_MAX_LENGTH]; @@ -601,7 +596,8 @@ static void NETRETROPAD_CORE_PREFIX(update_keyboard_cb)(bool down, unsigned keyc if (keycode < RETROK_LAST) { keyboard_state[keycode] = down ? true : false; - if (down && ((keycode == RETROK_a && keyboard_state[RETROK_b]) || (keycode == RETROK_b && keyboard_state[RETROK_a]))) + if (down && ((keycode == RETROK_a && keyboard_state[RETROK_b]) + || (keycode == RETROK_b && keyboard_state[RETROK_a]))) flip_screen(); /* Message for the keypresses not shown as actual keys, just placeholder blocks */ if ((keycode == 0) || @@ -634,10 +630,9 @@ static unsigned get_pixel_coordinate(int val, unsigned dimension) static unsigned set_pixel(unsigned x, unsigned y, unsigned color) { unsigned old_color; - uint16_t *pixel; - pixel = frame_buf + y * 320 + x; + uint16_t *pixel = frame_buf + y * 320 + x; old_color = *pixel; - *pixel = color; + *pixel = color; return old_color; } @@ -728,7 +723,7 @@ static void retropad_update_input(void) pointer_y = (int16_t)state; } } - + /* Do not send extra descriptor state - RA side is not prepared to receive it */ if (i>1) continue; @@ -849,7 +844,6 @@ static void netretropad_check_variables(void) mouse_type = NETRETROPAD_LIGHTGUN_OLD; else mouse_type = 0; - } void NETRETROPAD_CORE_PREFIX(retro_set_audio_sample)(retro_audio_sample_t cb) @@ -1035,14 +1029,12 @@ void NETRETROPAD_CORE_PREFIX(retro_run)(void) sensor_item_colors[median_index] = (uint16_t)(fabsf(32*4*value)) << 11; } } - + /* Button values for sensor test screen, since they do not follow any pattern, it is * * provided as a direct list. */ if (mouse_type == NETRETROPAD_MOUSE) { - int offset; - - offset = DESC_OFFSET(&mouse, 0, 0, RETRO_DEVICE_ID_MOUSE_LEFT); + int offset = DESC_OFFSET(&mouse, 0, 0, RETRO_DEVICE_ID_MOUSE_LEFT); sensor_item_colors[80] = mouse.value[offset] ? 0xA000 : 0x0000; offset = DESC_OFFSET(&mouse, 0, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE); @@ -1062,7 +1054,7 @@ void NETRETROPAD_CORE_PREFIX(retro_run)(void) offset = DESC_OFFSET(&mouse, 0, 0, RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP); sensor_item_colors[86] = mouse.value[offset] ? 0xA000 : 0x0000; - + offset = DESC_OFFSET(&mouse, 0, 0, RETRO_DEVICE_ID_MOUSE_BUTTON_4); sensor_item_colors[88] = mouse.value[offset] ? 0xA000 : 0x0000; @@ -1072,9 +1064,7 @@ void NETRETROPAD_CORE_PREFIX(retro_run)(void) } else if (mouse_type == NETRETROPAD_LIGHTGUN) { - int offset; - - offset = DESC_OFFSET(&lightgun, 0, 0, RETRO_DEVICE_ID_LIGHTGUN_AUX_A); + int offset = DESC_OFFSET(&lightgun, 0, 0, RETRO_DEVICE_ID_LIGHTGUN_AUX_A); sensor_item_colors[70] = lightgun.value[offset] ? 0xA000 : 0x0000; offset = DESC_OFFSET(&lightgun, 0, 0, RETRO_DEVICE_ID_LIGHTGUN_AUX_B); @@ -1094,7 +1084,7 @@ void NETRETROPAD_CORE_PREFIX(retro_run)(void) offset = DESC_OFFSET(&lightgun, 0, 0, RETRO_DEVICE_ID_LIGHTGUN_SELECT); sensor_item_colors[76] = lightgun.value[offset] ? 0xA000 : 0x0000; - + offset = DESC_OFFSET(&lightgun, 0, 0, RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN); sensor_item_colors[77] = lightgun.value[offset] ? 0xA000 : 0x0000; @@ -1113,9 +1103,7 @@ void NETRETROPAD_CORE_PREFIX(retro_run)(void) } else if (mouse_type == NETRETROPAD_POINTER) { - int offset; - - offset = DESC_OFFSET(&pointer, 0, 0, RETRO_DEVICE_ID_POINTER_PRESSED); + int offset = DESC_OFFSET(&pointer, 0, 0, RETRO_DEVICE_ID_POINTER_PRESSED); sensor_item_colors[104] = pointer.value[offset] ? 0xA000 : 0x0000; offset = DESC_OFFSET(&pointer, 0, 1, RETRO_DEVICE_ID_POINTER_PRESSED); @@ -1390,7 +1378,7 @@ void NETRETROPAD_CORE_PREFIX(retro_run)(void) pointer_prev_y = pointer_y_coord; } } - + NETRETROPAD_CORE_PREFIX(video_cb)(frame_buf, 320, 240, 640); retro_sleep(4); } @@ -1417,52 +1405,23 @@ bool NETRETROPAD_CORE_PREFIX(retro_load_game)(const struct retro_game_info *info return true; } -void NETRETROPAD_CORE_PREFIX(retro_unload_game)(void) -{} - +void NETRETROPAD_CORE_PREFIX(retro_unload_game)(void) { } unsigned NETRETROPAD_CORE_PREFIX(retro_get_region)(void) { return RETRO_REGION_NTSC; } - bool NETRETROPAD_CORE_PREFIX(retro_load_game_special)(unsigned type, - const struct retro_game_info *info, size_t num) -{ - (void)type; - (void)info; - (void)num; - return false; -} - + const struct retro_game_info *info, size_t num) { return false; } size_t NETRETROPAD_CORE_PREFIX(retro_serialize_size)(void) { return 0; } - -bool NETRETROPAD_CORE_PREFIX(retro_serialize)(void *data, size_t size) -{ - (void)data; - (void)size; - return false; -} - +bool NETRETROPAD_CORE_PREFIX(retro_serialize)(void *data, + size_t len) { return false; } bool NETRETROPAD_CORE_PREFIX(retro_unserialize)(const void *data, - size_t size) -{ - (void)data; - (void)size; - return false; -} + size_t len) { return false; } +size_t NETRETROPAD_CORE_PREFIX(retro_get_memory_size)( + unsigned id) { return 0; } +void NETRETROPAD_CORE_PREFIX(retro_cheat_reset)(void) { } +void NETRETROPAD_CORE_PREFIX(retro_cheat_set)(unsigned idx, + bool enabled, const char *code) { } void *NETRETROPAD_CORE_PREFIX(retro_get_memory_data)(unsigned id) { - (void)id; return NULL; } -size_t NETRETROPAD_CORE_PREFIX(retro_get_memory_size)(unsigned id) { return 0; } - -void NETRETROPAD_CORE_PREFIX(retro_cheat_reset)(void) -{} - -void NETRETROPAD_CORE_PREFIX(retro_cheat_set)(unsigned idx, - bool enabled, const char *code) -{ - (void)idx; - (void)enabled; - (void)code; -} diff --git a/cores/libretro-video-processor/video_processor_v4l2.c b/cores/libretro-video-processor/video_processor_v4l2.c index dca3412f1b..34a40a3743 100644 --- a/cores/libretro-video-processor/video_processor_v4l2.c +++ b/cores/libretro-video-processor/video_processor_v4l2.c @@ -70,6 +70,38 @@ struct v4l2_capbuf size_t len; }; +struct v4l2_resolution +{ + int width; + int height; +}; + +struct v4l2_resolution v4l2_resolutions[] = +{ + //4:3 + {160,120}, + {320,240}, + {480,320}, + {640,480}, + {720,480}, + {800,600}, + {960,720}, + {1024,768}, + {1280,960}, + {1440,1050}, + {1440,1080}, + {1600,1200}, + {1920,1440}, + //16:9 + {640,360}, + {960,540}, + {1280,720}, + {1600,900}, + {1920,1080}, + {1920,1200}, + {2560,1440}, + {3840,2160} +}; /* * Video capture state */ @@ -84,6 +116,7 @@ static struct v4l2_buffer video_buf; static uint8_t v4l2_ncapbuf_target; static size_t v4l2_ncapbuf; static struct v4l2_capbuf v4l2_capbuf[VIDEO_BUFFERS_MAX]; +struct v4l2_capability caps; static float dummy_pos=0; @@ -92,6 +125,7 @@ static uint32_t video_cap_width; static uint32_t video_cap_height; static uint32_t video_out_height; static char video_capture_mode[ENVVAR_BUFLEN]; +static char video_capture_resolution[ENVVAR_BUFLEN]; static char video_output_mode[ENVVAR_BUFLEN]; static char video_frame_times[ENVVAR_BUFLEN]; @@ -143,23 +177,17 @@ static void audio_callback(void) } } -static void -audio_set_state(bool enable) -{ -} +static void audio_set_state(bool enable) { } #endif -static void -appendstr(char *dst, const char *src, size_t dstsize) +static void appendstr(char *s, const char *in, size_t len) { - size_t resid = dstsize - (strlen(dst) + 1); - if (resid == 0) - return; - strncat(dst, src, resid); + size_t resid = len - (strlen(s) + 1); + if (resid != 0) + strncat(s, in, resid); } -static void -enumerate_video_devices(char *buf, size_t buflen) +static void enumerate_video_devices(char *s, size_t len) { #ifdef HAVE_UDEV int ndevs; @@ -170,9 +198,8 @@ enumerate_video_devices(char *buf, size_t buflen) struct udev *udev = NULL; #endif - memset(buf, 0, buflen); - - appendstr(buf, "Video capture device; ", buflen); + memset(s, 0, len); + appendstr(s, "Video capture device; ", len); #ifdef HAVE_UDEV /* Get a list of devices matching the "video4linux" subsystem from udev */ @@ -214,8 +241,8 @@ enumerate_video_devices(char *buf, size_t buflen) if (strncmp(name, "/dev/video", strlen("/dev/video")) == 0) { if (ndevs > 0) - appendstr(buf, "|", buflen); - appendstr(buf, name, buflen); + appendstr(s, "|", len); + appendstr(s, name, len); ndevs++; } @@ -226,57 +253,99 @@ enumerate_video_devices(char *buf, size_t buflen) udev_unref(udev); #else /* Just return a few options. We'll fail later if the device is not found. */ - appendstr(buf, "/dev/video0|/dev/video1|/dev/video2|/dev/video3", buflen); + appendstr(s, "/dev/video0|/dev/video1|/dev/video2|/dev/video3", len); #endif - } -static void -enumerate_audio_devices(char *buf, size_t buflen) +static void enumerate_audio_devices(char *s, size_t len) { - memset(buf, 0, buflen); +#ifdef HAVE_ALSA + int ndevs; + void **hints, **n; + char *ioid, *name, *descr; +#endif - appendstr(buf, "Audio capture device; ", buflen); + memset(s, 0, len); + appendstr(s, "Audio capture device; ", len); #ifdef HAVE_ALSA - void **hints, **n; - char *ioid, *name; - int ndevs; - if (snd_device_name_hint(-1, "pcm", &hints) < 0) return; ndevs = 0; for (n = hints; *n; n++) { - name = snd_device_name_get_hint(*n, "NAME"); ioid = snd_device_name_get_hint(*n, "IOID"); - if ((ioid == NULL || string_is_equal(ioid, "Input")) && - (!strncmp(name, "hw:", strlen("hw:")) || - !strncmp(name, "default:", strlen("default:")))) + if (ioid != NULL && strcmp(ioid, "Input") != 0) { - if (ndevs > 0) - appendstr(buf, "|", buflen); - appendstr(buf, name, buflen); - ++ndevs; + free(ioid); + ioid = NULL; + continue; + } + + name = snd_device_name_get_hint(*n, "NAME"); + if (name == NULL || strstr(name, "front:") == NULL) + { + free(name); + name = NULL; + continue; + } + + //todo: add more info to make picking audio device more user friendly + descr = snd_device_name_get_hint(*n, "DESC"); + if (!descr) + { + free(descr); + descr = NULL; + continue; + } + + if (ndevs > 0) + appendstr(s, "|", len); + appendstr(s, name, len); + ++ndevs; + + // not sure if this is necessary but ensuring things are free/null + if(name != NULL) + { + free(name); + name = NULL; + } + if(ioid != NULL) + { + free(ioid); + ioid = NULL; + } + if(descr != NULL) + { + free(descr); + descr = NULL; } - free(name); - free(ioid); } snd_device_name_free_hint(hints); #endif } +static void list_resolutions(char *capture_resolutions, size_t len) +{ + size_t i, written; + written = snprintf(capture_resolutions, len, "Capture resolution; "); + for (i = 0; i < sizeof(v4l2_resolutions) / sizeof(v4l2_resolutions[0]); i++) + written += snprintf(capture_resolutions + written, len - written, "%s%dx%d", i > 0 ? "|" : "", + v4l2_resolutions[i].width,v4l2_resolutions[i].height); +} RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_environment)(retro_environment_t cb) { bool no_content = true; char video_devices[ENVVAR_BUFLEN]; char audio_devices[ENVVAR_BUFLEN]; + char capture_resolutions[ENVVAR_BUFLEN]; struct retro_variable envvars[] = { { "videoproc_videodev", NULL }, { "videoproc_audiodev", NULL }, - { "videoproc_capture_mode", "Capture mode; alternate|interlaced|top|bottom|alternate_hack" }, + { "videoproc_capture_mode", "Capture mode; alternate|deinterlaced|interlaced|top|bottom|alternate_hack" }, + { "videoproc_capture_resolution", NULL }, { "videoproc_output_mode","Output mode; progressive|deinterlaced|interlaced" }, { "videoproc_frame_times","Print frame times to terminal (v4l2 only); Off|On" }, { NULL, NULL } @@ -302,6 +371,13 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_environment)(retro_environment_t envvars[1].key = "videoproc_audiodev"; envvars[1].value = audio_devices; + if(envvars[3].value == NULL) + list_resolutions(capture_resolutions, sizeof(capture_resolutions)); + appendstr(capture_resolutions, "|auto", ENVVAR_BUFLEN); + envvars[3].key = "videoproc_capture_resolution"; + envvars[3].value = capture_resolutions; + printf("captures: %s\n", envvars[3].value); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_VARIABLES, envvars); } @@ -330,24 +406,22 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_input_state)(retro_input_state_t VIDEOPROC_CORE_PREFIX(input_state_cb) = cb; } -RETRO_API void VIDEOPROC_CORE_PREFIX(retro_init)(void) -{ -} +RETRO_API void VIDEOPROC_CORE_PREFIX(retro_init)(void) { } static bool open_devices(void) { struct retro_variable videodev = { "videoproc_videodev", NULL }; struct retro_variable audiodev = { "videoproc_audiodev", NULL }; - struct v4l2_capability caps; + struct retro_variable captureresolution = { "videoproc_capture_resolution", NULL }; int error; /* Get the video and audio capture device names from the environment */ VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev); VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &audiodev); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &captureresolution); - if (strcmp(videodev.value, "dummy") == 0) { + if (strcmp(videodev.value, "dummy") == 0) return true; - } /* Video device is required */ if (videodev.value == NULL) @@ -499,42 +573,70 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_get_system_info)(struct retro_system_ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_get_system_av_info)(struct retro_system_av_info *info) { struct retro_variable videodev = { "videoproc_videodev", NULL }; + struct retro_variable capture_resolution = { "videoproc_capture_resolution", NULL }; struct v4l2_cropcap cc; int error; + char splitresolution[ENVVAR_BUFLEN]; + char* token; VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &capture_resolution); - if (strcmp(videodev.value, "dummy") == 0) { + if (strcmp(videodev.value, "dummy") == 0) + { info->geometry.aspect_ratio = 4.0/3.0; - info->geometry.base_width = info->geometry.max_width = video_cap_width; - info->geometry.base_height = video_cap_height; /* out? */ - info->geometry.max_height = video_out_height; - info->timing.fps = 60; + info->geometry.base_width = info->geometry.max_width = video_cap_width; + info->geometry.base_height = video_cap_height; /* out? */ + info->geometry.max_height = video_out_height; + info->timing.fps = 60; + info->timing.sample_rate = AUDIO_SAMPLE_RATE; + } + else + { + /* + * Query the device cropping limits. If available, we can use this to find the capture pixel aspect. + */ + memset(&cc, 0, sizeof(cc)); + cc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + error = v4l2_ioctl(video_device_fd, VIDIOC_CROPCAP, &cc); + + info->geometry.base_width = info->geometry.max_width = video_format.fmt.pix.width; + info->geometry.base_height = video_format.fmt.pix.height; + + if(capture_resolution.value != NULL) + strncpy(video_capture_resolution, capture_resolution.value, ENVVAR_BUFLEN-1); + else + strncpy(video_capture_resolution, "auto", ENVVAR_BUFLEN-1); + + if (strcmp(video_capture_resolution, "auto") != 0) + { + strcpy(splitresolution, video_capture_resolution); + token = strtok(splitresolution, "x"); + info->geometry.base_width = info->geometry.max_width = video_format.fmt.pix.width = atoi(token); + token = strtok(NULL, "x"); + info->geometry.base_height = video_format.fmt.pix.height = atoi(token); + printf("Resolution postfix %ux%u\n", info->geometry.base_width, + info->geometry.base_height); + } + // no doubling for interlaced or deinterlaced capture + bool nodouble = strcmp(video_capture_mode, "deinterlaced") == 0 || strcmp(video_capture_mode, "interlaced") == 0; + info->geometry.max_height = nodouble ? video_format.fmt.pix.height : video_format.fmt.pix.height * 2; + + /* TODO Only double if frames ARE fields (progressive or deinterlaced, full framerate) + * *2 for fields + */ + // defaulting to 60 if this this doesn't return a usable number + if(video_standard.frameperiod.denominator == 0 || video_standard.frameperiod.numerator == 0) + info->timing.fps = 60; + else + info->timing.fps = ((double)(video_standard.frameperiod.denominator*2)) / + (double)video_standard.frameperiod.numerator; info->timing.sample_rate = AUDIO_SAMPLE_RATE; - } else { - /* - * Query the device cropping limits. If available, we can use this to find the capture pixel aspect. - */ - memset(&cc, 0, sizeof(cc)); - cc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - error = v4l2_ioctl(video_device_fd, VIDIOC_CROPCAP, &cc); - info->geometry.base_width = info->geometry.max_width = video_format.fmt.pix.width; - info->geometry.base_height = video_format.fmt.pix.height; - /* TODO Only double if frames are NOT fields (interlaced, full resolution) */ - info->geometry.max_height = video_format.fmt.pix.height * 2; - /* TODO Only double if frames ARE fields (progressive or deinterlaced, full framerate) - * *2 for fields - */ - info->timing.fps = ((double)(video_standard.frameperiod.denominator*2)) / - (double)video_standard.frameperiod.numerator; - info->timing.sample_rate = AUDIO_SAMPLE_RATE; - - if (error == 0) { - /* TODO Allow for fixed 4:3 and 16:9 modes */ - info->geometry.aspect_ratio = (double)info->geometry.base_width / (double)info->geometry.max_height /\ - ((double)cc.pixelaspect.numerator / (double)cc.pixelaspect.denominator); - } + /* TODO/FIXME Allow for fixed 4:3 and 16:9 modes */ + if (error == 0) + info->geometry.aspect_ratio = (double)info->geometry.base_width / (double)info->geometry.max_height / + ((double)cc.pixelaspect.numerator / (double)cc.pixelaspect.denominator); } printf("Aspect ratio: %f\n",info->geometry.aspect_ratio); @@ -544,7 +646,7 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_get_system_av_info)(struct retro_syst info->geometry.max_height); } -RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_controller_port_device)(unsigned port, unsigned device) +RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_controller_port_device)(unsigned a, unsigned b) { } @@ -555,7 +657,8 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_reset)(void) } /* TODO improve this mess and make it generic enough for use with dummy mode */ -void v4l2_frame_times(struct v4l2_buffer buf) { +void v4l2_frame_times(struct v4l2_buffer buf) +{ if (strcmp("Off", video_frame_times) == 0) return; @@ -563,45 +666,49 @@ void v4l2_frame_times(struct v4l2_buffer buf) { ft_info = (char*)calloc(5000, sizeof(char)); if ( (buf.timestamp.tv_sec - ft_prevtime.tv_sec >= 1) && \ - (buf.timestamp.tv_usec + 1000000 - ft_prevtime2.tv_usec) >= 1000000) { + (buf.timestamp.tv_usec + 1000000 - ft_prevtime2.tv_usec) >= 1000000) + { double csec = ((double) buf.timestamp.tv_sec) + (buf.timestamp.tv_usec/1000000); double psec = ((double) ft_prevtime.tv_sec) + (ft_prevtime.tv_usec/1000000); printf("Fields last %.2f seconds: %d\n", csec - psec, ft_fcount); printf("Average frame times: %.3fms\n", ft_favg/(1000*ft_fcount)); printf("Fields timestampdiffs last second:\n%s\n", ft_info); free(ft_info); - ft_info = (char*)calloc(5000, sizeof(char)); - ft_fcount = 0; - ft_favg = 0; + ft_info = (char*)calloc(5000, sizeof(char)); + ft_fcount = 0; + ft_favg = 0; ft_prevtime = buf.timestamp; } ft_fcount++; ft_info2 = strdup(ft_info); ft_ftime = (double) (buf.timestamp.tv_usec + ((buf.timestamp.tv_sec - ft_prevtime2.tv_sec >= 1) ? 1000000 : 0) - ft_prevtime2.tv_usec); ft_favg += ft_ftime; - snprintf(ft_info, 5000 * sizeof(char), "%s %6.d %d %d %.2fms%s", ft_info2, buf.sequence, buf.index, buf.field, ft_ftime/1000, (!(ft_fcount % 7)) ? "\n" : ""); + snprintf(ft_info, 5000 * sizeof(char), "%s %6.d %d %d %.2fms%s", + ft_info2, buf.sequence, buf.index, buf.field, ft_ftime/1000, + (!(ft_fcount % 7)) ? "\n" : ""); free(ft_info2); ft_prevtime2 = buf.timestamp; } -void source_dummy(int width, int height) { +void source_dummy(int width, int height) +{ int i, triangpos, triangpos_t=0, triangpos_b=0, offset=0; bool field_ahead = false; uint8_t *src = frame_cap; float step = M_PI/64; - if (video_buf.field == V4L2_FIELD_TOP) { + if (video_buf.field == V4L2_FIELD_TOP) offset=0; - } else if (video_buf.field == V4L2_FIELD_BOTTOM) { + else if (video_buf.field == V4L2_FIELD_BOTTOM) offset=1; - } dummy_pos += step; /* no animation */ /* dummy_pos = M_PI/4; step = 0; */ triangpos = (sinf(dummy_pos)+1)/2*width; - if (video_buf.field == V4L2_FIELD_INTERLACED) { + if (video_buf.field == V4L2_FIELD_INTERLACED) + { if (video_half_feed_rate == 0) video_half_feed_rate = 1; triangpos_t = (sinf(dummy_pos)+1)/2*width; @@ -609,22 +716,28 @@ void source_dummy(int width, int height) { triangpos_b = (sinf(dummy_pos)+1)/2*width; } - for (i = 0; i < width * height; i+=1, src+=3) { + for (i = 0; i < width * height; i+=1, src+=3) + { float color = (clamp_float((float)(triangpos - (i%width) + offset)/10, -1, 1)+1)/2; src[0] = 0x10 + color*0xE0; src[1] = 0x10 + color*0xE0; src[2] = 0x10 + color*0xE0; /* End of a line */ - if ( ((i+1) % width) == 0 ) { + if ( ((i+1) % width) == 0 ) + { triangpos -= 2; /* offset should be half of this? */ triangpos_t -= 1; triangpos_b -= 1; - if (video_buf.field == V4L2_FIELD_INTERLACED) { - if (field_ahead) { + if (video_buf.field == V4L2_FIELD_INTERLACED) + { + if (field_ahead) + { triangpos = triangpos_b; field_ahead = false; - } else { + } + else + { triangpos = triangpos_t; field_ahead = true; } @@ -638,16 +751,17 @@ void source_dummy(int width, int height) { video_buf.field = V4L2_FIELD_TOP; } -void source_v4l2_normal(int width, int height) { +void source_v4l2_normal(int width, int height) +{ struct v4l2_buffer bufcp; int error; /* Wait until v4l2 dequees a buffer */ memset(&video_buf, 0, sizeof(struct v4l2_buffer)); - video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; video_buf.memory = V4L2_MEMORY_MMAP; - error = v4l2_ioctl(video_device_fd, VIDIOC_DQBUF, &video_buf); + error = v4l2_ioctl(video_device_fd, VIDIOC_DQBUF, &video_buf); if (error != 0) { printf("VIDIOC_DQBUF failed: %s\n", strerror(errno)); @@ -665,7 +779,8 @@ void source_v4l2_normal(int width, int height) { v4l2_frame_times(bufcp); } -void source_v4l2_alternate_hack(int width, int height) { +void source_v4l2_alternate_hack(int width, int height) +{ struct v4l2_buffer bufcp; struct v4l2_format fmt; struct v4l2_requestbuffers reqbufs; @@ -677,7 +792,7 @@ void source_v4l2_alternate_hack(int width, int height) { /* For later, saving time */ memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - error = v4l2_ioctl(video_device_fd, VIDIOC_G_FMT, &fmt); + error = v4l2_ioctl(video_device_fd, VIDIOC_G_FMT, &fmt); if (error != 0) { printf("VIDIOC_G_FMT failed: %s\n", strerror(errno)); @@ -700,7 +815,9 @@ void source_v4l2_alternate_hack(int width, int height) { /* Let's get the data as fast as possible! */ bufcp = video_buf; - memcpy( (uint32_t*) frame_cap, (uint8_t*) v4l2_capbuf[video_buf.index].start, video_format.fmt.pix.width * video_format.fmt.pix.height * 3); + memcpy( (uint32_t*) frame_cap, + (uint8_t*)v4l2_capbuf[video_buf.index].start, + video_format.fmt.pix.width * video_format.fmt.pix.height * 3); v4l2_munmap(v4l2_capbuf[0].start, v4l2_capbuf[0].len); @@ -730,20 +847,20 @@ void source_v4l2_alternate_hack(int width, int height) { v4l2_ncapbuf = reqbufs.count; /* printf("GOT v4l2_ncapbuf=%ld\n", v4l2_ncapbuf); */ - index = 0; + index = 0; memset(&video_buf, 0, sizeof(struct v4l2_buffer)); - video_buf.index = index; - video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + video_buf.index = index; + video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; video_buf.memory = V4L2_MEMORY_MMAP; v4l2_ioctl(video_device_fd, VIDIOC_QUERYBUF, &video_buf); - v4l2_capbuf[index].len = video_buf.length; + v4l2_capbuf[index].len = video_buf.length; v4l2_capbuf[index].start = v4l2_mmap(NULL, video_buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, video_device_fd, video_buf.m.offset); memset(&video_buf, 0, sizeof(struct v4l2_buffer)); - video_buf.index = index; - video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + video_buf.index = index; + video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; video_buf.memory = V4L2_MEMORY_MMAP; v4l2_ioctl(video_device_fd, VIDIOC_QBUF,& video_buf); @@ -764,25 +881,31 @@ void source_v4l2_alternate_hack(int width, int height) { v4l2_frame_times(bufcp); } -void processing_heal(uint8_t *src, int width, int height) { - uint32_t *fp1 = frame_prev1; +void processing_heal(uint8_t *src, int width, int height) +{ int i; - for (i = 0; i < width * height; i+=1, src += 3, ++fp1) { + uint32_t *fp1 = frame_prev1; + for (i = 0; i < width * height; i+=1, src += 3, ++fp1) + { /* Tries to filter a bunch of blanked out scanline sections my capture cards spits out with this crazy hack * Since the blanked out scanlines are set to a black value bellow anything that can be captured, it's quite * easy to select the scanlines... */ - if (src[0] <= 0 && src[1] <= 0 && src[2] <= 0 && i >= width && i <= width * height - width) { + if (src[0] <= 0 && src[1] <= 0 && src[2] <= 0 && i >= width && i <= width * height - width) + { if (*(src + 0 - width*3) >= ((*fp1>> 0&0xFF)-6) && \ *(src + 1 - width*3) >= ((*fp1>> 8&0xFF)-6) && \ *(src + 2 - width*3) >= ((*fp1>>16&0xFF)-6) && \ *(src + 0 - width*3) <= ((*fp1>> 0&0xFF)+6) && \ *(src + 1 - width*3) <= ((*fp1>> 8&0xFF)+6) && \ - *(src + 2 - width*3) <= ((*fp1>>16&0xFF)+6)) { + *(src + 2 - width*3) <= ((*fp1>>16&0xFF)+6)) + { src[0] = (*fp1>> 0&0xFF); src[1] = (*fp1>> 8&0xFF); src[2] = (*fp1>>16&0xFF); - } else { + } + else + { src[0] = (*(fp1+i+width)>> 0&0xFF); src[1] = (*(fp1+i+width)>> 8&0xFF); src[2] = (*(fp1+i+width)>>16&0xFF); @@ -791,7 +914,9 @@ void processing_heal(uint8_t *src, int width, int height) { } } -void processing_deinterlacing_crap(uint32_t *src, uint32_t *dst, int width, int height, enum v4l2_field field, int skip_lines_src) { +void processing_deinterlacing_crap(uint32_t *src, uint32_t *dst, int width, + int height, enum v4l2_field field, int skip_lines_src) +{ int i, targetrow=0; uint32_t pixacul=0; uint32_t *fp1 = frame_prev1, *fp2 = frame_prev2, *fp3 = frame_prev3; @@ -806,9 +931,11 @@ void processing_deinterlacing_crap(uint32_t *src, uint32_t *dst, int width, int * On progressive sources, should only skip the destination lines, since all lines the source are the same fields * On interlaced sources, should skip both the source and the destination lines, since only half the lines in the source are the same fields (must also skip fields later) */ - if (field == V4L2_FIELD_BOTTOM) { + if (field == V4L2_FIELD_BOTTOM) + { dst += width; - if (skip_lines_src == 1) { + if (skip_lines_src == 1) + { src += width; fp1 += width; fp2 += width; @@ -816,7 +943,8 @@ void processing_deinterlacing_crap(uint32_t *src, uint32_t *dst, int width, int } } - for (i = 0; i < width * height; i+=1, src += 1, dst += 1, ++fp1, ++fp2, ++fp3) { + for (i = 0; i < width * height; i+=1, src += 1, dst += 1, ++fp1, ++fp2, ++fp3) + { /* Will fill the current destination line with current field * The masking is used to prserve some information set by the * deinterlacing process, uses the alpha channel to tell if a @@ -825,32 +953,35 @@ void processing_deinterlacing_crap(uint32_t *src, uint32_t *dst, int width, int *(dst) = (*(src) & 0x00FFFFFF) | (*dst & 0xFF000000); /* Crappy deinterlacing */ - if (i >= width && i <= (width*height-width)) { + if (i >= width && i <= (width*height-width)) + { pixacul=((((*(dst)>> 0&0xFF) + (pixacul>> 0&0xFF))>>1<<0 |\ ((*(dst)>> 8&0xFF) + (pixacul>> 8&0xFF))>>1<<8 |\ ((*(dst)>>16&0xFF) + (pixacul>>16&0xFF))>>1<<16) \ & 0x00FFFFFF) | 0xFE000000; if ( ((*(dst ) & 0xFF000000) == 0xFE000000) ||\ - ((*(dst+targetrow) & 0xFF000000) == 0xFE000000) ) { + ((*(dst+targetrow) & 0xFF000000) == 0xFE000000) ) + { *dst = pixacul | 0xFF000000; *(dst+targetrow) = pixacul | 0xFF000000; - } else { + } + else + { if (!(((*(src+0)>> 0&0xFF) >= ((*(fp2+0)>> 0&0xFF)-9) ) &&\ ((*(src+0)>> 8&0xFF) >= ((*(fp2+0)>> 8&0xFF)-9) ) &&\ ((*(src+0)>>16&0xFF) >= ((*(fp2+0)>>16&0xFF)-9) ) &&\ ((*(src+0)>> 0&0xFF) <= ((*(fp2+0)>> 0&0xFF)+9) ) &&\ ((*(src+0)>> 8&0xFF) <= ((*(fp2+0)>> 8&0xFF)+9) ) &&\ - ((*(src+0)>>16&0xFF) <= ((*(fp2+0)>>16&0xFF)+9) )) ) { + ((*(src+0)>>16&0xFF) <= ((*(fp2+0)>>16&0xFF)+9) )) ) *(dst+targetrow) = pixacul; - } else if (!(((*fp3>> 0&0xFF) >= ((*fp1>> 0&0xFF)-9) ) &&\ + else if (!(((*fp3>> 0&0xFF) >= ((*fp1>> 0&0xFF)-9) ) &&\ ((*fp3>> 8&0xFF) >= ((*fp1>> 8&0xFF)-9) ) &&\ ((*fp3>>16&0xFF) >= ((*fp1>>16&0xFF)-9) ) &&\ ((*fp3>> 0&0xFF) <= ((*fp1>> 0&0xFF)+9) ) &&\ ((*fp3>> 8&0xFF) <= ((*fp1>> 8&0xFF)+9) ) &&\ - ((*fp3>>16&0xFF) <= ((*fp1>>16&0xFF)+9) ))) { + ((*fp3>>16&0xFF) <= ((*fp1>>16&0xFF)+9) ))) *(dst+targetrow) = pixacul; - } } } @@ -858,9 +989,11 @@ void processing_deinterlacing_crap(uint32_t *src, uint32_t *dst, int width, int * On progressive sources, should only skip the destination lines, * On interlaced sources, should skip both the source and the destination lines */ - if ( ((i+1) % width) == 0 ) { + if ( ((i+1) % width) == 0 ) + { dst += width; - if (skip_lines_src == 1) { + if (skip_lines_src == 1) + { src += width; fp1 += width; fp2 += width; @@ -870,12 +1003,12 @@ void processing_deinterlacing_crap(uint32_t *src, uint32_t *dst, int width, int } } -void processing_bgr_xrgb(uint8_t *src, uint32_t *dst, int width, int height) { +void processing_bgr_xrgb(uint8_t *src, uint32_t *dst, int width, int height) +{ /* BGR24 to XRGB8888 conversion */ int i; - for (i = 0; i < width * height; i+=1, src += 3, dst += 1) { + for (i = 0; i < width * height; i+=1, src += 3, dst += 1) *dst = 0xFF << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; - } } RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void) @@ -884,15 +1017,17 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void) struct retro_variable videodev = { "videoproc_videodev", NULL }; struct retro_variable audiodev = { "videoproc_audiodev", NULL }; struct retro_variable capturemode = { "videoproc_capture_mode", NULL }; + struct retro_variable captureresolution = { "videoproc_capture_resolution", NULL }; struct retro_variable outputmode = { "videoproc_output_mode", NULL }; struct retro_variable frametimes = { "videoproc_frame_times", NULL }; bool updated = false; - if (VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) { + if (VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) + { VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev); VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &audiodev); VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &capturemode); - VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &outputmode); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &captureresolution); VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &frametimes); /* Video or Audio device(s) has(ve) been changed * TODO We may get away without resetting devices when changing output mode... @@ -900,15 +1035,16 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void) if ((videodev.value && (strcmp(video_device, videodev.value) != 0)) ||\ (audiodev.value && (strcmp(audio_device, audiodev.value) != 0)) ||\ (capturemode.value && (strcmp(video_capture_mode, capturemode.value) != 0)) ||\ - (outputmode.value && (strcmp(video_output_mode, outputmode.value) != 0))) { + (captureresolution.value && (strcmp(video_capture_resolution, captureresolution.value) != 0)) ||\ + (outputmode.value && (strcmp(video_output_mode, outputmode.value) != 0))) + { VIDEOPROC_CORE_PREFIX(retro_unload_game)(); /* This core does not cares for the retro_game_info * argument? */ VIDEOPROC_CORE_PREFIX(retro_load_game)(NULL); } - if (frametimes.value != NULL) { + if (frametimes.value != NULL) strncpy(video_frame_times, frametimes.value, ENVVAR_BUFLEN-1); - } } VIDEOPROC_CORE_PREFIX(input_poll_cb)(); @@ -918,36 +1054,45 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void) * half_feed_rate allows interlaced input to be fed at half the calls to this function * where the same frame is then read by the deinterlacer twice, for each field */ - if (video_half_feed_rate == 0) { + if (video_half_feed_rate == 0) + { /* Capture */ - if (strcmp(video_device, "dummy") == 0) { + if (strcmp(video_device, "dummy") == 0) + { source_dummy(video_cap_width, video_cap_height); - } else { - if (strcmp(video_capture_mode, "alternate_hack") == 0) { + } + else + { + if (strcmp(video_capture_mode, "alternate_hack") == 0) + { source_v4l2_alternate_hack(video_cap_width, video_cap_height); processing_heal(frame_cap, video_cap_width, video_cap_height); - } else { + } + else + { source_v4l2_normal(video_cap_width, video_cap_height); } } if (video_buf.field == V4L2_FIELD_INTERLACED) video_half_feed_rate = 1; - } else { - video_half_feed_rate = 0; } + else + video_half_feed_rate = 0; /* Converts from bgr to xrgb, deinterlacing, final copy to the outpuit buffer (frame_out) * Every frame except frame_cap shall be encoded in xrgb * Every frame except frame_out shall have the same height */ - if (strcmp(video_output_mode, "deinterlaced") == 0) { + if (strcmp(video_output_mode, "deinterlaced") == 0) + { processing_bgr_xrgb(frame_cap, frame_curr, video_cap_width, video_cap_height); /* When deinterlacing a interlaced input, we need to process both fields of a frame, * one at a time (retro_run needs to be called twice, vide_half_feed_rate prevents the * source from being read twice... */ - if (strcmp(video_capture_mode, "interlaced") == 0) { + if (strcmp(video_capture_mode, "interlaced") == 0) + { enum v4l2_field field_read; if (video_half_feed_rate == 0) field_read = V4L2_FIELD_TOP; @@ -957,34 +1102,41 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void) * deinterlacing algo twice, extracting a given field for each run. */ processing_deinterlacing_crap(frame_curr, frame_out, video_cap_width, video_cap_height/2, field_read, 1); - } else { + } + else + { processing_deinterlacing_crap(frame_curr, frame_out, video_cap_width, video_cap_height, (enum v4l2_field)video_buf.field, 0); } - aux = frame_prev3; + aux = frame_prev3; frame_prev3 = frame_prev2; frame_prev2 = frame_prev1; frame_prev1 = frame_curr; - frame_curr = aux; + frame_curr = aux; VIDEOPROC_CORE_PREFIX(video_refresh_cb)(frame_out, video_cap_width, video_out_height, video_cap_width * sizeof(uint32_t)); - } else if (strcmp(video_capture_mode, "alternate_hack") == 0) { - /* Case where alternate_hack without deinterlacing would not generate previous frame for processing_heal */ + } + else if (strcmp(video_capture_mode, "alternate_hack") == 0) + { + /* Case where alternate_hack without deinterlacing would + * not generate previous frame for processing_heal */ processing_bgr_xrgb(frame_cap, frame_curr, video_cap_width, video_cap_height); - aux = frame_prev3; + aux = frame_prev3; frame_prev3 = frame_prev2; frame_prev2 = frame_prev1; frame_prev1 = frame_curr; - frame_curr = aux; + frame_curr = aux; - aux = frame_out; - frame_out = frame_curr; + aux = frame_out; + frame_out = frame_curr; VIDEOPROC_CORE_PREFIX(video_refresh_cb)(frame_out, video_cap_width, video_out_height, video_cap_width * sizeof(uint32_t)); - frame_out = aux; - } else { + frame_out = aux; + } + else + { processing_bgr_xrgb(frame_cap, frame_out, video_cap_width, video_out_height); VIDEOPROC_CORE_PREFIX(video_refresh_cb)(frame_out, video_cap_width, @@ -993,48 +1145,37 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void) } RETRO_API size_t VIDEOPROC_CORE_PREFIX(retro_serialize_size)(void) -{ - return 0; -} - -RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_serialize)(void *data, size_t size) -{ - return false; -} - -RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_unserialize)(const void *data, size_t size) -{ - return false; -} - -RETRO_API void VIDEOPROC_CORE_PREFIX(retro_cheat_reset)(void) -{ -} - -RETRO_API void VIDEOPROC_CORE_PREFIX(retro_cheat_set)(unsigned index, bool enabled, const char *code) -{ -} +{ return 0; } +RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_serialize)( + void *data, size_t len) { return false; } +RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_unserialize)( + const void *data, size_t len) { return false; } +RETRO_API void VIDEOPROC_CORE_PREFIX(retro_cheat_reset)(void) { } +RETRO_API void VIDEOPROC_CORE_PREFIX(retro_cheat_set)(unsigned a, + bool b, const char *c) { } #if 0 -static void videoinput_set_control_v4l2( uint32_t id, double val ) +static void videoinput_set_control_v4l2( uint32_t id, double val) { struct v4l2_queryctrl query; query.id = id; - if( ioctl( video_device_fd, VIDIOC_QUERYCTRL, &query ) >= 0 && !(query.flags & V4L2_CTRL_FLAG_DISABLED) ) { + if(ioctl(video_device_fd, VIDIOC_QUERYCTRL, &query) >= 0 && !(query.flags & V4L2_CTRL_FLAG_DISABLED)) + { struct v4l2_control control; control.id = id; control.value = query.minimum + ((int) ((val * ((double) (query.maximum - query.minimum))) + 0.5)); - ioctl( video_device_fd, VIDIOC_S_CTRL, &control ); + ioctl(video_device_fd, VIDIOC_S_CTRL, &control); } } #endif RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_info *game) { - struct retro_variable videodev = { "videoproc_videodev", NULL }; - struct retro_variable audiodev = { "videoproc_audiodev", NULL }; + struct retro_variable videodev = { "videoproc_videodev", NULL }; + struct retro_variable audiodev = { "videoproc_audiodev", NULL }; struct retro_variable capture_mode = { "videoproc_capture_mode", NULL }; + struct retro_variable capture_resolution = { "videoproc_capture_resolution", NULL }; struct retro_variable output_mode = { "videoproc_output_mode", NULL }; struct retro_variable frame_times = { "videoproc_frame_times", NULL }; enum retro_pixel_format pixel_format; @@ -1047,6 +1188,8 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in uint32_t index; bool std_found; int error; + char splitresolution[ENVVAR_BUFLEN]; + char* token; if (open_devices() == false) { @@ -1056,7 +1199,8 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in } #ifdef HAVE_ALSA - if (audio_handle != NULL) { + if (audio_handle != NULL) + { struct retro_audio_callback audio_cb; audio_cb.callback = audio_callback; audio_cb.set_state = audio_set_state; @@ -1065,7 +1209,8 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in #endif VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev); - if (videodev.value == NULL) { + if (videodev.value == NULL) + { close_devices(); return false; } @@ -1073,13 +1218,19 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in /* Audio device is optional... */ VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &audiodev); - if (audiodev.value != NULL) { + if (audiodev.value != NULL) strncpy(audio_device, audiodev.value, ENVVAR_BUFLEN-1); - } + + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &capture_resolution); + if(capture_resolution.value != NULL) + strncpy(video_capture_resolution, capture_resolution.value, ENVVAR_BUFLEN-1); + else + strncpy(video_capture_resolution, "auto", ENVVAR_BUFLEN-1); VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &capture_mode); VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &output_mode); - if (capture_mode.value == NULL || output_mode.value == NULL) { + if (capture_mode.value == NULL || output_mode.value == NULL) + { close_devices(); return false; } @@ -1087,32 +1238,37 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in strncpy(video_output_mode, output_mode.value, ENVVAR_BUFLEN-1); VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &frame_times); - if (frame_times.value != NULL) { + if (frame_times.value != NULL) strncpy(video_frame_times, frame_times.value, ENVVAR_BUFLEN-1); - } - if (strcmp(video_device, "dummy") == 0) { - if (strcmp(video_capture_mode, "interlaced") == 0) { + if (strcmp(video_device, "dummy") == 0) + { + if (strcmp(video_capture_mode, "interlaced") == 0) + { video_format.fmt.pix.height = 480; - video_cap_height = 480; - video_buf.field = V4L2_FIELD_INTERLACED; - } else if (strcmp(video_capture_mode, "alternate") == 0 ||\ - strcmp(video_capture_mode, "top") == 0 ||\ - strcmp(video_capture_mode, "bottom") == 0 ||\ - strcmp(video_capture_mode, "alternate_hack") == 0) { + video_cap_height = 480; + video_buf.field = V4L2_FIELD_INTERLACED; + } + else if ( strcmp(video_capture_mode, "alternate") == 0 + || strcmp(video_capture_mode, "top") == 0 + || strcmp(video_capture_mode, "bottom") == 0 + || strcmp(video_capture_mode, "alternate_hack") == 0) + { video_format.fmt.pix.height = 240; - video_cap_height = 240; - video_buf.field = V4L2_FIELD_TOP; + video_cap_height = 240; + video_buf.field = V4L2_FIELD_TOP; } - dummy_pos=0; + dummy_pos = 0; video_format.fmt.pix.width = 640; - video_cap_width = 640; - } else { + video_cap_width = 640; + } + else + { memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - error = v4l2_ioctl(video_device_fd, VIDIOC_G_FMT, &fmt); + error = v4l2_ioctl(video_device_fd, VIDIOC_G_FMT, &fmt); if (error != 0) { @@ -1125,33 +1281,48 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in fmt.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; fmt.fmt.pix.quantization = V4L2_QUANTIZATION_LIM_RANGE; - fmt.fmt.pix.height = 240; + // applied set resolution if not set to auto + if (strcmp(video_capture_resolution, "auto") != 0) + { + strcpy(splitresolution, video_capture_resolution); + token = strtok(splitresolution, "x"); + fmt.fmt.pix.width = atoi(token); + token = strtok(NULL, "x"); + fmt.fmt.pix.height = atoi(token); + } fmt.fmt.pix.field = V4L2_FIELD_TOP; - /* TODO Query the size and FPS */ - if (strcmp(video_capture_mode, "interlaced") == 0) { - v4l2_ncapbuf_target = 2; - fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; - video_format.fmt.pix.height = 480; - video_cap_height = 480; - } else { - v4l2_ncapbuf_target = 2; - video_format.fmt.pix.height = 240; - video_cap_height = 240; - if (strcmp(video_capture_mode, "alternate") == 0) + if (strcmp(video_capture_mode, "interlaced") == 0) + { + v4l2_ncapbuf_target = 2; + fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; + video_format.fmt.pix.height = fmt.fmt.pix.height; + video_cap_height = fmt.fmt.pix.height; + } + else + { + v4l2_ncapbuf_target = 2; + video_format.fmt.pix.height = fmt.fmt.pix.height/2; + video_cap_height = fmt.fmt.pix.height/2; + if (strcmp(video_capture_mode, "deinterlaced") == 0) + { + v4l2_ncapbuf_target = 2; + video_format.fmt.pix.height = fmt.fmt.pix.height; + video_cap_height = fmt.fmt.pix.height; + } else if (strcmp(video_capture_mode, "alternate") == 0) fmt.fmt.pix.field = V4L2_FIELD_ALTERNATE; else if (strcmp(video_capture_mode, "top") == 0) fmt.fmt.pix.field = V4L2_FIELD_TOP; else if (strcmp(video_capture_mode, "bottom") == 0) fmt.fmt.pix.field = V4L2_FIELD_BOTTOM; - else if (strcmp(video_capture_mode, "alternate_hack") == 0) { - fmt.fmt.pix.field = V4L2_FIELD_TOP; + else if (strcmp(video_capture_mode, "alternate_hack") == 0) + { + fmt.fmt.pix.field = V4L2_FIELD_TOP; v4l2_ncapbuf_target = 1; } } - video_format.fmt.pix.width = 720; - video_cap_width = 720; + video_cap_width = fmt.fmt.pix.width; error = v4l2_ioctl(video_device_fd, VIDIOC_S_FMT, &fmt); if (error != 0) @@ -1160,41 +1331,46 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in return false; } - error = v4l2_ioctl(video_device_fd, VIDIOC_G_STD, &std_id); - if (error != 0) + /* skipping this for (magewell usb) since the std ioctl gives errors + * unsure if this will impact other cards + */ + if(strcmp((const char*)caps.driver, "uvcvideo") != 0) { - printf("VIDIOC_G_STD failed: %s\n", strerror(errno)); - return false; - } - for (index = 0, std_found = false; ; index++) - { - memset(&std, 0, sizeof(std)); - std.index = index; - error = v4l2_ioctl(video_device_fd, VIDIOC_ENUMSTD, &std); - if (error) - break; - if (std.id == std_id) + error = v4l2_ioctl(video_device_fd, VIDIOC_G_STD, &std_id); + if (error != 0) { - video_standard = std; - std_found = true; + printf("VIDIOC_G_STD failed: %s\n", strerror(errno)); + return false; + } + for (index = 0, std_found = false; ; index++) + { + memset(&std, 0, sizeof(std)); + std.index = index; + error = v4l2_ioctl(video_device_fd, VIDIOC_ENUMSTD, &std); + if (error) + break; + if (std.id == std_id) + { + video_standard = std; + std_found = true; + } + printf("VIDIOC_ENUMSTD[%u]: %s%s\n", index, std.name, std.id == std_id ? " [*]" : ""); + } + if (!std_found) + { + printf("VIDIOC_ENUMSTD did not contain std ID %08x\n", (unsigned)std_id); + return false; } - printf("VIDIOC_ENUMSTD[%u]: %s%s\n", index, std.name, std.id == std_id ? " [*]" : ""); } - if (!std_found) - { - printf("VIDIOC_ENUMSTD did not contain std ID %08x\n", (unsigned)std_id); - return false; - } - video_format = fmt; /* TODO Check if what we got is indeed what we asked for */ memset(&reqbufs, 0, sizeof(reqbufs)); - reqbufs.count = v4l2_ncapbuf_target; - reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbufs.count = v4l2_ncapbuf_target; + reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbufs.memory = V4L2_MEMORY_MMAP; - error = v4l2_ioctl(video_device_fd, VIDIOC_REQBUFS, &reqbufs); + error = v4l2_ioctl(video_device_fd, VIDIOC_REQBUFS, &reqbufs); if (error != 0) { printf("VIDIOC_REQBUFS failed: %s\n", strerror(errno)); @@ -1206,18 +1382,18 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in for (index = 0; index < v4l2_ncapbuf; index++) { memset(&buf, 0, sizeof(buf)); - buf.index = index; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.index = index; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; - error = v4l2_ioctl(video_device_fd, VIDIOC_QUERYBUF, &buf); + error = v4l2_ioctl(video_device_fd, VIDIOC_QUERYBUF, &buf); if (error != 0) { printf("VIDIOC_QUERYBUF failed for %u: %s\n", index, strerror(errno)); return false; } - v4l2_capbuf[index].len = buf.length; + v4l2_capbuf[index].len = buf.length; v4l2_capbuf[index].start = v4l2_mmap(NULL, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, video_device_fd, buf.m.offset); if (v4l2_capbuf[index].start == MAP_FAILED) @@ -1230,19 +1406,20 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in for (index = 0; index < v4l2_ncapbuf; index++) { memset(&buf, 0, sizeof(buf)); - buf.index = index; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.index = index; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; - error = v4l2_ioctl(video_device_fd, VIDIOC_QBUF, &buf); + error = v4l2_ioctl(video_device_fd, VIDIOC_QBUF, &buf); if (error != 0) { - printf("VIDIOC_QBUF failed for %u: %s\n", index, strerror(errno)); + printf("VIDIOC_QBUF failed for %u: %s\n", index, + strerror(errno)); return false; } } - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; error = v4l2_ioctl(video_device_fd, VIDIOC_STREAMON, &type); if (error != 0) { @@ -1253,33 +1430,41 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in /* videoinput_set_control_v4l2(V4L2_CID_HUE, (double) 0.4f); */ } - /* TODO Framerates? - * Each frame should combine both fields into a full frame (if not already captured interlaced), half frame-rate + /* TODO/FIXME Framerates? + * Each frame should combine both fields into a full frame + * (if not already captured interlaced), half frame-rate */ - if (strcmp(video_output_mode, "interlaced") == 0) { - if (strcmp(video_capture_mode, "interlaced") == 0) { - video_out_height = video_cap_height; - } else { - printf("WARNING: Capture mode %s with output mode %s is not properly supported yet... (Is this even useful?)\n", \ - video_capture_mode, video_output_mode); - video_out_height = video_cap_height*2; - } - /* Each frame has one field, full frame-rate */ - } else if (strcmp(video_output_mode, "progressive") == 0) { - video_out_height = video_cap_height; - /* Each frame has one or both field to be deinterlaced into a full frame (double the lines if one field), full frame-rate */ - } else if (strcmp(video_output_mode, "deinterlaced") == 0) { + if (strcmp(video_output_mode, "interlaced") == 0) + { if (strcmp(video_capture_mode, "interlaced") == 0) video_out_height = video_cap_height; else + { + printf("WARNING: Capture mode %s with output mode %s is not" + " properly supported yet... (Is this even useful?)\n", \ + video_capture_mode, video_output_mode); video_out_height = video_cap_height*2; - } else + } + /* Each frame has one field, full frame-rate */ + } + /* Each frame has one or both field to be deinterlaced + * into a full frame (double the lines if one field), full frame-rate */ + else if (strcmp(video_output_mode, "progressive") == 0) + video_out_height = video_cap_height; + else if (strcmp(video_output_mode, "deinterlaced") == 0) + { + if (strcmp(video_capture_mode, "interlaced") == 0 || strcmp(video_capture_mode, "deinterlaced") == 0) + video_out_height = video_cap_height; + else + video_out_height = video_cap_height*2; + } + else video_out_height = video_cap_height; printf("Capture Resolution %ux%u\n", video_cap_width, video_cap_height); printf("Output Resolution %ux%u\n", video_cap_width, video_out_height); - frame_cap = (uint8_t*)calloc(1, video_cap_width * video_cap_height * sizeof(uint8_t) * 3); + frame_cap = (uint8_t*)calloc (1, video_cap_width * video_cap_height * sizeof(uint8_t) * 3); frame_out = (uint32_t*)calloc(1, video_cap_width * video_out_height * sizeof(uint32_t)); /* TODO: Only allocate frames if we are going to use it (for deinterlacing or other filters?) */ frames[0] = (uint32_t*)calloc(1, video_cap_width * video_out_height * sizeof(uint32_t)); @@ -1287,17 +1472,14 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in frames[2] = (uint32_t*)calloc(1, video_cap_width * video_out_height * sizeof(uint32_t)); frames[3] = (uint32_t*)calloc(1, video_cap_width * video_out_height * sizeof(uint32_t)); - frame_curr = frames[0]; + frame_curr = frames[0]; frame_prev1 = frames[1]; frame_prev2 = frames[2]; frame_prev3 = frames[3]; /* TODO: Check frames[] allocation */ if (!frame_out || !frame_cap) - { - printf("Cannot allocate buffers\n"); return false; - } printf("Allocated %" PRI_SIZET " byte conversion buffer\n", (size_t)(video_cap_width * video_cap_height) * sizeof(uint32_t)); @@ -1318,7 +1500,8 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_unload_game)(void) int i; #ifdef HAVE_ALSA - if (audio_handle != NULL) { + if (audio_handle != NULL) + { VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK, NULL); } #endif @@ -1327,7 +1510,8 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_unload_game)(void) { uint32_t index; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - int error = v4l2_ioctl(video_device_fd, VIDIOC_STREAMOFF, &type); + int error = v4l2_ioctl(video_device_fd, + VIDIOC_STREAMOFF, &type); if (error != 0) printf("VIDIOC_STREAMOFF failed: %s\n", strerror(errno)); @@ -1351,7 +1535,8 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_unload_game)(void) free(frame_cap); frame_cap = NULL; - for (i = 0; i<4; ++i) { + for (i = 0; i<4; ++i) + { if (frames[i]) free(frames[i]); frames[i] = NULL; @@ -1361,12 +1546,14 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_unload_game)(void) frame_prev2 = NULL; frame_prev3 = NULL; - if (ft_info) { + if (ft_info) + { free(ft_info); ft_info = NULL; } - if (ft_info2) { + if (ft_info2) + { free(ft_info2); ft_info2 = NULL; } @@ -1377,10 +1564,7 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_unload_game)(void) } RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game_special)(unsigned game_type, - const struct retro_game_info *info, size_t num_info) -{ - return false; -} + const struct retro_game_info *info, size_t num_info) { return false; } RETRO_API unsigned VIDEOPROC_CORE_PREFIX(retro_get_region)(void) { diff --git a/ctr/ctr_debug.h b/ctr/ctr_debug.h index 3a75a432a0..aa808ab447 100644 --- a/ctr/ctr_debug.h +++ b/ctr/ctr_debug.h @@ -17,7 +17,7 @@ void dump_result_value(Result val); #define DEBUG_HOLD() do{printf("%s@%s:%d.\n",__FUNCTION__, __FILE__, __LINE__);fflush(stdout);wait_for_input();}while(0) #define DEBUG_LINE() do{printf("%s:%d.\n",__FUNCTION__, __LINE__);fflush(stdout);}while(0) #define DEBUG_STR(X) printf( "%s: %s\n", #X, (char*)(X)) -#define DEBUG_VAR(X) printf( "%-20s: 0x%08X\n", #X, (u32)(X)) +#define DEBUG_VAR(X) printf( "%-20s: 0x%08" PRIX32 "\n", #X, (uint32_t)(X)) #define DEBUG_INT(X) printf( "%-20s: %10i\n", #X, (s32)(X)) #define DEBUG_VAR64(X) printf( #X"\r\t\t\t\t : 0x%016llX\n", (u64)(X)) #define DEBUG_ERROR(X) do{if(X)dump_result_value(X);}while(0) diff --git a/ctr/ctr_linear.cpp b/ctr/ctr_linear.cpp index f73a4b7723..c8c0cb85a4 100644 --- a/ctr/ctr_linear.cpp +++ b/ctr/ctr_linear.cpp @@ -21,7 +21,8 @@ struct MemBlock static MemBlock* Create(u8* base, u32 size) { auto b = (MemBlock*)malloc(sizeof(MemBlock)); - if (!b) return nullptr; + if (!b) + return nullptr; b->prev = nullptr; b->next = nullptr; b->base = base; @@ -159,7 +160,7 @@ static bool linearInit(void) return false; } -void* linearMemAlign(size_t size, size_t alignment) +void* linearMemAlign(size_t len, size_t alignment) { int shift; /* Enforce minimum alignment */ @@ -181,7 +182,7 @@ void* linearMemAlign(size_t size, size_t alignment) /* Allocate the chunk */ MemChunk chunk; - if (!sLinearPool.Allocate(chunk, size, shift)) + if (!sLinearPool.Allocate(chunk, len, shift)) return nullptr; auto node = newNode(chunk); @@ -190,43 +191,42 @@ void* linearMemAlign(size_t size, size_t alignment) sLinearPool.Deallocate(chunk); return nullptr; } - if (rbtree_insert(&sAddrMap, &node->node)); + if (!rbtree_insert(&sAddrMap, &node->node)) { + sLinearPool.Deallocate(chunk); + return nullptr; + } - if (sLinearPool_maxaddr < (u32)sLinearPool.last->base) - sLinearPool_maxaddr = (u32)sLinearPool.last->base; + if (sLinearPool_maxaddr < (u32)sLinearPool.last->base) + sLinearPool_maxaddr = (u32)sLinearPool.last->base; return chunk.addr; } -void* linearAlloc(size_t size) +void* linearAlloc(size_t len) { #if 0 - if(ctrConsole && ctrConsole->consoleInitialised) + if (ctrConsole && ctrConsole->consoleInitialised) { - printf("linearAlloc : 0x%08X\n", size); + printf("linearAlloc : 0x%08X\n", len); DEBUG_HOLD(); } #endif - return linearMemAlign(size, 0x80); + return linearMemAlign(len, 0x80); } -void* linearRealloc(void* mem, size_t size) -{ - /* TODO */ - return NULL; -} +void* linearRealloc(void* mem, size_t len) { return NULL; } void linearFree(void* mem) { - auto node = getNode(mem); - if (!node) + auto node = getNode(mem); + if (!node) return; - /* Free the chunk */ - sLinearPool.Deallocate(node->chunk); + /* Free the chunk */ + sLinearPool.Deallocate(node->chunk); - /* Free the node */ - delNode(node); + /* Free the node */ + delNode(node); } u32 linearSpaceFree(void) @@ -236,7 +236,7 @@ u32 linearSpaceFree(void) extern "C" u32 ctr_get_linear_free(void) { - if(sLinearPool.last->base + sLinearPool.last->size != (u8*)__linear_heap + __linear_heap_size) + if (sLinearPool.last->base + sLinearPool.last->size != (u8*)__linear_heap + __linear_heap_size) return 0; return sLinearPool.last->size; } @@ -248,16 +248,16 @@ extern "C" u32 ctr_get_linear_unused(void) extern "C" void ctr_linear_free_pages(u32 pages) { - if(sLinearPool.last->base + sLinearPool.last->size != (u8*)__linear_heap + __linear_heap_size) + u32 tmp, size; + if (sLinearPool.last->base + sLinearPool.last->size != (u8*)__linear_heap + __linear_heap_size) return; - u32 size = pages << 12; - if(size > sLinearPool.last->size) + size = pages << 12; + if (size > sLinearPool.last->size) return; sLinearPool.last->size -= size; __linear_heap_size -= size; - u32 tmp; svcControlMemory(&tmp, __linear_heap + __linear_heap_size, 0x0, size, MEMOP_FREE, (MemPerm)(MEMPERM_READ | MEMPERM_WRITE)); diff --git a/ctr/ctr_memory.c b/ctr/ctr_memory.c index bb84ff8f7d..c6d3d71a4e 100644 --- a/ctr/ctr_memory.c +++ b/ctr/ctr_memory.c @@ -40,7 +40,7 @@ void ctr_free_pages(u32 pages) u32 linear_free_pages; u32 stack_free, stack_usage, stack_free_pages; - if(!pages) + if (!pages) return; linear_free_pages = ctr_get_linear_free() >> 12; @@ -54,31 +54,31 @@ void ctr_free_pages(u32 pages) #endif stack_free = ctr_get_stack_free(); - stack_usage = __stacksize__ > stack_free + stack_usage = __stacksize__ > stack_free ? __stacksize__ - stack_free : 0; - stack_free = stack_free > __stack_size_extra - ? __stack_size_extra + stack_free = stack_free > __stack_size_extra + ? __stack_size_extra : stack_free; stack_free_pages = stack_free >> 12; - if(linear_free_pages + (stack_free_pages - (stack_usage >> 12)) > pages) + if (linear_free_pages + (stack_free_pages - (stack_usage >> 12)) > pages) { stack_free_pages -= (stack_usage >> 12); stack_free_pages = stack_free_pages > pages ? pages : stack_free_pages; linear_free_pages = pages - stack_free_pages; } - else if(linear_free_pages + stack_free_pages > pages) + else if (linear_free_pages + stack_free_pages > pages) stack_free_pages = pages - linear_free_pages; else return; - if(linear_free_pages) + if (linear_free_pages) ctr_linear_free_pages(linear_free_pages); - if(stack_free_pages) + if (stack_free_pages) { u32 tmp; svcControlMemory(&tmp, __stack_bottom, diff --git a/ctr/ctr_svchax.c b/ctr/ctr_svchax.c index 7614417c31..7231643e66 100644 --- a/ctr/ctr_svchax.c +++ b/ctr/ctr_svchax.c @@ -183,7 +183,7 @@ static u32 get_threads_limit(void) Handle resource_limit_handle; s64 thread_limit_current; s64 thread_limit_max; - u32 thread_limit_name = RESOURCE_LIMIT_THREADS; + ResourceLimitType thread_limit_name = RESOURCE_LIMIT_THREADS; svcGetResourceLimit(&resource_limit_handle, CURRENT_KPROCESS_HANDLE); svcGetResourceLimitCurrentValues(&thread_limit_current, resource_limit_handle, &thread_limit_name, 1); @@ -272,7 +272,7 @@ static void do_memchunkhax2(void) svcControlMemory(&linear_buffer, 0, 0, 0x1000, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); - mch2.alloc_size = ((((linear_size - (skip_pages << 12)) + mch2.alloc_size = ((((linear_size - (skip_pages << 12)) + 0x1000) >> 13) << 12); mem_free = osGetMemRegionFree(MEMREGION_APPLICATION); @@ -303,14 +303,14 @@ static void do_memchunkhax2(void) alloc_address_kaddr = osConvertVirtToPhys( (void*)linear_address) + mch2.kernel_fcram_mapping_offset; - mch2.thread_page_kva = get_first_free_basemem_page(mch2.isNew3DS) + mch2.thread_page_kva = get_first_free_basemem_page(mch2.isNew3DS) - 0x10000; /* skip down 16 pages */ ((u32*)linear_buffer)[0] = 1; ((u32*)linear_buffer)[1] = mch2.thread_page_kva; ((u32*)linear_buffer)[2] = alloc_address_kaddr + (((mch2.alloc_size >> 12) - 3) << 13) + (skip_pages << 12); - dst_memchunk = linear_address - + (((mch2.alloc_size >> 12) - 2) << 13) + dst_memchunk = linear_address + + (((mch2.alloc_size >> 12) - 2) << 13) + (skip_pages << 12); memcpy(flush_buffer, flush_buffer + 0x4000, 0x4000); @@ -319,7 +319,7 @@ static void do_memchunkhax2(void) GSPGPU_FlushDataCache((void*)linear_buffer, 16); memcpy(flush_buffer, flush_buffer + 0x4000, 0x4000); - /* can't clear gspEvents[GSPGPU_EVENT_PPF]), + /* can't clear gspEvents[GSPGPU_EVENT_PPF]), * directly so execute a dummy copy * and use gspWaitForEvent to clear it. */ @@ -380,8 +380,8 @@ static void do_memchunkhax2(void) thread_ACL[SVC_ACL_OFFSET(0x7B) >> 2] = SVC_ACL_MASK(0x7B); GSPGPU_FlushDataCache((void*)thread_ACL, 16); GSPGPU_InvalidateDataCache((void*)thread_ACL, 16); - mch2.threads[i].args.target_kaddr = get_thread_page() - + THREAD_PAGE_ACL_OFFSET + mch2.threads[i].args.target_kaddr = get_thread_page() + + THREAD_PAGE_ACL_OFFSET + SVC_ACL_OFFSET(0x7B); mch2.threads[i].args.target_val = SVC_ACL_MASK(0x7B); break; @@ -437,7 +437,7 @@ static void gspwn(u32 dst, u32 src, u32 size, u8* flush_buffer) } /* pseudo-code: - * if(val2) + * if (val2) * { * *(u32*)val1 = val2; * *(u32*)(val2 + 8) = (val1 - 4); @@ -503,8 +503,8 @@ static void do_memchunkhax1(void) u32 saved_vram_value = *(u32*)0x1F000008; /* 0x1F000000 contains the enable bit for svc 0x7B */ - memchunkhax1_write_pair(get_thread_page() - + THREAD_PAGE_ACL_OFFSET + memchunkhax1_write_pair(get_thread_page() + + THREAD_PAGE_ACL_OFFSET + SVC_ACL_OFFSET(0x7B), 0x1F000000); write_kaddr(0x1F000008, saved_vram_value); @@ -540,10 +540,10 @@ Result svchax_init(bool patch_srv) u32 luma_major, luma_minor; if (kver > SYSTEM_VERSION(2, 50, 11) && - (R_FAILED(get_luma_version(&luma_major, &luma_minor) + (R_FAILED(get_luma_version(&luma_major, &luma_minor) || luma_major < 8))) return -1; - else if (kver > SYSTEM_VERSION(2, 46, 0) + else if (kver > SYSTEM_VERSION(2, 46, 0) && kver <= SYSTEM_VERSION(2, 50, 11)) do_memchunkhax2(); else if (kver <= SYSTEM_VERSION(2, 46, 0)) @@ -557,7 +557,7 @@ Result svchax_init(bool patch_srv) if (patch_srv && !__ctr_svchax_srv) { - u32 PID_kaddr = read_kaddr(CURRENT_KPROCESS) + u32 PID_kaddr = read_kaddr(CURRENT_KPROCESS) + (isNew3DS ? 0xBC : (kver > SYSTEM_VERSION(2, 40, 0)) ? 0xB4 : 0xAC); u32 old_PID = read_kaddr(PID_kaddr); write_kaddr(PID_kaddr, 0); diff --git a/ctr/ctr_system.c b/ctr/ctr_system.c index 3937a2fc93..e310489282 100644 --- a/ctr/ctr_system.c +++ b/ctr/ctr_system.c @@ -187,12 +187,12 @@ Result APT_ReceiveDeliverArg_(void* param, size_t param_size, staticbufs[2] = saved_threadstorage[2]; staticbufs[3] = saved_threadstorage[3]; - if(R_FAILED(ret)) + if (R_FAILED(ret)) return ret; - if(source_pid) + if (source_pid) *source_pid = ((u64*)cmdbuf)[1]; - if(received) + if (received) *received = ((bool*)cmdbuf)[16]; return cmdbuf[1]; @@ -212,7 +212,7 @@ void __system_initArgv(void) u8 hmac[0x20]; bool received; - if(!__service_ptr + if (!__service_ptr && R_SUCCEEDED(APT_ReceiveDeliverArg_(¶m, sizeof(param), hmac, sizeof(hmac), NULL, &received)) && received && !memcmp(hmac, __argv_hmac, sizeof(__argv_hmac))) @@ -257,7 +257,7 @@ void __attribute__((noreturn)) __ctru_exit(int rc) { __libc_fini_array(); __appExit(); - asm ("mov sp, %[saved_stack] \n\t" : : [saved_stack] "r" (__saved_stack) : "sp"); + asm ("mov sp, %[saved_stack] \n\t" : : [saved_stack] "r" (__saved_stack)); __libctru_exit(rc); } diff --git a/ctr/exec-3dsx/exec_cia.c b/ctr/exec-3dsx/exec_cia.c index 8cbf66f606..43567ef66d 100644 --- a/ctr/exec-3dsx/exec_cia.c +++ b/ctr/exec-3dsx/exec_cia.c @@ -63,7 +63,7 @@ static int isCiaInstalled(u64 titleId, u16 version) return 0; } -static int deleteCia(u64 TitleId) +static void deleteCia(u64 TitleId) { u64 currTitleId = 0; diff --git a/ctr/gpu_old.c b/ctr/gpu_old.c index f3b92ff863..65ed3e9086 100644 --- a/ctr/gpu_old.c +++ b/ctr/gpu_old.c @@ -11,7 +11,9 @@ #include <3ds/gpu/gx.h> #include <3ds/gpu/shbin.h> +#define DEPRECATED #include "gpu_old.h" +#undef DEPRECATED void GPU_Init(Handle *gsphandle) { diff --git a/deps/7zip/LzmaEnc.c b/deps/7zip/LzmaEnc.c index 3fb17bc53c..f879099f0a 100644 --- a/deps/7zip/LzmaEnc.c +++ b/deps/7zip/LzmaEnc.c @@ -2828,12 +2828,13 @@ SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, nowPos64 = p->nowPos64; RangeEnc_Init(&p->rc); - p->rc.outStream = &outStream.vt; if (desiredPackSize == 0) return SZ_ERROR_OUTPUT_EOF; + p->rc.outStream = &outStream.vt; res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize); + p->rc.outStream = NULL; *unpackSize = (uint32_t)(p->nowPos64 - nowPos64); *destLen -= outStream.rem; diff --git a/deps/dr/dr_flac.h b/deps/dr/dr_flac.h index 568a4016e0..fd54402327 100644 --- a/deps/dr/dr_flac.h +++ b/deps/dr/dr_flac.h @@ -682,10 +682,17 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr #define DRFLAC_NO_CPUID #endif - #ifdef __linux__ -#define _BSD_SOURCE -#include + #ifndef _BSD_SOURCE + #define _BSD_SOURCE + #endif + #ifndef _DEFAULT_SOURCE + #define _DEFAULT_SOURCE + #endif + #ifndef __USE_BSD + #define __USE_BSD + #endif + #include #endif #if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) diff --git a/deps/dr/dr_mp3.h b/deps/dr/dr_mp3.h index 1686188747..f4a62ec01a 100644 --- a/deps/dr/dr_mp3.h +++ b/deps/dr/dr_mp3.h @@ -1064,12 +1064,22 @@ static void drmp3_L3_midside_stereo(float *left, int n) int i = 0; float *right = left + 576; #if DRMP3_HAVE_SIMD - if (drmp3_have_simd()) for (; i < n - 3; i += 4) + if (drmp3_have_simd()) { - drmp3_f4 vl = DRMP3_VLD(left + i); - drmp3_f4 vr = DRMP3_VLD(right + i); - DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr)); - DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr)); + for (; i < n - 3; i += 4) + { + drmp3_f4 vl = DRMP3_VLD(left + i); + drmp3_f4 vr = DRMP3_VLD(right + i); + DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr)); + DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr)); + } +#ifdef __GNUC__ + /* Workaround for spurious -Waggressive-loop-optimizations warning from gcc. + * For more info see: https://github.com/lieff/minimp3/issues/88 + */ + if (__builtin_constant_p(n % 4 == 0) && n % 4 == 0) + return; +#endif } #endif for (; i < n; i++) diff --git a/deps/game_ai_lib/.gitignore b/deps/game_ai_lib/.gitignore new file mode 100644 index 0000000000..87b50f35c4 --- /dev/null +++ b/deps/game_ai_lib/.gitignore @@ -0,0 +1,8 @@ +libtorch/ +build/ +CMakeFiles/ +Debug/ +libtorch/ +win/ +*.zip +.vscode/ \ No newline at end of file diff --git a/deps/game_ai_lib/CMakeLists.txt b/deps/game_ai_lib/CMakeLists.txt new file mode 100644 index 0000000000..586aac7448 --- /dev/null +++ b/deps/game_ai_lib/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.0 FATAL_ERROR) +project(custom_ops) + +find_package(Torch REQUIRED) +find_package(OpenCV REQUIRED) +include_directories(${OpenCV_INCLUDE_DIRS}) + +add_executable(test test.cpp RetroModel.cpp) +target_link_libraries(test "${TORCH_LIBRARIES}" ${OpenCV_LIBS}) + +add_library(game_ai SHARED GameAILocal.cpp RetroModel.cpp games/NHL94GameAI.cpp games/NHL94GameData.cpp games/DefaultGameAI.cpp utils/data.cpp utils/memory.cpp utils/utils.cpp) + +target_link_libraries(game_ai "${TORCH_LIBRARIES}" ${OpenCV_LIBS}) + +set_property(TARGET test PROPERTY CXX_STANDARD 17) +set_property(TARGET game_ai PROPERTY CXX_STANDARD 17) + +if (MSVC) + file(GLOB TORCH_DLLS "${TORCH_INSTALL_PREFIX}/lib/*.dll") + add_custom_command(TARGET test + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${TORCH_DLLS} + $) +endif (MSVC) \ No newline at end of file diff --git a/deps/game_ai_lib/GameAI.h b/deps/game_ai_lib/GameAI.h new file mode 100644 index 0000000000..c747b6d038 --- /dev/null +++ b/deps/game_ai_lib/GameAI.h @@ -0,0 +1,41 @@ +#pragma once + +#ifdef __cplusplus + +#include +#include +#include +#include +#include + +#endif + + +typedef void (*debug_log_t)(int level, const char *fmt, ...); + +#define GAMEAI_MAX_BUTTONS 16 +#define GAMEAI_SKIPFRAMES 4 + + +#ifdef __cplusplus + +class GameAI { +public: + virtual void Init(void * ram_ptr, int ram_size) {}; + virtual void Think(bool buttons[GAMEAI_MAX_BUTTONS], int player, const void *frame_data, unsigned int frame_width, unsigned int frame_height, unsigned int frame_pitch, unsigned int pixel_format) {}; + void SetShowDebug(const bool show){ this->showDebug = show; }; + void SetDebugLog(debug_log_t func){debugLogFunc = func;}; + +private: + bool showDebug; + debug_log_t debugLogFunc; +}; + +#endif + +typedef void * (*create_game_ai_t)(const char *); +typedef void (*destroy_game_ai_t)(void * obj_ptr); +typedef void (*game_ai_lib_init_t)(void * obj_ptr, void * ram_ptr, int ram_size); +typedef void (*game_ai_lib_think_t)(void * obj_ptr, bool buttons[GAMEAI_MAX_BUTTONS], int player, const void *frame_data, unsigned int frame_width, unsigned int frame_height, unsigned int frame_pitch, unsigned int pixel_format); +typedef void (*game_ai_lib_set_show_debug_t)(void * obj_ptr, const bool show); +typedef void (*game_ai_lib_set_debug_log_t)(void * obj_ptr, debug_log_t func); diff --git a/deps/game_ai_lib/GameAILocal.cpp b/deps/game_ai_lib/GameAILocal.cpp new file mode 100644 index 0000000000..a850dbf4f9 --- /dev/null +++ b/deps/game_ai_lib/GameAILocal.cpp @@ -0,0 +1,215 @@ + +#include + +#include "GameAI.h" +#include "./games/NHL94GameAI.h" +#include "./games/DefaultGameAI.h" + + +#if _WIN32 +#define DllExport __declspec( dllexport ) +#else +#define DllExport +#endif + + +//======================================================= +// C API +//======================================================= +extern "C" DllExport void game_ai_lib_init(void * obj_ptr, void * ram_ptr, int ram_size) +{ + if (obj_ptr) + static_cast(obj_ptr)->Init(ram_ptr, ram_size); +} + +extern "C" DllExport void game_ai_lib_think(void * obj_ptr,bool buttons[GAMEAI_MAX_BUTTONS], int player, const void *frame_data, unsigned int frame_width, unsigned int frame_height, unsigned int frame_pitch, unsigned int pixel_format) +{ + if (obj_ptr) + static_cast(obj_ptr)->Think(buttons, player, frame_data, frame_width, frame_height, frame_pitch, pixel_format); +} + +extern "C" DllExport void game_ai_lib_set_show_debug(void * obj_ptr,const bool show) +{ + if (obj_ptr) + static_cast(obj_ptr)->SetShowDebug(show); +} + +extern "C" DllExport void game_ai_lib_set_debug_log(void * obj_ptr,debug_log_t func) +{ + if (obj_ptr) + static_cast(obj_ptr)->SetDebugLog(func); +} + +extern "C" DllExport void * create_game_ai(const char * name) +{ + std::filesystem::path path = name; + std::string game_name = path.parent_path().filename().string(); + + GameAILocal * ptr = nullptr; + + if(game_name == "NHL941on1-Genesis") + { + ptr = new NHL94GameAI(); + } + else + { + ptr = new DefaultGameAI(); + } + + if (ptr) + { + ptr->full_path = path.string(); + ptr->dir_path = path.parent_path().string(); + ptr->game_name = game_name; + + ptr->DebugPrint("CreateGameAI"); + ptr->DebugPrint(name); + ptr->DebugPrint(game_name.c_str()); + } + + return (void *) ptr; +} + +extern "C" DllExport void destroy_game_ai(void * obj_ptr) +{ + if (obj_ptr) + { + GameAILocal * gaLocal = nullptr; + gaLocal = static_cast(obj_ptr); + delete gaLocal; + } +} + +//======================================================= +// GameAILocal::InitRAM +//======================================================= +void GameAILocal::InitRAM(void * ram_ptr, int ram_size) +{ + std::filesystem::path memDataPath = dir_path; + memDataPath += "/data.json"; + + //retro_data.load() + //std::cout << memDataPath << std::endl; + retro_data.load(memDataPath.string()); + + Retro::AddressSpace* m_addressSpace = nullptr; + m_addressSpace = &retro_data.addressSpace(); + m_addressSpace->reset(); + //Retro::configureData(data, m_core); + //reconfigureAddressSpace(); + retro_data.addressSpace().setOverlay(Retro::MemoryOverlay{ '=', '>', 2 }); + + m_addressSpace->addBlock(16711680, ram_size, ram_ptr); + std::cout << "RAM size:" << ram_size << std::endl; + std::cout << "RAM ptr:" << ram_ptr << std::endl; +} + +//======================================================= +// GameAILocal::LoadConfig_Player +//======================================================= +void GameAILocal::LoadConfig_Player(const nlohmann::detail::iter_impl &player) +{ + for (auto var = player->cbegin(); var != player->cend(); ++var) + { + if(var.key() == "models") + { + for (auto model = var.value().cbegin(); model != var.value().cend(); ++model) + { + std::filesystem::path modelPath = dir_path; + modelPath += "/"; + modelPath += model.value().get(); + + RetroModel * load_model = this->LoadModel(modelPath.string().c_str()); + + if (models.count(model.key()) == 0) + { + models.insert(std::pair(model.key(), load_model)); + } + } + } + } +} + +//======================================================= +// GameAILocal::LoadConfig +//======================================================= +void GameAILocal::LoadConfig() +{ + DebugPrint("GameAILocal::LoadConfig()"); + + std::filesystem::path configPath = dir_path; + configPath += "/config.json"; + DebugPrint(configPath.string().c_str()); + + std::ifstream file; + try { + file.open(configPath); + //std::cout << file.rdbuf(); + //std::cerr << "Error: " << strerror(errno); + //std::cout << file.get(); + } + catch (std::exception & e){ + DebugPrint("Error opening config file"); + DebugPrint(e.what()); + } + + //file.clear(); + //file.seekg(0, std::ios::beg); + + using nlohmann::json; + + json manifest; + try { + file >> manifest; + } catch (json::exception& e) { + DebugPrint("Error Loading config"); + DebugPrint(e.what()); + return; + } + + const auto& p1 = const_cast(manifest).find("p1"); + if (p1 == manifest.cend()) + { + DebugPrint("Error Loading config, no p1"); + return; + } + + LoadConfig_Player(p1); + + const auto& p2 = const_cast(manifest).find("p2"); + if (p2 == manifest.cend()) + { + DebugPrint("Error Loading config, no p1"); + return; + } + + LoadConfig_Player(p2); +} + +//======================================================= +// GameAILocal::LoadModel +//======================================================= +RetroModel * GameAILocal::LoadModel(const char * path) +{ + RetroModelPytorch * model = new RetroModelPytorch(); + + model->LoadModel(std::string(path)); + + return dynamic_cast(model); +} + +//======================================================= +// GameAILocal::DebugPrint +//======================================================= +void GameAILocal::DebugPrint(const char * msg) +{ + std::cout << msg << std::endl; + if (showDebug && debugLogFunc) + { + std::cout << msg << std::endl; + + debugLogFunc(0, msg); + } +} + + diff --git a/deps/game_ai_lib/GameAILocal.h b/deps/game_ai_lib/GameAILocal.h new file mode 100644 index 0000000000..11a745498a --- /dev/null +++ b/deps/game_ai_lib/GameAILocal.h @@ -0,0 +1,45 @@ +#pragma once + +#include "GameAI.h" +#include "RetroModel.h" + +#include +#include +#include +#include +#include +#include "utils/data.h" +#include "./utils/json.hpp" + + + +class GameAILocal : public GameAI { +public: + GameAILocal():showDebug(false), + debugLogFunc(nullptr){}; + + + RetroModel * LoadModel(const char * path); + void SetShowDebug(const bool show){ this->showDebug = show; }; + void SetDebugLog(debug_log_t func){debugLogFunc = func;}; + void DebugPrint(const char * msg); + +protected: + void InitRAM(void * ram_ptr, int ram_size); + void LoadConfig(); + void LoadConfig_Player(const nlohmann::detail::iter_impl &player); + + + bool showDebug; + debug_log_t debugLogFunc; + Retro::GameData retro_data; + + std::map models; + +public: + std::string full_path; + std::string dir_path; + std::string game_name; +}; + + diff --git a/deps/game_ai_lib/README.md b/deps/game_ai_lib/README.md new file mode 100644 index 0000000000..6d28b03b03 --- /dev/null +++ b/deps/game_ai_lib/README.md @@ -0,0 +1,64 @@ +# stable-retro lib +Library to be used with emulator frontends (such as RetroArch) to enable ML models to overide player input. +Warning: Still in early prototype version + +## Build for Linux + +``` +sudo apt update +sudo apt install git cmake unzip libqt5opengl5-dev qtbase5-dev zlib1g-dev python3 python3-pip build-essential libopencv-dev +``` + +``` +git clone https://github.com/MatPoliquin/stable-retro-scripts.git +``` + +Download pytorch C++ lib: +``` +cd stable-retro-scripts/ef_lib/ +wget https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-2.3.1%2Bcpu.zip +unzip libtorch-cxx11-abi-shared-with-deps-2.3.1+cpu.zip +``` + +Generate makefiles and compile +``` +cmake . -DCMAKE_PREFIX_PATH=./libtorch +make +``` + +## Build for Windows + +Clone stable-retro-scripts repo + +Download pytorch C++ lib for Windows: +``` +wget https://download.pytorch.org/libtorch/cpu/libtorch-win-shared-with-deps-2.3.1%2Bcpu.zip -o libtorch_win.zip +Expand-Archive libtorch_win.zip +``` +Note: 2.3.1 might have missing intel MLK dll issue: +https://github.com/pytorch/pytorch/issues/124009 +So you can use nightly build instead and it fixes the issue: +wget https://download.pytorch.org/libtorch/nightly/cpu/libtorch-win-shared-with-deps-latest.zip -o libtorch_win.zip + +Download and Extract OpenCV for Windows: +``` +https://sourceforge.net/projects/opencvlibrary/files/4.10.0/ +``` +The DLLs will be found here: +YourOpenCVFolder\opencv\build\x64\vc16\lib + +Generate makefiles and compile +``` +cd stable-retro-scripts +mkdir build +cd build +cmake .. -DCMAKE_PREFIX_PATH=Absolute\path\to\libtorch_win -DOpenCV_DIR=Absolute\path\to\opencv\build\x64\vc16\lib +cmake --build . --config Release +``` + +## Test the lib + +``` +export LD_LIBRARY_PATH=/path/to/game_ai.so +./retroarch +``` diff --git a/deps/game_ai_lib/RetroModel.cpp b/deps/game_ai_lib/RetroModel.cpp new file mode 100644 index 0000000000..4a077952d8 --- /dev/null +++ b/deps/game_ai_lib/RetroModel.cpp @@ -0,0 +1,94 @@ +#include "RetroModel.h" + + +//======================================================= +// RetroModelPytorch::LoadModel +//======================================================= +void RetroModelPytorch::LoadModel(std::string path) +{ + try { + this->module = torch::jit::load(path); + std::cerr << "LOADED MODEL:!" << path << std::endl; + } + catch (const c10::Error& e) { + std::cerr << "error loading the model\n"; + return; + } +} + +//======================================================= +// RetroModelPytorch::Forward +//======================================================= +void RetroModelPytorch::Forward(std::vector & output, const std::vector & input) +{ + std::vector inputs; + + at::Tensor tmp = torch::zeros({1, input.size()}); + + for(int i=0; i < input.size(); i++) + { + tmp[0][i] = input[i]; + } + + inputs.push_back(tmp); + + at::Tensor result = module.forward(inputs).toTuple()->elements()[0].toTensor(); + + for(int i=0; i < output.size(); i++) + { + output[i] = result[0][i].item(); + } +} + +//======================================================= +// RetroModelPytorch::Forward +//======================================================= +void RetroModelPytorch::Forward(std::vector & output, RetroModelFrameData & input) +{ + std::vector inputs; + + cv::Mat image(cv::Size(input.width, input.height), CV_8UC2, input.data); + cv::Mat rgb; + cv::Mat gray; + cv::Mat result; + + // add new frame on the stack + cv::Mat * newFrame = input.PushNewFrameOnStack(); + + // Downsample to 84x84 and turn to greyscale + cv::cvtColor(image, gray, cv::COLOR_BGR5652GRAY); + cv::resize(gray, result, cv::Size(84,84), cv::INTER_AREA); + result.copyTo(*newFrame); + + /*cv::namedWindow("Display Image", cv::WINDOW_NORMAL); + cv::imshow("Display Image", result); + cv::waitKey(0);*/ + + at::Tensor tmp = torch::ones({1, 4, 84, 84}); + + for(auto i : {0,1,2,3}) + { + if(input.stack[i]->data) + tmp[0][3-i] = torch::from_blob(input.stack[i]->data, { result.rows, result.cols }, at::kByte); + } + + + /*test[0][3] = torch::from_blob(input.stack[0]->data, { result.rows, result.cols }, at::kByte); + if(input.stack[1]->data) + test[0][2] = torch::from_blob(input.stack[1]->data, { result.rows, result.cols }, at::kByte); + if(input.stack[2]->data) + test[0][1] = torch::from_blob(input.stack[2]->data, { result.rows, result.cols }, at::kByte); + if(input.stack[3]->data) + test[0][0] = torch::from_blob(input.stack[3]->data, { result.rows, result.cols }, at::kByte);*/ + + inputs.push_back(tmp); + + // Execute the model and turn its output into a tensor. + torch::jit::IValue ret = module.forward(inputs); + at::Tensor actions = ret.toTuple()->elements()[0].toTensor(); + + for(int i=0; i < output.size(); i++) + { + output[i] = actions[0][i].item(); + } +} \ No newline at end of file diff --git a/deps/game_ai_lib/RetroModel.h b/deps/game_ai_lib/RetroModel.h new file mode 100644 index 0000000000..9c32412296 --- /dev/null +++ b/deps/game_ai_lib/RetroModel.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class RetroModelFrameData +{ +public: + RetroModelFrameData(): data(nullptr) + { + stack[0] = new cv::Mat; + stack[1] = new cv::Mat; + stack[2] = new cv::Mat; + stack[3] = new cv::Mat; + } + + ~RetroModelFrameData() + { + if(stack[0]) delete stack[0]; + if(stack[1]) delete stack[1]; + if(stack[2]) delete stack[2]; + if(stack[3]) delete stack[3]; + } + + cv::Mat * PushNewFrameOnStack() + { + //push everything down + cv::Mat * tmp = stack[3]; + stack[3] = stack[2]; + stack[2] = stack[1]; + stack[1] = stack[0]; + stack[0] = tmp; + + return stack[0]; + } + + + void *data; + unsigned int width; + unsigned int height; + unsigned int pitch; + unsigned int format; + + cv::Mat * stack[4]; +}; + +class RetroModel { +public: + virtual void Forward(std::vector & output, const std::vector & input)=0; + virtual void Forward(std::vector & output, RetroModelFrameData & input)=0; +}; + +class RetroModelPytorch : public RetroModel { +public: + virtual void LoadModel(std::string); + virtual void Forward(std::vector & output, const std::vector & input); + virtual void Forward(std::vector & output, RetroModelFrameData & input); + +private: + torch::jit::script::Module module; +}; + + + diff --git a/deps/game_ai_lib/games/DefaultGameAI.cpp b/deps/game_ai_lib/games/DefaultGameAI.cpp new file mode 100644 index 0000000000..486d043772 --- /dev/null +++ b/deps/game_ai_lib/games/DefaultGameAI.cpp @@ -0,0 +1,55 @@ +#include "DefaultGameAI.h" +#include +#include +#include +#include + +enum DefaultButtons { + INPUT_B = 0, + INPUT_A = 1, + INPUT_MODE = 2, + INPUT_START = 3, + INPUT_UP = 4, + INPUT_DOWN = 5, + INPUT_LEFT = 6, + INPUT_RIGHT = 7, + INPUT_C = 8, + INPUT_Y = 9, + INPUT_X = 10, + INPUT_Z = 11, + INPUT_MAX = 12 +}; + +//======================================================= +// DefaultGameAI::Init +//======================================================= +void DefaultGameAI::Init(void * ram_ptr, int ram_size) +{ + LoadConfig(); + + InitRAM(ram_ptr, ram_size); +} + +//======================================================= +// DefaultGameAI::Think +//======================================================= +void DefaultGameAI::Think(bool buttons[GAMEAI_MAX_BUTTONS], int player, const void *frame_data, unsigned int frame_width, unsigned int frame_height, unsigned int frame_pitch, unsigned int pixel_format) +{ + std::vector output(DefaultButtons::INPUT_MAX); + + input.data = (void *) frame_data; + input.width = frame_width; + input.height = frame_height; + input.pitch = frame_pitch; + input.format = pixel_format; + + models["Model"]->Forward(output, input); + + for (int i=0; i < output.size(); i++) + { + buttons[i] = output[i] >= 1.0 ? 1 : 0; + } + + buttons[DefaultButtons::INPUT_START] = 0; + buttons[DefaultButtons::INPUT_MODE] = 0; +} \ No newline at end of file diff --git a/deps/game_ai_lib/games/DefaultGameAI.h b/deps/game_ai_lib/games/DefaultGameAI.h new file mode 100644 index 0000000000..34f206b94f --- /dev/null +++ b/deps/game_ai_lib/games/DefaultGameAI.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../GameAILocal.h" +#include "memory.h" +#include "../utils/data.h" + + +class DefaultGameAI : public GameAILocal { +public: + virtual void Init(void * ram_ptr, int ram_size); + virtual void Think(bool buttons[GAMEAI_MAX_BUTTONS], int player, const void *frame_data, unsigned int frame_width, unsigned int frame_height, unsigned int frame_pitch, unsigned int pixel_format); + +private: + RetroModel * model; + RetroModelFrameData input; +}; \ No newline at end of file diff --git a/deps/game_ai_lib/games/NHL94GameAI.cpp b/deps/game_ai_lib/games/NHL94GameAI.cpp new file mode 100644 index 0000000000..864bbfe97e --- /dev/null +++ b/deps/game_ai_lib/games/NHL94GameAI.cpp @@ -0,0 +1,225 @@ +#include "NHL94GameAI.h" +#include +#include +#include +#include + +//======================================================= +// NHL94GameAI::Init +//======================================================= +void NHL94GameAI::Init(void * ram_ptr, int ram_size) +{ + LoadConfig(); + + InitRAM(ram_ptr, ram_size); + + static_assert(NHL94NeuralNetInput::NN_INPUT_MAX == 16); + + isShooting = false; +} + +//======================================================= +// NHL94GameAI::SetModelInputs +//======================================================= +void NHL94GameAI::SetModelInputs(std::vector & input, const NHL94Data & data) +{ + // players + input[NHL94NeuralNetInput::P1_X] = (float)data.p1_x / (float) NHL94NeuralNetInput::MAX_PLAYER_X; + input[NHL94NeuralNetInput::P1_Y] = (float)data.p1_y / (float) NHL94NeuralNetInput::MAX_PLAYER_Y; + input[NHL94NeuralNetInput::P2_X] = (float)data.p2_x / (float) NHL94NeuralNetInput::MAX_PLAYER_X; + input[NHL94NeuralNetInput::P2_Y] = (float) data.p2_y / (float) NHL94NeuralNetInput::MAX_PLAYER_Y; + input[NHL94NeuralNetInput::G2_X] = (float) data.g2_x / (float) NHL94NeuralNetInput::MAX_PLAYER_X; + input[NHL94NeuralNetInput::G2_Y] = (float) data.g2_y / (float) NHL94NeuralNetInput::MAX_PLAYER_Y; + input[NHL94NeuralNetInput::P1_VEL_X] = (float) data.p1_vel_x / (float) NHL94NeuralNetInput::MAX_VEL_XY; + input[NHL94NeuralNetInput::P1_VEL_Y] = (float) data.p1_vel_y / (float) NHL94NeuralNetInput::MAX_VEL_XY; + input[NHL94NeuralNetInput::P2_VEL_X] = (float) data.p2_vel_x / (float) NHL94NeuralNetInput::MAX_VEL_XY; + input[NHL94NeuralNetInput::P2_VEL_Y] = (float) data.p2_vel_y / (float) NHL94NeuralNetInput::MAX_VEL_XY; + + // puck + input[NHL94NeuralNetInput::PUCK_X] = (float) data.puck_x / (float) NHL94NeuralNetInput::MAX_PLAYER_X; + input[NHL94NeuralNetInput::PUCK_Y] = (float) data.puck_y / (float) NHL94NeuralNetInput::MAX_PLAYER_Y; + input[NHL94NeuralNetInput::PUCK_VEL_X] = (float) data.puck_vel_x / (float) NHL94NeuralNetInput::MAX_VEL_XY; + input[NHL94NeuralNetInput::PUCK_VEL_Y] = (float) data.puck_vel_y / (float) NHL94NeuralNetInput::MAX_VEL_XY; + + input[NHL94NeuralNetInput::P1_HASPUCK] = data.p1_haspuck ? 0.0 : 1.0; + input[NHL94NeuralNetInput::G1_HASPUCK] = data.g1_haspuck ? 0.0 : 1.0; +} + +//======================================================= +// NHL94GameAI::GotoTarget +//======================================================= +void NHL94GameAI::GotoTarget(std::vector & input, int vec_x, int vec_y) +{ + if (vec_x > 0) + input[NHL94Buttons::INPUT_LEFT] = 1; + else + input[NHL94Buttons::INPUT_RIGHT] = 1; + + if (vec_y > 0) + input[NHL94Buttons::INPUT_DOWN] = 1; + else + input[NHL94Buttons::INPUT_UP] = 1; +} + +//======================================================= +// isInsideAttackZone +//======================================================= +static bool isInsideAttackZone(NHL94Data & data) +{ + if (data.attack_zone_y > 0 && data.p1_y >= data.attack_zone_y) + { + return true; + } + else if (data.attack_zone_y < 0 && data.p1_y <= data.attack_zone_y) + { + return true; + } + + return false; +} + +//======================================================= +// isInsideScoreZone +//======================================================= +static bool isInsideScoreZone(NHL94Data & data) +{ + if (data.p1_y < data.score_zone_top && data.p1_y > data.score_zone_bottom) + { + return true; + } + + return false; +} + +//======================================================= +// isInsideDefenseZone +//======================================================= +static bool isInsideDefenseZone(NHL94Data & data) +{ + if (data.defense_zone_y > 0 && data.p1_y >= data.defense_zone_y) + { + return true; + } + else if (data.defense_zone_y < 0 && data.p1_y <= data.defense_zone_y) + { + return true; + } + + return false; +} + +//======================================================= +// NHL94GameAI::Think +//======================================================= +void NHL94GameAI::Think(bool buttons[GAMEAI_MAX_BUTTONS], int player, const void *frame_data, unsigned int frame_width, unsigned int frame_height, unsigned int frame_pitch, unsigned int pixel_format) +{ + NHL94Data data; + data.Init(retro_data); + + if(player == 1) + { + data.Flip(); + + if(data.period % 2 == 0) + { + data.FlipZones(); + } + } + else if (player == 0) + { + if(data.period % 2 == 1) + { + data.FlipZones(); + } + } + + + std::vector input(16); + std::vector output(12); + + this->SetModelInputs(input, data); + + if (data.p1_haspuck) + { + DebugPrint("have puck"); + + if (isInsideAttackZone(data)) + { + DebugPrint(" in attackzone"); + models["ScoreGoal"]->Forward(output, input); + output[NHL94Buttons::INPUT_C] = 0; + output[NHL94Buttons::INPUT_B] = 0; + + if (isInsideScoreZone(data)) + { + if (data.p1_vel_x >= 30 && data.puck_x > -23 && data.puck_x < 0) + { + DebugPrint("Shoot"); + output[NHL94Buttons::INPUT_C] = 1; + isShooting = true; + } + else if(data.p1_vel_x <= -30 && data.puck_x < 23 && data.puck_x > 0) + { + DebugPrint("Shoot"); + output[NHL94Buttons::INPUT_C] = 1; + isShooting = true; + } + } + } + else + { + this->GotoTarget(output, data.p1_x, -data.attack_zone_y); + } + } + else if (data.g1_haspuck) + { + if (rand() > (RAND_MAX / 2)) + output[NHL94Buttons::INPUT_B] = 1; + } + else + { + DebugPrint("Don't have puck"); + isShooting = false; + + if (isInsideDefenseZone(data) && data.p2_haspuck) + { + DebugPrint(" DefenseModel->Forward"); + models["DefenseZone"]->Forward(output, input); + } + else + { + DebugPrint(" GOTO TARGET"); + GotoTarget(output, data.p1_x - data.puck_x, data.p1_y - data.puck_y); + } + + if (isShooting) + { + //output[NHL94Buttons::INPUT_MODE] = 1; + DebugPrint("Shooting"); + output[NHL94Buttons::INPUT_C] = 1; + } + } + + assert(output.size() <= 16); + for (int i=0; i < output.size(); i++) + { + buttons[i] = output[i] >= 1.0 ? 1 : 0; + } + + + buttons[NHL94Buttons::INPUT_START] = 0; + buttons[NHL94Buttons::INPUT_MODE] = 0; + buttons[NHL94Buttons::INPUT_A] = 0; + //buttons[NHL94Buttons::INPUT_B] = 0; + //buttons[NHL94Buttons::INPUT_C] = 0; + buttons[NHL94Buttons::INPUT_X] = 0; + buttons[NHL94Buttons::INPUT_Y] = 0; + buttons[NHL94Buttons::INPUT_Z] = 0; + + //Flip directions + if(data.period % 2 != player) + { + std::swap(buttons[NHL94Buttons::INPUT_UP], buttons[NHL94Buttons::INPUT_DOWN]); + std::swap(buttons[NHL94Buttons::INPUT_LEFT], buttons[NHL94Buttons::INPUT_RIGHT]); + } +} \ No newline at end of file diff --git a/deps/game_ai_lib/games/NHL94GameAI.h b/deps/game_ai_lib/games/NHL94GameAI.h new file mode 100644 index 0000000000..7d9fa6d0ca --- /dev/null +++ b/deps/game_ai_lib/games/NHL94GameAI.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../GameAILocal.h" +#include "NHL94GameData.h" + +class NHL94GameAI : public GameAILocal { +public: + virtual void Init(void * ram_ptr, int ram_size); + virtual void Think(bool buttons[GAMEAI_MAX_BUTTONS], int player, const void *frame_data, unsigned int frame_width, unsigned int frame_height, unsigned int frame_pitch, unsigned int pixel_format); + + void SetModelInputs(std::vector & input, const NHL94Data & data); + void GotoTarget(std::vector & input, int vec_x, int vec_y); + +private: + bool isShooting; +}; \ No newline at end of file diff --git a/deps/game_ai_lib/games/NHL94GameData.cpp b/deps/game_ai_lib/games/NHL94GameData.cpp new file mode 100644 index 0000000000..d315be9099 --- /dev/null +++ b/deps/game_ai_lib/games/NHL94GameData.cpp @@ -0,0 +1,108 @@ +#include "NHL94GameData.h" + +//======================================================= +// NHL94Data::Init +//======================================================= +void NHL94Data::Init(const Retro::GameData & data) +{ + // players + p1_x = data.lookupValue("p1_x").cast(); + p1_y = data.lookupValue("p1_y").cast(); + p2_x = data.lookupValue("p2_x").cast(); + p2_y = data.lookupValue("p2_y").cast(); + p1_vel_x = data.lookupValue("p1_vel_x").cast(); + p1_vel_y = data.lookupValue("p1_vel_y").cast(); + p2_vel_x = data.lookupValue("p2_vel_x").cast(); + p2_vel_y = data.lookupValue("p2_vel_y").cast(); + + // goalies + g1_x = data.lookupValue("g1_x").cast(); + g1_y = data.lookupValue("g1_y").cast(); + g2_x = data.lookupValue("g2_x").cast(); + g2_y = data.lookupValue("g2_y").cast(); + + // puck + puck_x = data.lookupValue("puck_x").cast(); + puck_y = data.lookupValue("puck_y").cast(); + puck_vel_x = data.lookupValue("puck_vel_x").cast(); + puck_vel_y = data.lookupValue("puck_vel_y").cast(); + + p1_fullstar_x = data.lookupValue("fullstar_x").cast(); + p1_fullstar_y = data.lookupValue("fullstar_y").cast(); + p2_fullstar_x = data.lookupValue("p2_fullstar_x").cast(); + p2_fullstar_y = data.lookupValue("p2_fullstar_y").cast(); + + period = data.lookupValue("period").cast(); + + + // Knowing if the player has the puck is tricky since the fullstar in the game is not aligned with the player every frame + // There is an offset of up to 2 sometimes + + if (std::abs(p1_x - p1_fullstar_x) < 3 && std::abs(p1_y - p1_fullstar_y) < 3) + p1_haspuck = true; + else + p1_haspuck = false; + + if(std::abs(p2_x - p1_fullstar_x) < 3 && std::abs(p2_y - p1_fullstar_y) < 3) + p2_haspuck = true; + else + p2_haspuck = false; + + if(std::abs(g1_x - p1_fullstar_x) < 3 && std::abs(g1_y - p1_fullstar_y) < 3) + g1_haspuck = true; + else + g1_haspuck = false; + + if(std::abs(g2_x - p1_fullstar_x) < 3 && std::abs(g2_y - p1_fullstar_y) < 3) + g2_haspuck = true; + else + g2_haspuck = false; + + + attack_zone_y = NHL94Const::ATACKZONE_POS_Y; + defense_zone_y = NHL94Const::DEFENSEZONE_POS_Y; + score_zone_top = NHL94Const::SCORE_ZONE_TOP; + score_zone_bottom = NHL94Const::SCORE_ZONE_BOTTOM; +} + +//======================================================= +// NHL94Data::Flip +//======================================================= +void NHL94Data::Flip() +{ + std::swap(p1_x, p2_x); + std::swap(p1_y, p2_y); + std::swap(g1_x, g2_x); + std::swap(g1_y, g2_y); + std::swap(p1_haspuck, p2_haspuck); + std::swap(g1_haspuck, g2_haspuck); + + std::swap(p1_vel_x, p2_vel_x); + std::swap(p1_vel_y, p2_vel_y); +} + +//======================================================= +// NHL94Data::FlipZones +//======================================================= +void NHL94Data::FlipZones() +{ + p1_x = -p1_x; + p1_y = -p1_y; + p2_x = -p2_x; + p2_y = -p2_y; + g1_x = -g1_x; + g1_y = -g1_y; + g2_x = -g2_x; + g2_y = -g2_y; + + p1_vel_x = -p1_vel_x; + p1_vel_y = -p1_vel_y; + p2_vel_x = -p2_vel_x; + p2_vel_y = -p2_vel_y; + + puck_x = -puck_x; + puck_y = -puck_y; + + puck_vel_x = -puck_vel_x; + puck_vel_y = -puck_vel_y; +} \ No newline at end of file diff --git a/deps/game_ai_lib/games/NHL94GameData.h b/deps/game_ai_lib/games/NHL94GameData.h new file mode 100644 index 0000000000..2f1bf4c532 --- /dev/null +++ b/deps/game_ai_lib/games/NHL94GameData.h @@ -0,0 +1,100 @@ +#pragma once + +#include "memory.h" +#include "../utils/data.h" + +enum NHL94Buttons { + INPUT_B = 0, + INPUT_A = 1, + INPUT_MODE = 2, + INPUT_START = 3, + INPUT_UP = 4, + INPUT_DOWN = 5, + INPUT_LEFT = 6, + INPUT_RIGHT = 7, + INPUT_C = 8, + INPUT_Y = 9, + INPUT_X = 10, + INPUT_Z = 11, + INPUT_MAX = 12 +}; + +enum NHL94NeuralNetInput { + P1_X = 0, + P1_Y, + P1_VEL_X, + P1_VEL_Y, + P2_X, + P2_Y, + P2_VEL_X, + P2_VEL_Y, + PUCK_X, + PUCK_Y, + PUCK_VEL_X, + PUCK_VEL_Y, + G2_X, + G2_Y, + P1_HASPUCK, + G1_HASPUCK, + NN_INPUT_MAX, + + // Used for normalization + MAX_PLAYER_X = 120, + MAX_PLAYER_Y = 270, + MAX_PUCK_X = 130, + MAX_PUCK_Y = 270, + MAX_VEL_XY = 50 +}; + + +enum NHL94Const { + ATACKZONE_POS_Y = 100, + DEFENSEZONE_POS_Y = -80, + SCORE_ZONE_TOP = 230, + SCORE_ZONE_BOTTOM = 210, +}; + +class NHL94Data { +public: + int p1_x; + int p1_y; + int p2_x; + int p2_y; + int p1_vel_x; + int p1_vel_y; + int p2_vel_x; + int p2_vel_y; + int g1_x; + int g1_y; + int g2_x; + int g2_y; + + int puck_x; + int puck_y; + int puck_vel_x; + int puck_vel_y; + + int p1_fullstar_x; + int p1_fullstar_y; + int p2_fullstar_x; + int p2_fullstar_y; + + + bool p1_haspuck; + bool g1_haspuck; + bool p2_haspuck; + bool g2_haspuck; + + int attack_zone_y; + int defense_zone_y; + int score_zone_top; + int score_zone_bottom; + + int period; + + void Init(const Retro::GameData & data); + + void Flip(); + + void FlipZones(); +}; \ No newline at end of file diff --git a/deps/game_ai_lib/test.cpp b/deps/game_ai_lib/test.cpp new file mode 100644 index 0000000000..5fa406b967 --- /dev/null +++ b/deps/game_ai_lib/test.cpp @@ -0,0 +1,202 @@ +// test of game ai dynamic lib +#include +#include +#include +#include +#include +#include +#include "GameAI.h" +#include "RetroModel.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + + + +#if 0 +/* +#include "onnxruntime_cxx_api.h" + +void Test_ONNX() +{ + +// Load the model and create InferenceSession +Ort::Env env; +std::string model_path = "path/to/your/onnx/model"; +Ort::Session session(env, model_path, Ort::SessionOptions{ nullptr }); +// Load and preprocess the input image to inputTensor +... +// Run inference +std::vector outputTensors = +session.Run(Ort::RunOptions{nullptr}, inputNames.data(), &inputTensor, + inputNames.size(), outputNames.data(), outputNames.size()); +const float* outputDataPtr = outputTensors[0].GetTensorMutableData(); +std::cout << outputDataPtr[0] << std::endl; + + +}*/ + +void Test_Resnet() +{ + + torch::jit::script::Module module; +try { + + module = torch::jit::load("/home/mat/github/stable-retro-scripts/traced_resnet_model.pt"); + //module = torch::jit::load("/home/mat/github/stable-retro-scripts/model.pt"); + std::cerr << "SUCCESS!\n"; + + module.eval(); + + // Create a vector of inputs. + std::vector inputs; + inputs.push_back(torch::ones({1, 3, 224, 224})); + //inputs.push_back(torch::ones({1, 4, 84, 84})); + + // Execute the model and turn its output into a tensor. + at::Tensor output = module.forward(inputs).toTensor(); + //std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n'; + } + catch (const c10::Error& e) { + std::cerr << "error loading the model\n"; + return; + } +} +#endif + +//======================================================= +// test_opencv +//======================================================= +void test_opencv(std::map & tests) +{ + cv::Mat image; + cv::Mat grey; + cv::Mat result; + + image = cv::imread( "../screenshots/wwf.png", cv::IMREAD_COLOR ); + + cv::cvtColor(image, grey, cv::COLOR_RGB2GRAY); + cv::resize(grey, result, cv::Size(84,84), cv::INTER_AREA); + + if ( !image.data ) + { + printf("No image data \n"); + return; + } + cv::namedWindow("Display Image", cv::WINDOW_NORMAL); + cv::imshow("Display Image", result); + + cv::waitKey(1000); + + tests["OPENCV GRAYSCALE DOWNSAMPLE TO 84x84"] = true; +} + +//======================================================= +// test_loadlibrary +//======================================================= +void test_loadlibrary(std::map & tests) +{ + GameAI * ga = nullptr; + create_game_ai_t func = nullptr; + +#ifdef _WIN32 + HINSTANCE hinstLib; + BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; + + hinstLib = LoadLibrary(TEXT("game_ai.dll")); + + if (hinstLib != NULL) + { + tests["LOAD LIBRARY"] = true; + func = (create_game_ai_t) GetProcAddress(hinstLib, "create_game_ai"); + } +#else + void *myso = dlopen("./libgame_ai.so", RTLD_NOW); + + //std::cout << dlerror() << std::endl; + + if(myso) + { + tests["LOAD LIBRARY"] = true; + + func = reinterpret_cast(dlsym(myso, "create_game_ai")); + } +#endif + if(func) + { + tests["GET CREATEGAME FUNC"] = true; + ga = (GameAI *) func("./data/NHL941on1-Genesis/NHL941on1.md"); + + if(ga) + tests["CREATEGAME FUNC"] = true; + } + +#ifdef _WIN32 + fFreeResult = FreeLibrary(hinstLib); +#endif +} + +//======================================================= +// test_pytorch +//======================================================= +void test_pytorch(std::map & tests) +{ + +try { + RetroModelPytorch * model = new RetroModelPytorch(); + + model->LoadModel(std::string("./data/NHL941on1-Genesis/ScoreGoal.pt")); + + std::vector input(16); + std::vector output(12); + + model->Forward(output, input); + + //TODO validate output + tests["LOAD PYTORCH MODEL"] = true; + + } + catch (const c10::Error& e) { + //std::cerr << "error loading the model\n"; + throw std::runtime_error ("error loading the model\n"); + return; + } +} + +int main() +{ + std::map tests; + + tests.insert(std::pair("LOAD LIBRARY",false)); + tests.insert(std::pair("GET CREATEGAME FUNC",false)); + tests.insert(std::pair("CREATEGAME FUNC",false)); + tests.insert(std::pair("OPENCV GRAYSCALE DOWNSAMPLE TO 84x84",false)); + tests.insert(std::pair("LOAD PYTORCH MODEL",false)); + + std::cout << "========== RUNNING TESTS ==========" << std::endl; + + try { + test_loadlibrary(tests); + + test_opencv(tests); + + test_pytorch(tests); + } + catch (std::exception &e) { + std::cout << "============= EXCEPTION =============" << std::endl; + std::cout << e.what(); + } + + std::cout << "============== RESULTS =============" << std::endl; + + for(auto i: tests) + { + const char * result = i.second ? "PASS" : "FAIL"; + std::cout << i.first << "..." << result << std::endl; + } + + return 0; +} \ No newline at end of file diff --git a/deps/game_ai_lib/utils/data.cpp b/deps/game_ai_lib/utils/data.cpp new file mode 100644 index 0000000000..cd8dde65f1 --- /dev/null +++ b/deps/game_ai_lib/utils/data.cpp @@ -0,0 +1,405 @@ +// Adapted from OpenAI's retro source code: +// https://github.com/openai/retro + +#include "data.h" + +//#include "script.h" +#include "utils.h" + +#ifdef ERROR +#undef ERROR +#endif + +#include "json.hpp" + +#include + +using namespace Retro; +using namespace std; +using nlohmann::json; + +static string s_dataDirectory; + +template +T find(json::const_reference j, const string& key) { + const auto& iter = j.find(key); + if (iter == j.end()) { + return T(); + } + try { + T t = *iter; + return t; + } catch (json::exception&) { + return T(); + } +} + +static void setActions(const vector& buttonList, const vector>>& actionsIn, map>& actions) { + actions.clear(); + + for (const auto& outer : actionsIn) { + set sublist; + int mask = 0; + for (const auto& middle : outer) { + int buttons = 0; + for (const auto& button : middle) { + const auto& iter = find(buttonList.begin(), buttonList.end(), button); + buttons |= 1 << (iter - buttonList.begin()); + } + mask |= buttons; + sublist.insert(buttons); + } + actions.emplace(mask, move(sublist)); + } +} + +static unsigned filterAction(unsigned action, const map>& actions) { + unsigned newAction = 0; + for (const auto& actionSet : actions) { + unsigned maskedAction = action & actionSet.first; + if (actionSet.second.find(maskedAction) != actionSet.second.end()) { + newAction |= maskedAction; + } + } + return newAction; +} + +Variable::Variable(const DataType& type, size_t address, uint64_t mask) + : type(type) + , address(address) + , mask(mask) { +} + +bool Variable::operator==(const Variable& other) const { + return type == other.type && address == other.address && mask == other.mask; +} + +bool GameData::load(const string& filename) { + ifstream file(filename); + return load(&file); +} + +bool GameData::load(istream* file) { + json manifest; + try { + *file >> manifest; + } catch (json::exception&) { + return false; + } + + const auto& info = const_cast(manifest).find("info"); + if (info == manifest.cend()) { + return false; + } + + unordered_map oldVars; + oldVars.swap(m_vars); + for (auto var = info->cbegin(); var != info->cend(); ++var) { + if (var->find("address") == var->cend() || var->find("type") == var->cend()) { + oldVars.swap(m_vars); + return false; + } + string dtype = var->at("type"); + if (dtype.size() < 3) { + continue; + } + try { + Variable v(dtype, var->at("address"), var->value("mask", UINT64_MAX)); + setVariable(var.key(), v); + } catch (std::out_of_range) { + continue; + } + } + return true; +} + +bool GameData::save(const string& filename) const { + ofstream file(filename); + return save(&file); +} + +bool GameData::save(ostream* file) const { + json manifest; + json info; + + for (const auto& var : m_vars) { + json jvar; + jvar["address"] = var.second.address; + jvar["type"] = var.second.type.type; + if (var.second.mask != UINT64_MAX) { + jvar["mask"] = var.second.mask; + } + info[var.first] = jvar; + } + + manifest["info"] = info; + try { + file->width(2); + *file << manifest; + *file << endl; + } catch (json::exception&) { + return false; + } + return true; +} + +string GameData::dataPath(const string& hint) { + if (s_dataDirectory.size()) { + return s_dataDirectory; + } + const char* envDir = getenv("RETRO_DATA_PATH"); + if (envDir) { + s_dataDirectory = envDir; + } else { + s_dataDirectory = drillUp({ "retro/data", "data" }, ".", hint); + } + return s_dataDirectory; +} + +void GameData::reset() { + restart(); + m_lastMem.reset(); + m_cloneMem.reset(); + m_vars.clear(); + //m_searches.clear(); + m_searchOldMem.clear(); +} + +void GameData::restart() { + m_customVars.clear(); +} + +void GameData::updateRam() { + m_lastMem = move(m_cloneMem); + m_cloneMem.clone(m_mem); +} + +void GameData::setTypes(const vector types) { + m_types = vector(types); +} + +void GameData::setButtons(const vector& buttons) { + m_buttons = buttons; +} + +vector GameData::buttons() const { + return m_buttons; +} + +void GameData::setActions(const vector>>& actions) { + ::setActions(m_buttons, actions, m_actions); +} + +map> GameData::validActions() const { + return m_actions; +} + +unsigned GameData::filterAction(unsigned action) const { + return ::filterAction(action, m_actions); +} + +Datum GameData::lookupValue(const string& name) { + auto variant = m_customVars.find(name); + if (variant != m_customVars.end()) { + return Datum(variant->second.get()); + } + auto v = m_vars.find(name); + if (v == m_vars.end()) { + throw invalid_argument(name); + } + return m_mem[v->second]; +} + +Variant GameData::lookupValue(const string& name) const { + auto variant = m_customVars.find(name); + if (variant != m_customVars.end()) { + return *variant->second; + } + auto v = m_vars.find(name); + if (v == m_vars.end()) { + throw invalid_argument(name); + } + return m_mem[v->second]; +} + +/*Datum GameData::lookupValue(const TypedSearchResult& result) { + return m_mem[Variable{ result.type, result.address }]; +} + +int64_t GameData::lookupValue(const TypedSearchResult& result) const { + return m_mem[Variable{ result.type, result.address }]; +}*/ + +int64_t GameData::lookupDelta(const string& name) const { + const auto& v = m_vars.find(name); + if (v == m_vars.end()) { + return 0; + } + int64_t newVal = m_cloneMem[v->second]; + + if (!m_lastMem.ok()) { + return 0; + } + int64_t oldVal = m_lastMem[v->second]; + + return newVal - oldVal; +} + +unordered_map GameData::lookupAll() { + unordered_map data; + for (auto var = m_vars.cbegin(); var != m_vars.cend(); ++var) { + try { + data.emplace(var->first, m_mem[var->second]); + } catch (...) { + } + } + for (auto var = m_customVars.cbegin(); var != m_customVars.cend(); ++var) { + data.emplace(var->first, var->second.get()); + } + return data; +} + +unordered_map GameData::lookupAll() const { + unordered_map data; + for (auto var = m_vars.cbegin(); var != m_vars.cend(); ++var) { + try { + data.emplace(var->first, m_mem[var->second]); + } catch (...) { + } + } + for (auto var = m_customVars.cbegin(); var != m_customVars.cend(); ++var) { + data.emplace(var->first, *var->second); + } + return data; +} + +void GameData::setValue(const std::string& name, int64_t v) { + auto variant = m_customVars.find(name); + if (variant != m_customVars.end()) { + *variant->second = v; + return; + } + auto var = m_vars.find(name); + if (var != m_vars.end()) { + m_mem[var->second] = v; + return; + } + m_customVars.emplace(name, std::make_unique(v)); +} + +void GameData::setValue(const std::string& name, const Variant& v) { + auto variant = m_customVars.find(name); + if (variant != m_customVars.end()) { + *variant->second = v; + return; + } + auto var = m_vars.find(name); + if (var != m_vars.end()) { + m_mem[var->second] = v; + return; + } + m_customVars.emplace(name, std::make_unique(v)); +} + +Variable GameData::getVariable(const string& name) const { + const auto& v = m_vars.find(name); + if (v == m_vars.end()) { + throw invalid_argument(name); + } + return v->second; +} + +void GameData::setVariable(const string& name, const Variable& var) { + removeVariable(name); + m_vars.emplace(name, var); +} + +void GameData::removeVariable(const string& name) { + auto iter = m_vars.find(name); + if (iter != m_vars.end()) { + m_vars.erase(iter); + } +} + +unordered_map GameData::listVariables() const { + return m_vars; +} + +size_t GameData::numVariables() const { + return m_vars.size(); +} + +/*void GameData::search(const std::string& name, int64_t value) { + if (m_searches.find(name) == m_searches.cend()) { + if (m_types.size()) { + m_searches.emplace(name, Search{ m_types }); + } else { + m_searches.emplace(name, Search{}); + } + } + Search* search = &m_searches[name]; + search->search(m_mem, value); + m_searchOldMem[name].clone(m_mem); +}*/ + +/*void GameData::deltaSearch(const std::string& name, Operation op, int64_t reference) { + if (m_searches.find(name) == m_searches.cend()) { + if (m_types.size()) { + m_searches.emplace(name, Search{ m_types }); + } else { + m_searches.emplace(name, Search{}); + } + } + if (m_searchOldMem.find(name) == m_searchOldMem.cend()) { + m_searchOldMem[name].clone(m_mem); + } + Search* search = &m_searches[name]; + search->delta(m_mem, m_searchOldMem[name], op, reference); + m_searchOldMem[name].clone(m_mem); +}* + +size_t GameData::numSearches() const { + return m_searches.size(); +} + +vector GameData::listSearches() const { + vector names; + for (const auto& search : m_searches) { + names.emplace_back(search.first); + } + return names; +} + +Search* GameData::getSearch(const string& name) { + auto iter = m_searches.find(name); + if (iter != m_searches.end()) { + return &iter->second; + } + return nullptr; +} + +void GameData::removeSearch(const string& name) { + auto iter = m_searches.find(name); + if (iter != m_searches.end()) { + m_searches.erase(iter); + } +}*/ + + + +static const vector> s_ops{ + make_pair("equal", Operation::EQUAL), + make_pair("negative-equal", Operation::NEGATIVE_EQUAL), + make_pair("not-equal", Operation::NOT_EQUAL), + make_pair("less-than", Operation::LESS_THAN), + make_pair("greater-than", Operation::GREATER_THAN), + make_pair("less-or-equal", Operation::LESS_OR_EQUAL), + make_pair("greater-or-equal", Operation::GREATER_OR_EQUAL), + make_pair("less-or-equal", Operation::LESS_OR_EQUAL), + make_pair("nonzero", Operation::NONZERO), + make_pair("zero", Operation::ZERO), + make_pair("negative", Operation::NEGATIVE), + make_pair("positive", Operation::POSITIVE), + make_pair("sign", Operation::SIGN) +}; + diff --git a/deps/game_ai_lib/utils/data.h b/deps/game_ai_lib/utils/data.h new file mode 100644 index 0000000000..61f913e25f --- /dev/null +++ b/deps/game_ai_lib/utils/data.h @@ -0,0 +1,94 @@ +// Adapted from OpenAI's retro source code: +// https://github.com/openai/retro + +#pragma once + +//#include "emulator.h" +#include "memory.h" +//#include "search.h" +#include "utils.h" + +#include +#include +#include +#include +#include + +#ifdef ABSOLUTE +#undef ABSOLUTE +#endif + +namespace Retro { + +class GameData { +public: + bool load(const std::string& filename); + bool load(std::istream* stream); + + bool save(const std::string& filename) const; + bool save(std::ostream* stream) const; + + void reset(); + void restart(); + + static std::string dataPath(const std::string& hint = "."); + + AddressSpace& addressSpace() { return m_mem; } + const AddressSpace& addressSpace() const { return m_mem; } + void updateRam(); + + void setTypes(const std::vector types); + void setButtons(const std::vector& names); + std::vector buttons() const; + + void setActions(const std::vector>>& actions); + std::map> validActions() const; + unsigned filterAction(unsigned) const; + + Datum lookupValue(const std::string& name); + Variant lookupValue(const std::string& name) const; + //Datum lookupValue(const TypedSearchResult&); + //int64_t lookupValue(const TypedSearchResult&) const; + std::unordered_map lookupAll(); + std::unordered_map lookupAll() const; + + void setValue(const std::string& name, int64_t); + void setValue(const std::string& name, const Variant&); + + int64_t lookupDelta(const std::string& name) const; + + Variable getVariable(const std::string& name) const; + void setVariable(const std::string& name, const Variable&); + void removeVariable(const std::string& name); + + std::unordered_map listVariables() const; + size_t numVariables() const; + + void search(const std::string& name, int64_t value); + void deltaSearch(const std::string& name, Operation op, int64_t reference); + size_t numSearches() const; + + std::vector listSearches() const; + //Search* getSearch(const std::string& name); + void removeSearch(const std::string& name); + +#ifdef USE_CAPNP + bool loadSearches(const std::string& filename); + bool saveSearches(const std::string& filename) const; +#endif + +private: + AddressSpace m_mem; + AddressSpace m_cloneMem; + AddressSpace m_lastMem; + std::vector m_types; + + std::map> m_actions; + std::vector m_buttons; + + std::unordered_map m_vars; + //std::unordered_map m_searches; + std::unordered_map m_searchOldMem; + std::unordered_map> m_customVars; +}; +} diff --git a/deps/game_ai_lib/utils/json.hpp b/deps/game_ai_lib/utils/json.hpp new file mode 100644 index 0000000000..6b6655af8a --- /dev/null +++ b/deps/game_ai_lib/utils/json.hpp @@ -0,0 +1,17300 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.1.2 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2018 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 1 +#define NLOHMANN_JSON_VERSION_PATCH 2 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +// #include + + +#include // not +#include // size_t +#include // numeric_limits +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // declval + +// #include + +// #include + + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +// source: https://stackoverflow.com/a/37193089/4116453 + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +template +struct is_compatible_complete_type +{ + static constexpr bool value = + not std::is_base_of::value and + not is_basic_json::value and + not is_basic_json_nested_type::value and + has_to_json::value; +}; + +template +struct is_compatible_type + : conjunction, + is_compatible_complete_type> +{ +}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +// #include + + +#include // array +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // pair, declval +#include // valarray + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// overloads for basic_json template parameters +template::value and + not std::is_same::value, + int> = 0> +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_UNLIKELY(not j.is_boolean())) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_UNLIKELY(not j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + arr = *j.template get_ptr(); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.resize(j.size()); + std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +{ + using std::end; + + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + void()) +{ + using std::end; + + arr.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template < + typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < + is_compatible_array_type::value and + not std::is_same::value and + std::is_constructible < + BasicJsonType, typename CompatibleArrayType::value_type >::value, + int > = 0 > +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + + std::string(j.type_name()))); + } + + from_json_array_impl(j, arr, priority_tag<2> {}); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +{ + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); + } + + auto inner_object = j.template get_ptr(); + using value_type = typename CompatibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(obj, obj.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value, + int> = 0> +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ + p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ + t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ + from_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct from_json_fn +{ + private: + template + auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } + + template + void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find from_json() method in T's namespace"); +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) + { + return call(j, val, priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} +} + +// #include + + +#include // or, and, not +#include // begin, end +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_type = value_t::string; + j.m_value = std::move(s); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_type = value_t::array; + j.m_value = std::move(arr); + j.assert_invariant(); + } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_value.array->push_back(x); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->resize(arr.size()); + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_type = value_t::object; + j.m_value = std::move(obj); + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template::value or + std::is_same::value, + int> = 0> +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, std::valarray arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, T (&arr)[N]) +{ + external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = {p.first, p.second}; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +{ + j = {std::get(t)...}; +} + +template +void to_json(BasicJsonType& j, const std::tuple& t) +{ + to_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct to_json_fn +{ + private: + template + auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } + + template + void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find to_json() method in T's namespace"); + +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(BasicJsonType& j, T&& val) const + noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) + { + return call(j, std::forward(val), priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} +} + +// #include + + +#include // min +#include // array +#include // assert +#include // size_t +#include // strlen +#include // streamsize, streamoff, streampos +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of exactly +one non-EOF character for future input. The int_type characters returned +consist of all valid char values as positive values (typically unsigned char), +plus an EOF value outside that range, specified by the value of the function +std::char_traits::eof(). This value is typically -1, but could be any +arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; + /// restore the last non-eof() character to input + virtual void unget_character() = 0; + virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ + public: + ~input_stream_adapter() override + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags + is.clear(); + } + + explicit input_stream_adapter(std::istream& i) + : is(i), sb(*i.rdbuf()) + { + // skip byte order mark + std::char_traits::int_type c; + if ((c = get_character()) == 0xEF) + { + if ((c = get_character()) == 0xBB) + { + if ((c = get_character()) == 0xBF) + { + return; // Ignore BOM + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xBB'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xEF'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); // no byte order mark; process as usual + } + } + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() override + { + return sb.sbumpc(); + } + + void unget_character() override + { + sb.sungetc(); // is.unget() avoided for performance + } + + private: + /// the associated input stream + std::istream& is; + std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ + public: + input_buffer_adapter(const char* b, const std::size_t l) + : cursor(b), limit(b + l), start(b) + { + // skip byte order mark + if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') + { + cursor += 3; + } + } + + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + + std::char_traits::int_type get_character() noexcept override + { + if (JSON_LIKELY(cursor < limit)) + { + return std::char_traits::to_int_type(*(cursor++)); + } + + return std::char_traits::eof(); + } + + void unget_character() noexcept override + { + if (JSON_LIKELY(cursor > start)) + { + --cursor; + } + } + + private: + /// pointer to the current character + const char* cursor; + /// pointer past the last character + const char* limit; + /// pointer to the first character + const char* start; +}; + +class input_adapter +{ + public: + // native support + + /// input adapter for input stream + input_adapter(std::istream& i) + : ia(std::make_shared(i)) {} + + /// input adapter for input stream + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + + /// input adapter for buffer + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} + + // derived support + + /// input adapter for string literal + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b) + : input_adapter(reinterpret_cast(b), + std::strlen(reinterpret_cast(b))) {} + + /// input adapter for iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + input_adapter(IteratorType first, IteratorType last) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + const auto len = static_cast(std::distance(first, last)); + if (JSON_LIKELY(len > 0)) + { + // there is at least one element: use the address of first + ia = std::make_shared(reinterpret_cast(&(*first)), len); + } + else + { + // the address of first cannot be used: use nullptr + ia = std::make_shared(nullptr, len); + } + } + + /// input adapter for array + template + input_adapter(T (&array)[N]) + : input_adapter(std::begin(array), std::end(array)) {} + + /// input adapter for contiguous container + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> + input_adapter(const ContiguousContainer& c) + : input_adapter(std::begin(c), std::end(c)) {} + + operator input_adapter_t() + { + return ia; + } + + private: + /// the actual adapter + input_adapter_t ia = nullptr; +}; +} +} + +// #include + + +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // hex, uppercase +#include // setw, setfill +#include // stringstream +#include // char_traits, string +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + default: // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + + explicit lexer(detail::input_adapter_t adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer& operator=(lexer&) = delete; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + static char get_decimal_point() noexcept + { + const auto loc = localeconv(); + assert(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + assert(current == 'u'); + int codepoint = 0; + + const auto factors = { 12, 8, 4, 0 }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' and current <= '9') + { + codepoint += ((current - 0x30) << factor); + } + else if (current >= 'A' and current <= 'F') + { + codepoint += ((current - 0x37) << factor); + } + else if (current >= 'a' and current <= 'f') + { + codepoint += ((current - 0x57) << factor); + } + else + { + return -1; + } + } + + assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_LIKELY(*range <= current and current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset token_buffer (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + assert(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_LIKELY(get() == '\\' and get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(codepoint); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + error_message = "invalid string: control character must be escaped"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() + { + // reset token_buffer to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + // all other characters are rejected outside scan_number() + assert(false); // LCOV_EXCL_LINE + } + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, token_buffer.data(), &endptr); + + // we checked the number format before + assert(endptr == token_buffer.data() + token_buffer.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + token_type scan_literal(const char* literal_text, const std::size_t length, + token_type return_type) + { + assert(current == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_UNLIKELY(get() != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset token_buffer; current character is beginning of token + void reset() noexcept + { + token_buffer.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + std::char_traits::int_type get() + { + ++chars_read; + current = ia->get_character(); + if (JSON_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + return current; + } + + /// unget current character (return it again on next get) + void unget() + { + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) + { + ia->unget_character(); + assert(token_string.size() != 0); + token_string.pop_back(); + } + } + + /// add a character to token_buffer + void add(int c) + { + token_buffer.push_back(std::char_traits::to_char_type(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + string_t&& move_string() + { + return std::move(token_buffer); + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr std::size_t get_position() const noexcept + { + return chars_read; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if ('\x00' <= c and c <= '\x1F') + { + // escape control characters + std::stringstream ss; + ss << "(c) << ">"; + result += ss.str(); + } + else + { + // add character as is + result.push_back(c); + } + } + + return result; + } + + /// return syntax error message + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + token_type scan() + { + // read next character and ignore whitespace + do + { + get(); + } + while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + return scan_literal("true", 4, token_type::literal_true); + case 'f': + return scan_literal("false", 5, token_type::literal_false); + case 'n': + return scan_literal("null", 4, token_type::literal_null); + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + detail::input_adapter_t ia = nullptr; + + /// the current character + std::char_traits::int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + string_t token_buffer {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char decimal_point_char = '.'; +}; +} +} + +// #include + + +#include // assert +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +/*! +@brief syntax analysis + +This class implements a recursive decent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + using parser_callback_t = + std::function; + + /// a parser reading from an input adapter + explicit parser(detail::input_adapter_t adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true) + : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) + {} + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + // read first token + get_token(); + + parse_internal(true, result); + result.assert_invariant(); + + // in strict mode, input must be completely read + if (strict) + { + get_token(); + expect(token_type::end_of_input); + } + + // in case of an error, return discarded value + if (errored) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + // read first token + get_token(); + + if (not accept_internal()) + { + return false; + } + + // strict => last token must be EOF + return not strict or (get_token() == token_type::end_of_input); + } + + private: + /*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse_internal(bool keep, BasicJsonType& result) + { + // never parse after a parse error was detected + assert(not errored); + + // start with a discarded value + if (not result.is_discarded()) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + + switch (last_token) + { + case token_type::begin_object: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::object_start, result); + } + + if (not callback or keep) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = value_t::object; + } + } + + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + string_t key; + BasicJsonType value; + while (true) + { + // store key + if (not expect(token_type::value_string)) + { + return; + } + key = m_lexer.move_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + BasicJsonType k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + if (not expect(token_type::name_separator)) + { + return; + } + + // parse and add value + get_token(); + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and keep_tag and not value.is_discarded()) + { + result.m_value.object->emplace(std::move(key), std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + if (not expect(token_type::end_object)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::begin_array: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::array_start, result); + } + + if (not callback or keep) + { + // explicitly set result to array to cope with [] + result.m_type = value_t::array; + result.m_value = value_t::array; + } + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + BasicJsonType value; + while (true) + { + // parse value + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and not value.is_discarded()) + { + result.m_value.array->push_back(std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + if (not expect(token_type::end_array)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::literal_null: + { + result.m_type = value_t::null; + break; + } + + case token_type::value_string: + { + result.m_type = value_t::string; + result.m_value = m_lexer.move_string(); + break; + } + + case token_type::literal_true: + { + result.m_type = value_t::boolean; + result.m_value = true; + break; + } + + case token_type::literal_false: + { + result.m_type = value_t::boolean; + result.m_value = false; + break; + } + + case token_type::value_unsigned: + { + result.m_type = value_t::number_unsigned; + result.m_value = m_lexer.get_number_unsigned(); + break; + } + + case token_type::value_integer: + { + result.m_type = value_t::number_integer; + result.m_value = m_lexer.get_number_integer(); + break; + } + + case token_type::value_float: + { + result.m_type = value_t::number_float; + result.m_value = m_lexer.get_number_float(); + + // throw in case of infinity or NAN + if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) + { + if (allow_exceptions) + { + JSON_THROW(out_of_range::create(406, "number overflow parsing '" + + m_lexer.get_token_string() + "'")); + } + expect(token_type::uninitialized); + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + if (not expect(token_type::uninitialized)) + { + return; + } + break; // LCOV_EXCL_LINE + } + + default: + { + // the last token was unexpected; we expected a value + if (not expect(token_type::literal_or_value)) + { + return; + } + break; // LCOV_EXCL_LINE + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + } + + /*! + @brief the actual acceptor + + @invariant 1. The last token is not yet processed. Therefore, the caller + of this function must make sure a token has been read. + 2. When this function returns, the last token is processed. + That is, the last read character was already considered. + + This invariant makes sure that no token needs to be "unput". + */ + bool accept_internal() + { + switch (last_token) + { + case token_type::begin_object: + { + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + return true; + } + + // parse values + while (true) + { + // parse key + if (last_token != token_type::value_string) + { + return false; + } + + // parse separator (:) + get_token(); + if (last_token != token_type::name_separator) + { + return false; + } + + // parse value + get_token(); + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + return (last_token == token_type::end_object); + } + } + + case token_type::begin_array: + { + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + return true; + } + + // parse values + while (true) + { + // parse value + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + return (last_token == token_type::end_array); + } + } + + case token_type::value_float: + { + // reject infinity or NAN + return std::isfinite(m_lexer.get_number_float()); + } + + case token_type::literal_false: + case token_type::literal_null: + case token_type::literal_true: + case token_type::value_integer: + case token_type::value_string: + case token_type::value_unsigned: + return true; + + default: // the last token was unexpected + return false; + } + } + + /// get next token from lexer + token_type get_token() + { + return (last_token = m_lexer.scan()); + } + + /*! + @throw parse_error.101 if expected token did not occur + */ + bool expect(token_type t) + { + if (JSON_UNLIKELY(t != last_token)) + { + errored = true; + expected = t; + if (allow_exceptions) + { + throw_exception(); + } + else + { + return false; + } + } + + return true; + } + + [[noreturn]] void throw_exception() const + { + std::string error_msg = "syntax error - "; + if (last_token == token_type::parse_error) + { + error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + + m_lexer.get_token_string() + "'"; + } + else + { + error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); + } + + JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether a syntax error occurred + bool errored = false; + /// possible reason for the syntax error + token_type expected = token_type::uninitialized; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; +} +} + +// #include + + +#include // ptrdiff_t +#include // numeric_limits + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + private: + using difference_type = std::ptrdiff_t; + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); + + public: + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type n) noexcept + { + auto result = *this; + result += n; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + primitive_iterator_t& operator++() noexcept + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) noexcept + { + auto result = *this; + m_it++; + return result; + } + + primitive_iterator_t& operator--() noexcept + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) noexcept + { + auto result = *this; + m_it--; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) noexcept + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) noexcept + { + m_it -= n; + return *this; + } +}; +} +} + +// #include + + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} +} + +// #include + + +#include // not +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class + +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. + +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). + +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ + /// allow basic_json to access private members + friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + friend BasicJsonType; + friend iteration_proxy; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + + public: + + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + /// default constructor + iter_impl() = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) {} + + /*! + @brief converting assignment + @param[in,out] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + private: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator==(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator!=(const iter_impl& other) const + { + return not operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return not other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return not operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return not operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + typename object_t::key_type key() const + { + assert(m_object != nullptr); + + if (JSON_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it; +}; +} +} + +// #include + + +#include // size_t +#include // string, to_string + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// proxy class for the items() function +template class iteration_proxy +{ + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_internal& o) const noexcept + { + return anchor != o.anchor; + } + + /// return key of the iterator + std::string key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + return std::to_string(array_index); + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + default: + return ""; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) noexcept + : container(cont) {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept + { + return iteration_proxy_internal(container.end()); + } +}; +} +} + +// #include + + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator const operator++(int) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator const operator--(int) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; +} +} + +// #include + + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) : v(vec) {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} + + void write_character(CharType c) override + { + stream.put(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template> +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(StringType& s) : str(s) {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + StringType& str; +}; + +template> +class output_adapter +{ + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(StringType& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} +} + +// #include + + +#include // generate_n +#include // array +#include // assert +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // setw, setfill +#include // hex +#include // back_inserter +#include // numeric_limits +#include // stringstream +#include // char_traits, string +#include // make_pair, move + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR and MessagePack values +*/ +template +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using string_t = typename BasicJsonType::string_t; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) + { + assert(ia); + } + + /*! + @brief create a JSON value from CBOR input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_cbor(const bool strict) + { + const auto res = parse_cbor_internal(); + if (strict) + { + get(); + expect_eof(); + } + return res; + } + + /*! + @brief create a JSON value from MessagePack input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_msgpack(const bool strict) + { + const auto res = parse_msgpack_internal(); + if (strict) + { + get(); + expect_eof(); + } + return res; + } + + /*! + @brief create a JSON value from UBJSON input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from UBJSON input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_ubjson(const bool strict) + { + const auto res = parse_ubjson_internal(); + if (strict) + { + get_ignore_noop(); + expect_eof(); + } + return res; + } + + /*! + @brief determine system byte order + + @return true if and only if system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ + static constexpr bool little_endianess(int num = 1) noexcept + { + return (*reinterpret_cast(&num) == 1); + } + + private: + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ + BasicJsonType parse_cbor_internal(const bool get_char = true) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return static_cast(current); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + return get_number(); + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + return get_number(); + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + return get_number(); + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + return get_number(); + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return static_cast(0x20 - 1 - current); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + return static_cast(-1) - + static_cast(get_number()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + return get_cbor_string(); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + { + return get_cbor_array(current & 0x1F); + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + return get_cbor_array(get_number()); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9F: // array (indefinite length) + { + BasicJsonType result = value_t::array; + while (get() != 0xFF) + { + result.push_back(parse_cbor_internal(false)); + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + { + return get_cbor_object(current & 0x1F); + } + + case 0xB8: // map (one-byte uint8_t for n follows) + { + return get_cbor_object(get_number()); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBF: // map (indefinite length) + { + BasicJsonType result = value_t::object; + while (get() != 0xFF) + { + auto key = get_cbor_string(); + result[key] = parse_cbor_internal(); + } + return result; + } + + case 0xF4: // false + { + return false; + } + + case 0xF5: // true + { + return true; + } + + case 0xF6: // null + { + return value_t::null; + } + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const int byte1 = get(); + unexpect_eof(); + const int byte2 = get(); + unexpect_eof(); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const int half = (byte1 << 8) + byte2; + const int exp = (half >> 10) & 0x1F; + const int mant = half & 0x3FF; + double val; + if (exp == 0) + { + val = std::ldexp(mant, -24); + } + else if (exp != 31) + { + val = std::ldexp(mant + 1024, exp - 25); + } + else + { + val = (mant == 0) ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + } + return (half & 0x8000) != 0 ? -val : val; + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + return get_number(); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + return get_number(); + } + + default: // anything else (0xFF is handled inside the other types) + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); + } + } + } + + BasicJsonType parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return static_cast(current); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + { + return get_msgpack_object(current & 0x0F); + } + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + { + return get_msgpack_array(current & 0x0F); + } + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + return get_msgpack_string(); + + case 0xC0: // nil + return value_t::null; + + case 0xC2: // false + return false; + + case 0xC3: // true + return true; + + case 0xCA: // float 32 + return get_number(); + + case 0xCB: // float 64 + return get_number(); + + case 0xCC: // uint 8 + return get_number(); + + case 0xCD: // uint 16 + return get_number(); + + case 0xCE: // uint 32 + return get_number(); + + case 0xCF: // uint 64 + return get_number(); + + case 0xD0: // int 8 + return get_number(); + + case 0xD1: // int 16 + return get_number(); + + case 0xD2: // int 32 + return get_number(); + + case 0xD3: // int 64 + return get_number(); + + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + return get_msgpack_string(); + + case 0xDC: // array 16 + { + return get_msgpack_array(get_number()); + } + + case 0xDD: // array 32 + { + return get_msgpack_array(get_number()); + } + + case 0xDE: // map 16 + { + return get_msgpack_object(get_number()); + } + + case 0xDF: // map 32 + { + return get_msgpack_object(get_number()); + } + + // positive fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return static_cast(current); + + default: // anything else + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "error reading MessagePack; last byte: 0x" + ss.str())); + } + } + } + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ + BasicJsonType parse_ubjson_internal(const bool get_char = true) + { + return get_ubjson_value(get_char ? get_ignore_noop() : current); + } + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + int get() + { + ++chars_read; + return (current = ia->get_character()); + } + + /*! + @return character read from the input after ignoring all 'N' entries + */ + int get_ignore_noop() + { + do + { + get(); + } + while (current == 'N'); + + return current; + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + + @return number of type @a NumberType + + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + + @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes + */ + template NumberType get_number() + { + // step 1: read input into array with system's byte order + std::array vec; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + unexpect_eof(); + + // reverse byte order prior to conversion if necessary + if (is_little_endian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + NumberType result; + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return result; + } + + /*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ + template + string_t get_string(const NumberType len) + { + string_t result; + std::generate_n(std::back_inserter(result), len, [this]() + { + get(); + unexpect_eof(); + return static_cast(current); + }); + return result; + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + string_t get_cbor_string() + { + unexpect_eof(); + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(current & 0x1F); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + return get_string(get_number()); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + return get_string(get_number()); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + return get_string(get_number()); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + return get_string(get_number()); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + string_t result; + while (get() != 0xFF) + { + result.append(get_cbor_string()); + } + return result; + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_cbor_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_cbor_internal(); + }); + return result; + } + + template + BasicJsonType get_cbor_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_cbor_string(); + auto val = parse_cbor_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + string_t get_msgpack_string() + { + unexpect_eof(); + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(current & 0x1F); + } + + case 0xD9: // str 8 + { + return get_string(get_number()); + } + + case 0xDA: // str 16 + { + return get_string(get_number()); + } + + case 0xDB: // str 32 + { + return get_string(get_number()); + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "expected a MessagePack string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_msgpack_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_msgpack_internal(); + }); + return result; + } + + template + BasicJsonType get_msgpack_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_msgpack_string(); + auto val = parse_msgpack_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + string_t get_ubjson_string(const bool get_char = true) + { + if (get_char) + { + get(); // TODO: may we ignore N here? + } + + unexpect_eof(); + + switch (current) + { + case 'U': + return get_string(get_number()); + case 'i': + return get_string(get_number()); + case 'I': + return get_string(get_number()); + case 'l': + return get_string(get_number()); + case 'L': + return get_string(get_number()); + default: + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "expected a UBJSON string; last byte: 0x" + ss.str())); + } + } + + /*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @return pair of the size and the type + */ + std::pair get_ubjson_size_type() + { + std::size_t sz = string_t::npos; + int tc = 0; + + get_ignore_noop(); + + if (current == '$') + { + tc = get(); // must not ignore 'N', because 'N' maybe the type + unexpect_eof(); + + get_ignore_noop(); + if (current != '#') + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "expected '#' after UBJSON type information; last byte: 0x" + ss.str())); + } + sz = parse_ubjson_internal(); + } + else if (current == '#') + { + sz = parse_ubjson_internal(); + } + + return std::make_pair(sz, tc); + } + + BasicJsonType get_ubjson_value(const int prefix) + { + switch (prefix) + { + case std::char_traits::eof(): // EOF + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + case 'T': // true + return true; + case 'F': // false + return false; + + case 'Z': // null + return nullptr; + + case 'U': + return get_number(); + case 'i': + return get_number(); + case 'I': + return get_number(); + case 'l': + return get_number(); + case 'L': + return get_number(); + case 'd': + return get_number(); + case 'D': + return get_number(); + + case 'C': // char + { + get(); + unexpect_eof(); + if (JSON_UNLIKELY(current > 127)) + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + ss.str())); + } + return string_t(1, static_cast(current)); + } + + case 'S': // string + return get_ubjson_string(); + + case '[': // array + return get_ubjson_array(); + + case '{': // object + return get_ubjson_object(); + + default: // anything else + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "error reading UBJSON; last byte: 0x" + ss.str())); + } + } + + BasicJsonType get_ubjson_array() + { + BasicJsonType result = value_t::array; + const auto size_and_type = get_ubjson_size_type(); + + if (size_and_type.first != string_t::npos) + { + if (JSON_UNLIKELY(size_and_type.first > result.max_size())) + { + JSON_THROW(out_of_range::create(408, + "excessive array size: " + std::to_string(size_and_type.first))); + } + + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + std::generate_n(std::back_inserter(*result.m_value.array), + size_and_type.first, [this, size_and_type]() + { + return get_ubjson_value(size_and_type.second); + }); + } + } + else + { + std::generate_n(std::back_inserter(*result.m_value.array), + size_and_type.first, [this]() + { + return parse_ubjson_internal(); + }); + } + } + else + { + while (current != ']') + { + result.push_back(parse_ubjson_internal(false)); + get_ignore_noop(); + } + } + + return result; + } + + BasicJsonType get_ubjson_object() + { + BasicJsonType result = value_t::object; + const auto size_and_type = get_ubjson_size_type(); + + if (size_and_type.first != string_t::npos) + { + if (JSON_UNLIKELY(size_and_type.first > result.max_size())) + { + JSON_THROW(out_of_range::create(408, + "excessive object size: " + std::to_string(size_and_type.first))); + } + + if (size_and_type.second != 0) + { + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + size_and_type.first, [this, size_and_type]() + { + auto key = get_ubjson_string(); + auto val = get_ubjson_value(size_and_type.second); + return std::make_pair(std::move(key), std::move(val)); + }); + } + else + { + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + size_and_type.first, [this]() + { + auto key = get_ubjson_string(); + auto val = parse_ubjson_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + } + } + else + { + while (current != '}') + { + auto key = get_ubjson_string(false); + result[std::move(key)] = parse_ubjson_internal(); + get_ignore_noop(); + } + } + + return result; + } + + /*! + @brief throw if end of input is not reached + @throw parse_error.110 if input not ended + */ + void expect_eof() const + { + if (JSON_UNLIKELY(current != std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); + } + } + + /*! + @briefthrow if end of input is reached + @throw parse_error.110 if input ended + */ + void unexpect_eof() const + { + if (JSON_UNLIKELY(current == std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } + } + + private: + /// input adapter + input_adapter_t ia = nullptr; + + /// the current character + int current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); +}; +} +} + +// #include + + +#include // reverse +#include // array +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ + public: + /*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) : oa(adapter) + { + assert(oa); + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_cbor(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(static_cast(0xF6)); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_value.boolean + ? static_cast(0xF5) + : static_cast(0xF4)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_integer)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x38)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x39)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x3A)); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(static_cast(0x3B)); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_unsigned)); + } + break; + } + + case value_t::number_float: // Double-Precision Float + { + oa->write_character(static_cast(0xFB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 0x17) + { + write_number(static_cast(0x60 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x78)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x79)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x7A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x7B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 0x17) + { + write_number(static_cast(0x80 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x98)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x99)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x9A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x9B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_cbor(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 0x17) + { + write_number(static_cast(0xA0 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0xB8)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0xB9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0xBA)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0xBB)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_cbor(el.first); + write_cbor(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_msgpack(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: // nil + { + oa->write_character(static_cast(0xC0)); + break; + } + + case value_t::boolean: // true and false + { + oa->write_character(j.m_value.boolean + ? static_cast(0xC3) + : static_cast(0xC2)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we used + // the code from the value_t::number_unsigned case here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(static_cast(0xD0)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(static_cast(0xD1)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(static_cast(0xD2)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(static_cast(0xD3)); + write_number(static_cast(j.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + break; + } + + case value_t::number_float: // float 64 + { + oa->write_character(static_cast(0xCB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xA0 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 8 + oa->write_character(static_cast(0xD9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 16 + oa->write_character(static_cast(0xDA)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 32 + oa->write_character(static_cast(0xDB)); + write_number(static_cast(N)); + } + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 16 + oa->write_character(static_cast(0xDC)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 32 + oa->write_character(static_cast(0xDD)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_msgpack(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xF))); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 16 + oa->write_character(static_cast(0xDE)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 32 + oa->write_character(static_cast(0xDF)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + @param[in] use_count whether to use '#' prefixes (optimized format) + @param[in] use_type whether to use '$' prefixes (optimized format) + @param[in] add_prefix whether prefixes need to be used for this value + */ + void write_ubjson(const BasicJsonType& j, const bool use_count, + const bool use_type, const bool add_prefix = true) + { + switch (j.type()) + { + case value_t::null: + { + if (add_prefix) + { + oa->write_character(static_cast('Z')); + } + break; + } + + case value_t::boolean: + { + if (add_prefix) + oa->write_character(j.m_value.boolean + ? static_cast('T') + : static_cast('F')); + break; + } + + case value_t::number_integer: + { + write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); + break; + } + + case value_t::number_unsigned: + { + write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); + break; + } + + case value_t::number_float: + { + write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); + break; + } + + case value_t::string: + { + if (add_prefix) + { + oa->write_character(static_cast('S')); + } + write_number_with_ubjson_prefix(j.m_value.string->size(), true); + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + if (add_prefix) + { + oa->write_character(static_cast('[')); + } + + bool prefix_required = true; + if (use_type and not j.m_value.array->empty()) + { + assert(use_count); + const char first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin() + 1, j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(static_cast('$')); + oa->write_character(static_cast(first_prefix)); + } + } + + if (use_count) + { + oa->write_character(static_cast('#')); + write_number_with_ubjson_prefix(j.m_value.array->size(), true); + } + + for (const auto& el : *j.m_value.array) + { + write_ubjson(el, use_count, use_type, prefix_required); + } + + if (not use_count) + { + oa->write_character(static_cast(']')); + } + + break; + } + + case value_t::object: + { + if (add_prefix) + { + oa->write_character(static_cast('{')); + } + + bool prefix_required = true; + if (use_type and not j.m_value.object->empty()) + { + assert(use_count); + const char first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin(), j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(static_cast('$')); + oa->write_character(static_cast(first_prefix)); + } + } + + if (use_count) + { + oa->write_character(static_cast('#')); + write_number_with_ubjson_prefix(j.m_value.object->size(), true); + } + + for (const auto& el : *j.m_value.object) + { + write_number_with_ubjson_prefix(el.first.size(), true); + oa->write_characters( + reinterpret_cast(el.first.c_str()), + el.first.size()); + write_ubjson(el.second, use_count, use_type, prefix_required); + } + + if (not use_count) + { + oa->write_character(static_cast('}')); + } + + break; + } + + default: + break; + } + } + + private: + /* + @brief write a number to output input + + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + + @note This function needs to respect the system's endianess, because bytes + in CBOR, MessagePack, and UBJSON are stored in network order (big + endian) and therefore need reordering on little endian systems. + */ + template + void write_number(const NumberType n) + { + // step 1: write number to array of length NumberType + std::array vec; + std::memcpy(vec.data(), &n, sizeof(NumberType)); + + // step 2: write array to output (with possible reordering) + if (is_little_endian) + { + // reverse byte order prior to conversion if necessary + std::reverse(vec.begin(), vec.end()); + } + + oa->write_characters(vec.data(), sizeof(NumberType)); + } + + // UBJSON: write number (floating point) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (add_prefix) + { + oa->write_character(static_cast('D')); // float64 + } + write_number(n); + } + + // UBJSON: write number (unsigned integer) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('i')); // int8 + } + write_number(static_cast(n)); + } + else if (n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('U')); // uint8 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('I')); // int16 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('l')); // int32 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('L')); // int64 + } + write_number(static_cast(n)); + } + else + { + JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + } + } + + // UBJSON: write number (signed integer) + template::value and + not std::is_floating_point::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('i')); // int8 + } + write_number(static_cast(n)); + } + else if (static_cast((std::numeric_limits::min)()) <= n and n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('U')); // uint8 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('I')); // int16 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('l')); // int32 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('L')); // int64 + } + write_number(static_cast(n)); + } + // LCOV_EXCL_START + else + { + JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + } + // LCOV_EXCL_STOP + } + + /*! + @brief determine the type prefix of container values + + @note This function does not need to be 100% accurate when it comes to + integer limits. In case a number exceeds the limits of int64_t, + this will be detected by a later call to function + write_number_with_ubjson_prefix. Therefore, we return 'L' for any + value that does not fit the previous limits. + */ + char ubjson_prefix(const BasicJsonType& j) const noexcept + { + switch (j.type()) + { + case value_t::null: + return 'Z'; + + case value_t::boolean: + return j.m_value.boolean ? 'T' : 'F'; + + case value_t::number_integer: + { + if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'i'; + } + else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'U'; + } + else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'I'; + } + else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'l'; + } + else // no check and assume int64_t (see note above) + { + return 'L'; + } + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + return 'i'; + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + return 'U'; + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + return 'I'; + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + return 'l'; + } + else // no check and assume int64_t (see note above) + { + return 'L'; + } + } + + case value_t::number_float: + return 'D'; + + case value_t::string: + return 'S'; + + case value_t::array: + return '['; + + case value_t::object: + return '{'; + + default: // discarded values + return 'N'; + } + } + + private: + /// whether we can assume little endianess + const bool is_little_endian = binary_reader::little_endianess(); + + /// the output + output_adapter_t oa = nullptr; +}; +} +} + +// #include + + +#include // reverse, remove, fill, find, none_of +#include // array +#include // assert +#include // and, or +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // setfill +#include // next +#include // numeric_limits +#include // string +#include // stringstream +#include // is_same + +// #include + +// #include + + +#include // assert +#include // or, and, not +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ + static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + + Target target; + std::memcpy(&target, &source, sizeof(Source)); + return target; +} + +struct diyfp // f * 2^e +{ + static constexpr int kPrecision = 64; // = q + + uint64_t f; + int e; + + constexpr diyfp() noexcept : f(0), e(0) {} + constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + + /*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ + static diyfp sub(const diyfp& x, const diyfp& y) noexcept + { + assert(x.e == y.e); + assert(x.f >= y.f); + + return diyfp(x.f - y.f, x.e); + } + + /*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ + static diyfp mul(const diyfp& x, const diyfp& y) noexcept + { + static_assert(kPrecision == 64, "internal error"); + + // Computes: + // f = round((x.f * y.f) / 2^q) + // e = x.e + y.e + q + + // Emulate the 64-bit * 64-bit multiplication: + // + // p = u * v + // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) + // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) + // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) + // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) + // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) + // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) + // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) + // + // (Since Q might be larger than 2^32 - 1) + // + // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) + // + // (Q_hi + H does not overflow a 64-bit int) + // + // = p_lo + 2^64 p_hi + + const uint64_t u_lo = x.f & 0xFFFFFFFF; + const uint64_t u_hi = x.f >> 32; + const uint64_t v_lo = y.f & 0xFFFFFFFF; + const uint64_t v_hi = y.f >> 32; + + const uint64_t p0 = u_lo * v_lo; + const uint64_t p1 = u_lo * v_hi; + const uint64_t p2 = u_hi * v_lo; + const uint64_t p3 = u_hi * v_hi; + + const uint64_t p0_hi = p0 >> 32; + const uint64_t p1_lo = p1 & 0xFFFFFFFF; + const uint64_t p1_hi = p1 >> 32; + const uint64_t p2_lo = p2 & 0xFFFFFFFF; + const uint64_t p2_hi = p2 >> 32; + + uint64_t Q = p0_hi + p1_lo + p2_lo; + + // The full product might now be computed as + // + // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) + // p_lo = p0_lo + (Q << 32) + // + // But in this particular case here, the full p_lo is not required. + // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Q_hi + 1 does not overflow). + + Q += uint64_t{1} << (64 - 32 - 1); // round, ties up + + const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32); + + return diyfp(h, x.e + y.e + 64); + } + + /*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ + static diyfp normalize(diyfp x) noexcept + { + assert(x.f != 0); + + while ((x.f >> 63) == 0) + { + x.f <<= 1; + x.e--; + } + + return x; + } + + /*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ + static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept + { + const int delta = x.e - target_exponent; + + assert(delta >= 0); + assert(((x.f << delta) >> delta) == x.f); + + return diyfp(x.f << delta, target_exponent); + } +}; + +struct boundaries +{ + diyfp w; + diyfp minus; + diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ + assert(std::isfinite(value)); + assert(value > 0); + + // Convert the IEEE representation into a diyfp. + // + // If v is denormal: + // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) + // If v is normalized: + // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + + static_assert(std::numeric_limits::is_iec559, + "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + + constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) + constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); + constexpr int kMinExp = 1 - kBias; + constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + + using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type; + + const uint64_t bits = reinterpret_bits(value); + const uint64_t E = bits >> (kPrecision - 1); + const uint64_t F = bits & (kHiddenBit - 1); + + const bool is_denormal = (E == 0); + const diyfp v = is_denormal + ? diyfp(F, kMinExp) + : diyfp(F + kHiddenBit, static_cast(E) - kBias); + + // Compute the boundaries m- and m+ of the floating-point value + // v = f * 2^e. + // + // Determine v- and v+, the floating-point predecessor and successor if v, + // respectively. + // + // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) + // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) + // + // v+ = v + 2^e + // + // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ + // between m- and m+ round to v, regardless of how the input rounding + // algorithm breaks ties. + // + // ---+-------------+-------------+-------------+-------------+--- (A) + // v- m- v m+ v+ + // + // -----------------+------+------+-------------+-------------+--- (B) + // v- m- v m+ v+ + + const bool lower_boundary_is_closer = (F == 0 and E > 1); + const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_minus = lower_boundary_is_closer + ? diyfp(4 * v.f - 1, v.e - 2) // (B) + : diyfp(2 * v.f - 1, v.e - 1); // (A) + + // Determine the normalized w+ = m+. + const diyfp w_plus = diyfp::normalize(m_plus); + + // Determine w- = m- such that e_(w-) = e_(w+). + const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + + return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ + uint64_t f; + int e; + int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ + // Now + // + // alpha <= e_c + e + q <= gamma (1) + // ==> f_c * 2^alpha <= c * 2^e * 2^q + // + // and since the c's are normalized, 2^(q-1) <= f_c, + // + // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) + // ==> 2^(alpha - e - 1) <= c + // + // If c were an exakt power of ten, i.e. c = 10^k, one may determine k as + // + // k = ceil( log_10( 2^(alpha - e - 1) ) ) + // = ceil( (alpha - e - 1) * log_10(2) ) + // + // From the paper: + // "In theory the result of the procedure could be wrong since c is rounded, + // and the computation itself is approximated [...]. In practice, however, + // this simple function is sufficient." + // + // For IEEE double precision floating-point numbers converted into + // normalized diyfp's w = f * 2^e, with q = 64, + // + // e >= -1022 (min IEEE exponent) + // -52 (p - 1) + // -52 (p - 1, possibly normalize denormal IEEE numbers) + // -11 (normalize the diyfp) + // = -1137 + // + // and + // + // e <= +1023 (max IEEE exponent) + // -52 (p - 1) + // -11 (normalize the diyfp) + // = 960 + // + // This binary exponent range [-1137,960] results in a decimal exponent + // range [-307,324]. One does not need to store a cached power for each + // k in this range. For each such k it suffices to find a cached power + // such that the exponent of the product lies in [alpha,gamma]. + // This implies that the difference of the decimal exponents of adjacent + // table entries must be less than or equal to + // + // floor( (gamma - alpha) * log_10(2) ) = 8. + // + // (A smaller distance gamma-alpha would require a larger table.) + + // NB: + // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + + constexpr int kCachedPowersSize = 79; + constexpr int kCachedPowersMinDecExp = -300; + constexpr int kCachedPowersDecStep = 8; + + static constexpr cached_power kCachedPowers[] = + { + { 0xAB70FE17C79AC6CA, -1060, -300 }, + { 0xFF77B1FCBEBCDC4F, -1034, -292 }, + { 0xBE5691EF416BD60C, -1007, -284 }, + { 0x8DD01FAD907FFC3C, -980, -276 }, + { 0xD3515C2831559A83, -954, -268 }, + { 0x9D71AC8FADA6C9B5, -927, -260 }, + { 0xEA9C227723EE8BCB, -901, -252 }, + { 0xAECC49914078536D, -874, -244 }, + { 0x823C12795DB6CE57, -847, -236 }, + { 0xC21094364DFB5637, -821, -228 }, + { 0x9096EA6F3848984F, -794, -220 }, + { 0xD77485CB25823AC7, -768, -212 }, + { 0xA086CFCD97BF97F4, -741, -204 }, + { 0xEF340A98172AACE5, -715, -196 }, + { 0xB23867FB2A35B28E, -688, -188 }, + { 0x84C8D4DFD2C63F3B, -661, -180 }, + { 0xC5DD44271AD3CDBA, -635, -172 }, + { 0x936B9FCEBB25C996, -608, -164 }, + { 0xDBAC6C247D62A584, -582, -156 }, + { 0xA3AB66580D5FDAF6, -555, -148 }, + { 0xF3E2F893DEC3F126, -529, -140 }, + { 0xB5B5ADA8AAFF80B8, -502, -132 }, + { 0x87625F056C7C4A8B, -475, -124 }, + { 0xC9BCFF6034C13053, -449, -116 }, + { 0x964E858C91BA2655, -422, -108 }, + { 0xDFF9772470297EBD, -396, -100 }, + { 0xA6DFBD9FB8E5B88F, -369, -92 }, + { 0xF8A95FCF88747D94, -343, -84 }, + { 0xB94470938FA89BCF, -316, -76 }, + { 0x8A08F0F8BF0F156B, -289, -68 }, + { 0xCDB02555653131B6, -263, -60 }, + { 0x993FE2C6D07B7FAC, -236, -52 }, + { 0xE45C10C42A2B3B06, -210, -44 }, + { 0xAA242499697392D3, -183, -36 }, + { 0xFD87B5F28300CA0E, -157, -28 }, + { 0xBCE5086492111AEB, -130, -20 }, + { 0x8CBCCC096F5088CC, -103, -12 }, + { 0xD1B71758E219652C, -77, -4 }, + { 0x9C40000000000000, -50, 4 }, + { 0xE8D4A51000000000, -24, 12 }, + { 0xAD78EBC5AC620000, 3, 20 }, + { 0x813F3978F8940984, 30, 28 }, + { 0xC097CE7BC90715B3, 56, 36 }, + { 0x8F7E32CE7BEA5C70, 83, 44 }, + { 0xD5D238A4ABE98068, 109, 52 }, + { 0x9F4F2726179A2245, 136, 60 }, + { 0xED63A231D4C4FB27, 162, 68 }, + { 0xB0DE65388CC8ADA8, 189, 76 }, + { 0x83C7088E1AAB65DB, 216, 84 }, + { 0xC45D1DF942711D9A, 242, 92 }, + { 0x924D692CA61BE758, 269, 100 }, + { 0xDA01EE641A708DEA, 295, 108 }, + { 0xA26DA3999AEF774A, 322, 116 }, + { 0xF209787BB47D6B85, 348, 124 }, + { 0xB454E4A179DD1877, 375, 132 }, + { 0x865B86925B9BC5C2, 402, 140 }, + { 0xC83553C5C8965D3D, 428, 148 }, + { 0x952AB45CFA97A0B3, 455, 156 }, + { 0xDE469FBD99A05FE3, 481, 164 }, + { 0xA59BC234DB398C25, 508, 172 }, + { 0xF6C69A72A3989F5C, 534, 180 }, + { 0xB7DCBF5354E9BECE, 561, 188 }, + { 0x88FCF317F22241E2, 588, 196 }, + { 0xCC20CE9BD35C78A5, 614, 204 }, + { 0x98165AF37B2153DF, 641, 212 }, + { 0xE2A0B5DC971F303A, 667, 220 }, + { 0xA8D9D1535CE3B396, 694, 228 }, + { 0xFB9B7CD9A4A7443C, 720, 236 }, + { 0xBB764C4CA7A44410, 747, 244 }, + { 0x8BAB8EEFB6409C1A, 774, 252 }, + { 0xD01FEF10A657842C, 800, 260 }, + { 0x9B10A4E5E9913129, 827, 268 }, + { 0xE7109BFBA19C0C9D, 853, 276 }, + { 0xAC2820D9623BF429, 880, 284 }, + { 0x80444B5E7AA7CF85, 907, 292 }, + { 0xBF21E44003ACDD2D, 933, 300 }, + { 0x8E679C2F5E44FF8F, 960, 308 }, + { 0xD433179D9C8CB841, 986, 316 }, + { 0x9E19DB92B4E31BA9, 1013, 324 }, + }; + + // This computation gives exactly the same results for k as + // k = ceil((kAlpha - e - 1) * 0.30102999566398114) + // for |e| <= 1500, but doesn't require floating-point operations. + // NB: log_10(2) ~= 78913 / 2^18 + assert(e >= -1500); + assert(e <= 1500); + const int f = kAlpha - e - 1; + const int k = (f * 78913) / (1 << 18) + (f > 0); + + const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; + assert(index >= 0); + assert(index < kCachedPowersSize); + static_cast(kCachedPowersSize); // Fix warning. + + const cached_power cached = kCachedPowers[index]; + assert(kAlpha <= cached.e + e + 64); + assert(kGamma >= cached.e + e + 64); + + return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const uint32_t n, uint32_t& pow10) +{ + // LCOV_EXCL_START + if (n >= 1000000000) + { + pow10 = 1000000000; + return 10; + } + // LCOV_EXCL_STOP + else if (n >= 100000000) + { + pow10 = 100000000; + return 9; + } + else if (n >= 10000000) + { + pow10 = 10000000; + return 8; + } + else if (n >= 1000000) + { + pow10 = 1000000; + return 7; + } + else if (n >= 100000) + { + pow10 = 100000; + return 6; + } + else if (n >= 10000) + { + pow10 = 10000; + return 5; + } + else if (n >= 1000) + { + pow10 = 1000; + return 4; + } + else if (n >= 100) + { + pow10 = 100; + return 3; + } + else if (n >= 10) + { + pow10 = 10; + return 2; + } + else + { + pow10 = 1; + return 1; + } +} + +inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, + uint64_t rest, uint64_t ten_k) +{ + assert(len >= 1); + assert(dist <= delta); + assert(rest <= delta); + assert(ten_k > 0); + + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // ten_k + // <------> + // <---- rest ----> + // --------------[------------------+----+--------------]-------------- + // w V + // = buf * 10^k + // + // ten_k represents a unit-in-the-last-place in the decimal representation + // stored in buf. + // Decrement buf by ten_k while this takes buf closer to w. + + // The tests are written in this order to avoid overflow in unsigned + // integer arithmetic. + + while (rest < dist + and delta - rest >= ten_k + and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) + { + assert(buf[len - 1] != '0'); + buf[len - 1]--; + rest += ten_k; + } +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, + diyfp M_minus, diyfp w, diyfp M_plus) +{ + static_assert(kAlpha >= -60, "internal error"); + static_assert(kGamma <= -32, "internal error"); + + // Generates the digits (and the exponent) of a decimal floating-point + // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's + // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. + // + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // Grisu2 generates the digits of M+ from left to right and stops as soon as + // V is in [M-,M+]. + + assert(M_plus.e >= kAlpha); + assert(M_plus.e <= kGamma); + + uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) + uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + + // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): + // + // M+ = f * 2^e + // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e + // = ((p1 ) * 2^-e + (p2 )) * 2^e + // = p1 + p2 * 2^e + + const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e); + + uint32_t p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + + // 1) + // + // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + + assert(p1 > 0); + + uint32_t pow10; + const int k = find_largest_pow10(p1, pow10); + + // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) + // + // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) + // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) + // + // M+ = p1 + p2 * 2^e + // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e + // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e + // = d[k-1] * 10^(k-1) + ( rest) * 2^e + // + // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) + // + // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] + // + // but stop as soon as + // + // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + + int n = k; + while (n > 0) + { + // Invariants: + // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) + // pow10 = 10^(n-1) <= p1 < 10^n + // + const uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) + const uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) + // + // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e + // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) + // + assert(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) + // + p1 = r; + n--; + // + // M+ = buffer * 10^n + (p1 + p2 * 2^e) + // pow10 = 10^n + // + + // Now check if enough digits have been generated. + // Compute + // + // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e + // + // Note: + // Since rest and delta share the same exponent e, it suffices to + // compare the significands. + const uint64_t rest = (uint64_t{p1} << -one.e) + p2; + if (rest <= delta) + { + // V = buffer * 10^n, with M- <= V <= M+. + + decimal_exponent += n; + + // We may now just stop. But instead look if the buffer could be + // decremented to bring V closer to w. + // + // pow10 = 10^n is now 1 ulp in the decimal representation V. + // The rounding procedure works with diyfp's with an implicit + // exponent of e. + // + // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e + // + const uint64_t ten_n = uint64_t{pow10} << -one.e; + grisu2_round(buffer, length, dist, delta, rest, ten_n); + + return; + } + + pow10 /= 10; + // + // pow10 = 10^(n-1) <= p1 < 10^n + // Invariants restored. + } + + // 2) + // + // The digits of the integral part have been generated: + // + // M+ = d[k-1]...d[1]d[0] + p2 * 2^e + // = buffer + p2 * 2^e + // + // Now generate the digits of the fractional part p2 * 2^e. + // + // Note: + // No decimal point is generated: the exponent is adjusted instead. + // + // p2 actually represents the fraction + // + // p2 * 2^e + // = p2 / 2^-e + // = d[-1] / 10^1 + d[-2] / 10^2 + ... + // + // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) + // + // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m + // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) + // + // using + // + // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) + // = ( d) * 2^-e + ( r) + // + // or + // 10^m * p2 * 2^e = d + r * 2^e + // + // i.e. + // + // M+ = buffer + p2 * 2^e + // = buffer + 10^-m * (d + r * 2^e) + // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e + // + // and stop as soon as 10^-m * r * 2^e <= delta * 2^e + + assert(p2 > delta); + + int m = 0; + for (;;) + { + // Invariant: + // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e + // = buffer * 10^-m + 10^-m * (p2 ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e + // + assert(p2 <= UINT64_MAX / 10); + p2 *= 10; + const uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e + const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e + // + // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) + // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + assert(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + p2 = r; + m++; + // + // M+ = buffer * 10^-m + 10^-m * p2 * 2^e + // Invariant restored. + + // Check if enough digits have been generated. + // + // 10^-m * p2 * 2^e <= delta * 2^e + // p2 * 2^e <= 10^m * delta * 2^e + // p2 <= 10^m * delta + delta *= 10; + dist *= 10; + if (p2 <= delta) + { + break; + } + } + + // V = buffer * 10^-m, with M- <= V <= M+. + + decimal_exponent -= m; + + // 1 ulp in the decimal representation is now 10^-m. + // Since delta and dist are now scaled by 10^m, we need to do the + // same with ulp in order to keep the units in sync. + // + // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e + // + const uint64_t ten_m = one.f; + grisu2_round(buffer, length, dist, delta, p2, ten_m); + + // By construction this algorithm generates the shortest possible decimal + // number (Loitsch, Theorem 6.2) which rounds back to w. + // For an input number of precision p, at least + // + // N = 1 + ceil(p * log_10(2)) + // + // decimal digits are sufficient to identify all binary floating-point + // numbers (Matula, "In-and-Out conversions"). + // This implies that the algorithm does not produce more than N decimal + // digits. + // + // N = 17 for p = 53 (IEEE double precision) + // N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +inline void grisu2(char* buf, int& len, int& decimal_exponent, + diyfp m_minus, diyfp v, diyfp m_plus) +{ + assert(m_plus.e == m_minus.e); + assert(m_plus.e == v.e); + + // --------(-----------------------+-----------------------)-------- (A) + // m- v m+ + // + // --------------------(-----------+-----------------------)-------- (B) + // m- v m+ + // + // First scale v (and m- and m+) such that the exponent is in the range + // [alpha, gamma]. + + const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + + const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + + // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] + const diyfp w = diyfp::mul(v, c_minus_k); + const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); + const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + + // ----(---+---)---------------(---+---)---------------(---+---)---- + // w- w w+ + // = c*m- = c*v = c*m+ + // + // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and + // w+ are now off by a small amount. + // In fact: + // + // w - v * 10^k < 1 ulp + // + // To account for this inaccuracy, add resp. subtract 1 ulp. + // + // --------+---[---------------(---+---)---------------]---+-------- + // w- M- w M+ w+ + // + // Now any number in [M-, M+] (bounds included) will round to w when input, + // regardless of how the input rounding algorithm breaks ties. + // + // And digit_gen generates the shortest possible such number in [M-, M+]. + // Note that this does not mean that Grisu2 always generates the shortest + // possible number in the interval (m-, m+). + const diyfp M_minus(w_minus.f + 1, w_minus.e); + const diyfp M_plus (w_plus.f - 1, w_plus.e ); + + decimal_exponent = -cached.k; // = -(-k) = k + + grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ + static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, + "internal error: not enough precision"); + + assert(std::isfinite(value)); + assert(value > 0); + + // If the neighbors (and boundaries) of 'value' are always computed for double-precision + // numbers, all float's can be recovered using strtod (and strtof). However, the resulting + // decimal representations are not exactly "short". + // + // The documentation for 'std::to_chars' (http://en.cppreference.com/w/cpp/utility/to_chars) + // says "value is converted to a string as if by std::sprintf in the default ("C") locale" + // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' + // does. + // On the other hand, the documentation for 'std::to_chars' requires that "parsing the + // representation using the corresponding std::from_chars function recovers value exactly". That + // indicates that single precision floating-point numbers should be recovered using + // 'std::strtof'. + // + // NB: If the neighbors are computed for single-precision numbers, there is a single float + // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision + // value is off by 1 ulp. +#if 0 + const boundaries w = compute_boundaries(static_cast(value)); +#else + const boundaries w = compute_boundaries(value); +#endif + + grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +inline char* append_exponent(char* buf, int e) +{ + assert(e > -1000); + assert(e < 1000); + + if (e < 0) + { + e = -e; + *buf++ = '-'; + } + else + { + *buf++ = '+'; + } + + uint32_t k = static_cast(e); + if (k < 10) + { + // Always print at least two digits in the exponent. + // This is for compatibility with printf("%g"). + *buf++ = '0'; + *buf++ = static_cast('0' + k); + } + else if (k < 100) + { + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + else + { + *buf++ = static_cast('0' + k / 100); + k %= 100; + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + + return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +inline char* format_buffer(char* buf, int len, int decimal_exponent, + int min_exp, int max_exp) +{ + assert(min_exp < 0); + assert(max_exp > 0); + + const int k = len; + const int n = len + decimal_exponent; + + // v = buf * 10^(n-k) + // k is the length of the buffer (number of decimal digits) + // n is the position of the decimal point relative to the start of the buffer. + + if (k <= n and n <= max_exp) + { + // digits[000] + // len <= max_exp + 2 + + std::memset(buf + k, '0', static_cast(n - k)); + // Make it look like a floating-point number (#362, #378) + buf[n + 0] = '.'; + buf[n + 1] = '0'; + return buf + (n + 2); + } + + if (0 < n and n <= max_exp) + { + // dig.its + // len <= max_digits10 + 1 + + assert(k > n); + + std::memmove(buf + (n + 1), buf + n, static_cast(k - n)); + buf[n] = '.'; + return buf + (k + 1); + } + + if (min_exp < n and n <= 0) + { + // 0.[000]digits + // len <= 2 + (-min_exp - 1) + max_digits10 + + std::memmove(buf + (2 + -n), buf, static_cast(k)); + buf[0] = '0'; + buf[1] = '.'; + std::memset(buf + 2, '0', static_cast(-n)); + return buf + (2 + (-n) + k); + } + + if (k == 1) + { + // dE+123 + // len <= 1 + 5 + + buf += 1; + } + else + { + // d.igitsE+123 + // len <= max_digits10 + 1 + 5 + + std::memmove(buf + 2, buf + 1, static_cast(k - 1)); + buf[1] = '.'; + buf += 1 + k; + } + + *buf++ = 'e'; + return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +char* to_chars(char* first, char* last, FloatType value) +{ + static_cast(last); // maybe unused - fix warning + assert(std::isfinite(value)); + + // Use signbit(value) instead of (value < 0) since signbit works for -0. + if (std::signbit(value)) + { + value = -value; + *first++ = '-'; + } + + if (value == 0) // +-0 + { + *first++ = '0'; + // Make it look like a floating-point number (#362, #378) + *first++ = '.'; + *first++ = '0'; + return first; + } + + assert(last - first >= std::numeric_limits::max_digits10); + + // Compute v = buffer * 10^decimal_exponent. + // The decimal digits are stored in the buffer, which needs to be interpreted + // as an unsigned decimal integer. + // len is the length of the buffer, i.e. the number of decimal digits. + int len = 0; + int decimal_exponent = 0; + dtoa_impl::grisu2(first, len, decimal_exponent, value); + + assert(len <= std::numeric_limits::max_digits10); + + // Format the buffer like printf("%.*g", prec, value) + constexpr int kMinExp = -4; + // Use digits10 here to increase compatibility with version 2. + constexpr int kMaxExp = std::numeric_limits::digits10; + + assert(last - first >= kMaxExp + 2); + assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + assert(last - first >= std::numeric_limits::max_digits10 + 6); + + return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +template +class serializer +{ + using string_t = typename BasicJsonType::string_t; + using number_float_t = typename BasicJsonType::number_float_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + static constexpr uint8_t UTF8_ACCEPT = 0; + static constexpr uint8_t UTF8_REJECT = 1; + + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + */ + serializer(output_adapter_t s, const char ichar) + : o(std::move(s)), loc(std::localeconv()), + thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), + decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), + indent_char(ichar), indent_string(512, indent_char) + {} + + // delete because of pointer members + serializer(const serializer&) = delete; + serializer& operator=(const serializer&) = delete; + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(const BasicJsonType& val, const bool pretty_print, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent = 0) + { + switch (val.m_type) + { + case value_t::object: + { + if (val.m_value.object->empty()) + { + o->write_characters("{}", 2); + return; + } + + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + + o->write_character('}'); + } + + return; + } + + case value_t::array: + { + if (val.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } + + if (pretty_print) + { + o->write_characters("[\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(not val.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else + { + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + dump(*i, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(not val.m_value.array->empty()); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + + o->write_character(']'); + } + + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_value.string, ensure_ascii); + o->write_character('\"'); + return; + } + + case value_t::boolean: + { + if (val.m_value.boolean) + { + o->write_characters("true", 4); + } + else + { + o->write_characters("false", 5); + } + return; + } + + case value_t::number_integer: + { + dump_integer(val.m_value.number_integer); + return; + } + + case value_t::number_unsigned: + { + dump_integer(val.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + } + } + + private: + /*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ + void dump_escaped(const string_t& s, const bool ensure_ascii) + { + uint32_t codepoint; + uint8_t state = UTF8_ACCEPT; + std::size_t bytes = 0; // number of bytes written to string_buffer + + for (std::size_t i = 0; i < s.size(); ++i) + { + const auto byte = static_cast(s[i]); + + switch (decode(state, codepoint, byte)) + { + case UTF8_ACCEPT: // decode found a new code point + { + switch (codepoint) + { + case 0x08: // backspace + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'b'; + break; + } + + case 0x09: // horizontal tab + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 't'; + break; + } + + case 0x0A: // newline + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'n'; + break; + } + + case 0x0C: // formfeed + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'f'; + break; + } + + case 0x0D: // carriage return + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'r'; + break; + } + + case 0x22: // quotation mark + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\"'; + break; + } + + case 0x5C: // reverse solidus + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\\'; + break; + } + + default: + { + // escape control characters (0x00..0x1F) or, if + // ensure_ascii parameter is used, non-ASCII characters + if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F))) + { + if (codepoint <= 0xFFFF) + { + std::snprintf(string_buffer.data() + bytes, 7, "\\u%04x", + static_cast(codepoint)); + bytes += 6; + } + else + { + std::snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", + static_cast(0xD7C0 + (codepoint >> 10)), + static_cast(0xDC00 + (codepoint & 0x3FF))); + bytes += 12; + } + } + else + { + // copy byte to buffer (all previous bytes + // been copied have in default case above) + string_buffer[bytes++] = s[i]; + } + break; + } + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + break; + } + + case UTF8_REJECT: // decode found invalid UTF-8 byte + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); + } + + default: // decode found yet incomplete multi-byte code point + { + if (not ensure_ascii) + { + // code point will not be escaped - copy byte to buffer + string_buffer[bytes++] = s[i]; + } + break; + } + } + } + + if (JSON_LIKELY(state == UTF8_ACCEPT)) + { + // write buffer + if (bytes > 0) + { + o->write_characters(string_buffer.data(), bytes); + } + } + else + { + // we finish reading, but do not accept: string was incomplete + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(s.back())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); + } + } + + /*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ + template::value or + std::is_same::value, + int> = 0> + void dump_integer(NumberType x) + { + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } + + const bool is_negative = (x <= 0) and (x != 0); // see issue #755 + std::size_t i = 0; + + while (x != 0) + { + // spare 1 byte for '\0' + assert(i < number_buffer.size() - 1); + + const auto digit = std::labs(static_cast(x % 10)); + number_buffer[i++] = static_cast('0' + digit); + x /= 10; + } + + if (is_negative) + { + // make sure there is capacity for the '-' + assert(i < number_buffer.size() - 2); + number_buffer[i++] = '-'; + } + + std::reverse(number_buffer.begin(), number_buffer.begin() + i); + o->write_characters(number_buffer.data(), i); + } + + /*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ + void dump_float(number_float_t x) + { + // NaN / inf + if (not std::isfinite(x)) + { + o->write_characters("null", 4); + return; + } + + // If number_float_t is an IEEE-754 single or double precision number, + // use the Grisu2 algorithm to produce short numbers which are + // guaranteed to round-trip, using strtof and strtod, resp. + // + // NB: The test below works if == . + static constexpr bool is_ieee_single_or_double + = (std::numeric_limits::is_iec559 and std::numeric_limits::digits == 24 and std::numeric_limits::max_exponent == 128) or + (std::numeric_limits::is_iec559 and std::numeric_limits::digits == 53 and std::numeric_limits::max_exponent == 1024); + + dump_float(x, std::integral_constant()); + } + + void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) + { + char* begin = number_buffer.data(); + char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); + + o->write_characters(begin, static_cast(end - begin)); + } + + void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) + { + // get number of digits for a float -> text -> float round-trip + static constexpr auto d = std::numeric_limits::max_digits10; + + // the actual conversion + std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + + // negative value indicates an error + assert(len > 0); + // check if buffer was large enough + assert(static_cast(len) < number_buffer.size()); + + // erase thousands separator + if (thousands_sep != '\0') + { + const auto end = std::remove(number_buffer.begin(), + number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + assert((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } + + // convert decimal point to '.' + if (decimal_point != '\0' and decimal_point != '.') + { + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + if (dec_pos != number_buffer.end()) + { + *dec_pos = '.'; + } + } + + o->write_characters(number_buffer.data(), static_cast(len)); + + // determine if need to append ".0" + const bool value_is_int_like = + std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, + [](char c) + { + return (c == '.' or c == 'e'); + }); + + if (value_is_int_like) + { + o->write_characters(".0", 2); + } + } + + /*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) + @param[in] byte next byte to decode + @return new state + + @note The function has been edited: a std::array is used. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ + static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept + { + static const std::array utf8d = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 + } + }; + + const uint8_t type = utf8d[byte]; + + codep = (state != UTF8_ACCEPT) + ? (byte & 0x3fu) | (codep << 6) + : static_cast(0xff >> type) & (byte); + + state = utf8d[256u + state * 16u + type]; + return state; + } + + private: + /// the output of the serializer + output_adapter_t o = nullptr; + + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv* loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; + + /// string buffer + std::array string_buffer{{}}; + + /// the indentation character + const char indent_char; + /// the indentation string + string_t indent_string; +}; +} +} + +// #include + + +#include +#include + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) + {} + + json_ref(const value_type& value) + : value_ref(const_cast(&value)), is_rvalue(false) + {} + + json_ref(std::initializer_list init) + : owned_value(init), value_ref(&owned_value), is_rvalue(true) + {} + + template + json_ref(Args&& ... args) + : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) + {} + + // class should be movable only + json_ref(json_ref&&) = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + + value_type moved_or_copied() const + { + if (is_rvalue) + { + return std::move(*value_ref); + } + return *value_ref; + } + + value_type const& operator*() const + { + return *static_cast(value_ref); + } + + value_type const* operator->() const + { + return static_cast(value_ref); + } + + private: + mutable value_type owned_value = nullptr; + value_type* value_ref = nullptr; + const bool is_rvalue; +}; +} +} + +// #include + + +#include // assert +#include // accumulate +#include // string +#include // vector + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +template +class json_pointer +{ + // allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + public: + /*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the empty + string is assumed which references the whole JSON value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and does + not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is + not followed by `0` (representing `~`) or `1` (representing `/`); see + example below + + @liveexample{The example shows the construction several valid JSON pointers + as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ + explicit json_pointer(const std::string& s = "") + : reference_tokens(split(s)) + {} + + /*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`., + json_pointer__to_string} + + @since version 2.0.0 + */ + std::string to_string() const noexcept + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + escape(b); + }); + } + + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } + + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw out_of_range.404 if string @a s could not be converted to an integer + */ + static int array_index(const std::string& s) + { + std::size_t processed_chars = 0; + const int res = std::stoi(s, &processed_chars); + + // check if the string was completely read + if (JSON_UNLIKELY(processed_chars != s.size())) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); + } + + return res; + } + + private: + /*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ + std::string pop_back() + { + if (JSON_UNLIKELY(is_root())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + auto last = reference_tokens.back(); + reference_tokens.pop_back(); + return last; + } + + /// return whether pointer points to the root document + bool is_root() const + { + return reference_tokens.empty(); + } + + json_pointer top() const + { + if (JSON_UNLIKELY(is_root())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + BasicJsonType& get_and_create(BasicJsonType& j) const + { + using size_type = typename BasicJsonType::size_type; + auto result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->m_type) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + JSON_TRY + { + result = &result->operator[](static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_unchecked(BasicJsonType* ptr) const + { + using size_type = typename BasicJsonType::size_type; + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->m_type == detail::value_t::null) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const char x) + { + return (x >= '0' and x <= '9'); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums or reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->m_type) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + JSON_TRY + { + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_checked(BasicJsonType* ptr) const + { + using size_type = typename BasicJsonType::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const + { + using size_type = typename BasicJsonType::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // use unchecked array access + JSON_TRY + { + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_checked(const BasicJsonType* ptr) const + { + using size_type = typename BasicJsonType::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const std::string& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, + "JSON pointer must be empty or begin with '/' - was: '" + + reference_string + "'")); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == string::npos+1 = 0 + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != std::string::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + assert(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_UNLIKELY(pos == reference_token.size() - 1 or + (reference_token[pos + 1] != '0' and + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); + } + } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** + + @since version 2.0.0 + */ + static void replace_substring(std::string& s, const std::string& f, + const std::string& t) + { + assert(not f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} + } + + /// escape "~"" to "~0" and "/" to "~1" + static std::string escape(std::string s) + { + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } + + /// unescape "~1" to tilde and "~0" to slash (order is important!) + static void unescape(std::string& s) + { + replace_substring(s, "~1", "/"); + replace_substring(s, "~0", "~"); + } + + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + static void flatten(const std::string& reference_string, + const BasicJsonType& value, + BasicJsonType& result) + { + switch (value.m_type) + { + case detail::value_t::array: + { + if (value.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), element.second, result); + } + } + break; + } + + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + static BasicJsonType + unflatten(const BasicJsonType& value) + { + if (JSON_UNLIKELY(not value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); + } + + BasicJsonType result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (JSON_UNLIKELY(not element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + friend bool operator==(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return (lhs.reference_tokens == rhs.reference_tokens); + } + + friend bool operator!=(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return not (lhs == rhs); + } + + /// the reference tokens + std::vector reference_tokens; +}; +} + +// #include + + +#include + +// #include + +// #include + + +namespace nlohmann +{ +template +struct adl_serializer +{ + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static void from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static void to_json(BasicJsonType& j, ValueType&& val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; +} + + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json +{ + private: + template friend struct detail::external_constructor; + friend ::nlohmann::json_pointer; + friend ::nlohmann::detail::parser; + friend ::nlohmann::detail::serializer; + template + friend class ::nlohmann::detail::iter_impl; + template + friend class ::nlohmann::detail::binary_writer; + template + friend class ::nlohmann::detail::binary_reader; + + /// workaround type for MSVC + using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + + // convenience aliases for types residing in namespace detail; + using lexer = ::nlohmann::detail::lexer; + using parser = ::nlohmann::detail::parser; + + using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; + template + using internal_iterator = ::nlohmann::detail::internal_iterator; + template + using iter_impl = ::nlohmann::detail::iter_impl; + template + using iteration_proxy = ::nlohmann::detail::iteration_proxy; + template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + + template + using output_adapter_t = ::nlohmann::detail::output_adapter_t; + + using binary_reader = ::nlohmann::detail::binary_reader; + template using binary_writer = ::nlohmann::detail::binary_writer; + + using serializer = ::nlohmann::detail::serializer; + + public: + using value_t = detail::value_t; + /// @copydoc nlohmann::json_pointer + using json_pointer = ::nlohmann::json_pointer; + template + using json_serializer = JSONSerializer; + /// helper type for initializer lists of basic_json values + using initializer_list_t = std::initializer_list>; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /// @copydoc detail::exception + using exception = detail::exception; + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; + + /// @} + + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @complexity Constant. + + @since 2.1.0 + */ + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2017 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"]["string"] = + std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_PATCH); + result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; + result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; + result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; + +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + +#if defined(JSON_HAS_CPP_14) + // Use transparent comparator if possible, combined with perfect forwarding + // on find() and count() calls prevents unnecessary string construction. + using object_comparator_t = std::less<>; +#else + using object_comparator_t = std::less; +#endif + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, it is unspecified which + one of the values for a given key will be chosen. For instance, + `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or + `{"key": 2}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /// @} + + private: + + /// helper for exception-safe object creation + template + static T* create(Args&& ... args) + { + AllocatorType alloc; + using AllocatorTraits = std::allocator_traits>; + + auto deleter = [&](T * object) + { + AllocatorTraits::deallocate(alloc, object, 1); + }; + std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); + AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); + assert(object != nullptr); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + case value_t::null: + { + object = nullptr; // silence warning, see #821 + break; + } + + default: + { + object = nullptr; // silence warning, see #821 + if (JSON_UNLIKELY(t == value_t::null)) + { + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.2")); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for rvalue strings + json_value(string_t&& value) + { + string = create(std::move(value)); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for rvalue objects + json_value(object_t&& value) + { + object = create(std::move(value)); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + + /// constructor for rvalue arrays + json_value(array_t&& value) + { + array = create(std::move(value)); + } + + void destroy(value_t t) noexcept + { + switch (t) + { + case value_t::object: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, object); + std::allocator_traits::deallocate(alloc, object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, array); + std::allocator_traits::deallocate(alloc, array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + break; + } + + default: + { + break; + } + } + } + }; + + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ + void assert_invariant() const noexcept + { + assert(m_type != value_t::object or m_value.object != nullptr); + assert(m_type != value_t::array or m_value.array != nullptr); + assert(m_type != value_t::string or m_value.string != nullptr); + } + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief parser event types + + The parser callback distinguishes the following events: + - `object_start`: the parser read `{` and started to process a JSON object + - `key`: the parser read a key of a value in an object + - `object_end`: the parser read `}` and finished processing a JSON object + - `array_start`: the parser read `[` and started to process a JSON array + - `array_end`: the parser read `]` and finished processing a JSON array + - `value`: the parser finished reading a JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + @sa @ref parser_callback_t for more information and examples + */ + using parse_event_t = typename parser::parse_event_t; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse, it is called on certain events + (passed as @ref parse_event_t via parameter @a event) with a set recursion + depth @a depth and context JSON value @a parsed. The return value of the + callback function is a boolean indicating whether the element that emitted + the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse for examples + + @since version 1.0.0 + */ + using parser_callback_t = typename parser::parser_callback_t; + + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] v the type of the value to create + + @complexity Constant. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref clear() -- restores the postcondition of this constructor + + @since version 1.0.0 + */ + basic_json(const value_t v) + : m_type(v), m_value(v) + { + assert_invariant(); + } + + /*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } + + /*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exists. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments) + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded to the respective constructor + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ + template , + detail::enable_if_t< + detail::is_compatible_type::value, int> = 0> + basic_json(CompatibleType && val) noexcept(noexcept( + JSONSerializer::to_json(std::declval(), + std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + assert_invariant(); + } + + /*! + @brief create a JSON value from an existing one + + This is a constructor for existing @ref basic_json types. + It does not hijack copy/move constructors, since the parameter has different + template arguments than the current ones. + + The constructor tries to convert the internal @ref m_value of the parameter. + + @tparam BasicJsonType a type such that: + - @a BasicJsonType is a @ref basic_json type. + - @a BasicJsonType has different template arguments than @ref basic_json_t. + + @param[in] val the @ref basic_json value to be converted. + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @since version 3.1.2 + */ + template ::value and not std::is_same::value, int> = 0> + basic_json(const BasicJsonType& val) + { + using other_boolean_t = typename BasicJsonType::boolean_t; + using other_number_float_t = typename BasicJsonType::number_float_t; + using other_number_integer_t = typename BasicJsonType::number_integer_t; + using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using other_string_t = typename BasicJsonType::string_t; + using other_object_t = typename BasicJsonType::object_t; + using other_array_t = typename BasicJsonType::array_t; + + switch (val.type()) + { + case value_t::boolean: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_float: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_integer: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_unsigned: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::string: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::object: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::array: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::null: + *this = nullptr; + break; + case value_t::discarded: + m_type = value_t::discarded; + break; + } + assert_invariant(); + } + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has no way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(initializer_list_t) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(initializer_list_t) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(initializer_list_t) and + @ref object(initializer_list_t). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(initializer_list_t) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(initializer_list_t init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const detail::json_ref& element_ref) + { + return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string()); + }); + + // adjust type if type deduction is not wanted + if (not type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object)) + { + JSON_THROW(type_error::create(301, "cannot create object from initializer list")); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) + { + auto element = element_ref.moved_or_copied(); + m_value.object->emplace( + std::move(*((*element.m_value.array)[0].m_value.string)), + std::move((*element.m_value.array)[1])); + }); + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init.begin(), init.end()); + } + + assert_invariant(); + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(initializer_list_t, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + static basic_json array(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(initializer_list_t), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(initializer_list_t, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(initializer_list_t, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + static basic_json object(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @post `std::distance(begin(),end()) == cnt` holds. + + @complexity Linear in @a cnt. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + assert_invariant(); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. + + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See http://en.cppreference.com/w/cpp/error/assert for more + information. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. + + @complexity Linear in distance between @a first and @a last. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type = 0> + basic_json(InputIT first, InputIT last) + { + assert(first.m_object != nullptr); + assert(last.m_object != nullptr); + + // make sure iterator fits the current value + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); + } + + // copy type from first iterator + m_type = first.m_object->m_type; + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin() + or not last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + break; + } + + default: + break; + } + + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + + std::string(first.m_object->type_name()))); + } + + assert_invariant(); + } + + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + /// @private + basic_json(const detail::json_ref& ref) + : basic_json(ref.moved_or_copied()) + {} + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @post `*this == other` + + @complexity Linear in the size of @a other. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + // check of passed value is valid + other.assert_invariant(); + + switch (m_type) + { + case value_t::object: + { + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + default: + break; + } + + assert_invariant(); + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) + requirements. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(); + + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + + assert_invariant(); + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the `swap()` member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + reference& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + // check that passed value is valid + other.assert_invariant(); + + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + + assert_invariant(); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() noexcept + { + assert_invariant(); + m_value.destroy(m_type); + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + and @a ensure_ascii parameters. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation if @a indent is + greater than `0`. The default is ` ` (space). + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + + @return string containing the serialization of the JSON value + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0; indentation character @a indent_char, option + @a ensure_ascii and exceptions added in version 3.0.0 + */ + string_t dump(const int indent = -1, const char indent_char = ' ', + const bool ensure_ascii = false) const + { + string_t result; + serializer s(detail::output_adapter(result), indent_char); + + if (indent >= 0) + { + s.dump(*this, true, ensure_ascii, static_cast(indent)); + } + else + { + s.dump(*this, false, ensure_ascii, 0); + } + + return result; + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (floating-point) | value_t::number_float + object | value_t::object + array | value_t::array + discarded | value_t::discarded + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } + + /*! + @brief return whether type is structured + + This function returns true if and only if the JSON type is structured + (array or object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() or is_object(); + } + + /*! + @brief return whether value is null + + This function returns true if and only if the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return (m_type == value_t::null); + } + + /*! + @brief return whether value is a boolean + + This function returns true if and only if the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return (m_type == value_t::boolean); + } + + /*! + @brief return whether value is a number + + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return (m_type == value_t::number_integer or m_type == value_t::number_unsigned); + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return (m_type == value_t::number_unsigned); + } + + /*! + @brief return whether value is a floating-point number + + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return (m_type == value_t::number_float); + } + + /*! + @brief return whether value is an object + + This function returns true if and only if the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return (m_type == value_t::object); + } + + /*! + @brief return whether value is an array + + This function returns true if and only if the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return (m_type == value_t::array); + } + + /*! + @brief return whether value is a string + + This function returns true if and only if the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return (m_type == value_t::string); + } + + /*! + @brief return whether value is discarded + + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return (m_type == value_t::discarded); + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @sa @ref type() -- return the type of the JSON value (explicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t* /*unused*/) const + { + if (JSON_LIKELY(is_boolean())) + { + return m_value.boolean; + } + + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t* /*unused*/) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t* /*unused*/) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t* /*unused*/) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + auto ptr = obj.template get_ptr::type>(); + + if (JSON_LIKELY(ptr != nullptr)) + { + return *ptr; + } + + JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); + } + + public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template::type, basic_json_t>::value, + int> = 0> + basic_json get() const + { + return *this; + } + + /*! + @brief get special-case overload + + This overloads converts the current @ref basic_json in a different + @ref basic_json type + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this, converted into @tparam BasicJsonType + + @complexity Depending on the implementation of the called `from_json()` + method. + + @since version 3.1.2 + */ + template::value and + detail::is_basic_json::value, int> = 0> + BasicJsonType get() const + { + return *this; + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template, + detail::enable_if_t < + not detail::is_basic_json::value and + detail::has_from_json::value and + not detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + static_assert(std::is_default_constructible::value, + "types must be DefaultConstructible when used with get()"); + + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template, + detail::enable_if_t::value and + detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) + { + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return JSONSerializer::from_json(*this); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, int>::type = 0> + constexpr const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get_ptr() noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + constexpr const PointerType get_ptr() const noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename std::enable_if < + not std::is_pointer::value and + not std::is_same>::value and + not std::is_same::value and + not detail::is_basic_json::value +#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 + and not std::is_same>::value +#endif +#if defined(JSON_HAS_CPP_17) + and not std::is_same::value +#endif + , int >::type = 0 > + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// Access to the JSON value. + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ + reference at(size_type idx) + { + // at only works for arrays + if (JSON_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (JSON_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); + } + + // operator[] only works for arrays + if (JSON_LIKELY(is_array())) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); + } + + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array; in that case, + using the [] operator with an index makes no sense. + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (JSON_LIKELY(is_array())) + { + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (JSON_LIKELY(is_object())) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // at only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + const_reference operator[](T* key) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + template::value, int>::type = 0> + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + + return default_value; + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an objec; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ + template::value, int>::type = 0> + ValueType value(const json_pointer& ptr, const ValueType& default_value) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this); + } + JSON_CATCH (out_of_range&) + { + return default_value; + } + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on a `null` value. See example + below. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType pos) + { + // make sure iterator fits the current value + if (JSON_UNLIKELY(this != pos.m_object)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin())) + { + JSON_THROW(invalid_iterator::create(205, "iterator out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType first, IteratorType last) + { + // make sure iterator fits the current value + if (JSON_UNLIKELY(this != first.m_object or this != last.m_object)) + { + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin() + or not last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->erase(key); + } + + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (JSON_LIKELY(is_array())) + { + if (JSON_UNLIKELY(idx >= size())) + { + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + } + + /// @} + + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for. + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ + template + iterator find(KeyT&& key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(KeyT&&) + */ + template + const_iterator find(KeyT&& key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + template + size_type count(KeyT&& key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(std::forward(key)) : 0; + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @note The name of this function is not yet final and may change in the + future. + + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use @ref items() instead; + that is, replace `json::iterator_wrapper(j)` with `j.items()`. + */ + JSON_DEPRECATED + static iteration_proxy iterator_wrapper(reference ref) noexcept + { + return ref.items(); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + JSON_DEPRECATED + static iteration_proxy iterator_wrapper(const_reference ref) noexcept + { + return ref.items(); + } + + /*! + @brief helper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without `items()` function: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without `items()` function: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with `items()` function: + + @code{cpp} + for (auto it : j_object.items()) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). For primitive types (e.g., numbers), + `key()` returns an empty string. + + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the function is used.,items} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 3.x.x. + */ + iteration_proxy items() noexcept + { + return iteration_proxy(*this); + } + + /*! + @copydoc items() + */ + iteration_proxy items() const noexcept + { + return iteration_proxy(*this); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty. + + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); + } + + case value_t::object: + { + // delegate call to object_t::empty() + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + // delegate call to array_t::size() + return m_value.array->size(); + } + + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + // delegate call to array_t::max_size() + return m_value.array->max_size(); + } + + case value_t::object: + { + // delegate call to object_t::max_size() + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + m_value.string->clear(); + break; + } + + case value_t::array: + { + m_value.array->clear(); + break; + } + + case value_t::object: + { + m_value.object->clear(); + break; + } + + default: + break; + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (move semantics) + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (JSON_UNLIKELY(not(is_null() or is_object()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param[in] init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(initializer_list_t init) + { + if (is_object() and init.size() == 2 and (*init.begin())->is_string()) + { + basic_json&& key = init.begin()->moved_or_copied(); + push_back(typename object_t::value_type( + std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); + } + else + { + push_back(basic_json(init)); + } + } + + /*! + @brief add an object to an object + @copydoc push_back(initializer_list_t) + */ + reference operator+=(initializer_list_t init) + { + push_back(init); + return *this; + } + + /*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8 + */ + template + void emplace_back(Args&& ... args) + { + // emplace_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (perfect forwarding) + m_value.array->emplace_back(std::forward(args)...); + } + + /*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ + template + std::pair emplace(Args&& ... args) + { + // emplace only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_object()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array (perfect forwarding) + auto res = m_value.object->emplace(std::forward(args)...); + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; + + // return pair of iterator and boolean + return {it, res.second}; + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (JSON_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (JSON_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (JSON_UNLIKELY(not is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + if (JSON_UNLIKELY(first.m_object == this)) + { + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert( + pos.m_it.array_iterator, + first.m_it.array_iterator, + last.m_it.array_iterator); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, initializer_list_t ilist) + { + // insert only works for arrays + if (JSON_UNLIKELY(not is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)`. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. + + @liveexample{The example shows how `insert()` is used.,insert__range_object} + + @since version 3.0.0 + */ + void insert(const_iterator first, const_iterator last) + { + // insert only works for objects + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_UNLIKELY(not first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from JSON object @a j and overwrites existing keys. + + @param[in] j JSON object to read values from + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_reference j) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); + } + + for (auto it = j.cbegin(); it != j.cend(); ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from from range `[first, last)` and overwrites existing + keys. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used__range.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_iterator first, const_iterator last) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_UNLIKELY(not first.m_object->is_object() + or not last.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + for (auto it = first; it != last; ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + assert_invariant(); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (JSON_LIKELY(is_array())) + { + std::swap(*(m_value.array), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (JSON_LIKELY(is_object())) + { + std::swap(*(m_value.object), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (JSON_LIKELY(is_string())) + { + std::swap(*(m_value.string), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /// @} + + public: + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Note than two NaN values are always treated as unequal. + - Two JSON null values are equal. + + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + + @note NaN values never compare equal to themselves or to other NaN values. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return (*lhs.m_value.array == *rhs.m_value.array); + + case value_t::object: + return (*lhs.m_value.object == *rhs.m_value.object); + + case value_t::null: + return true; + + case value_t::string: + return (*lhs.m_value.string == *rhs.m_value.string); + + case value_t::boolean: + return (lhs.m_value.boolean == rhs.m_value.boolean); + + case value_t::number_integer: + return (lhs.m_value.number_integer == rhs.m_value.number_integer); + + case value_t::number_unsigned: + return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned); + + case value_t::number_float: + return (lhs.m_value.number_float == rhs.m_value.number_float); + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return (static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return (lhs.m_value.number_float == static_cast(rhs.m_value.number_integer)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return (lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return (lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned)); + } + + return false; + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs == basic_json(rhs)); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) == rhs); + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs == rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs != basic_json(rhs)); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) != rhs); + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return (*lhs.m_value.array) < (*rhs.m_value.array); + + case value_t::object: + return *lhs.m_value.object < *rhs.m_value.object; + + case value_t::null: + return false; + + case value_t::string: + return *lhs.m_value.string < *rhs.m_value.string; + + case value_t::boolean: + return lhs.m_value.boolean < rhs.m_value.boolean; + + case value_t::number_integer: + return lhs.m_value.number_integer < rhs.m_value.number_integer; + + case value_t::number_unsigned: + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + + case value_t::number_float: + return lhs.m_value.number_float < rhs.m_value.number_float; + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs < basic_json(rhs)); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) < rhs); + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not (rhs < lhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs <= basic_json(rhs)); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) <= rhs); + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs <= rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs > basic_json(rhs)); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) > rhs); + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs < rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs >= basic_json(rhs)); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) >= rhs); + } + + /// @} + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation character can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentation character added in version 3.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + serializer s(detail::output_adapter(o), o.fill()); + s.dump(j, pretty_print, false, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use + @ref operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_DEPRECATED + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from a compatible input + + This function reads from a compatible input. Examples are: + - an array of 1-byte values + - strings with character/literal type with size of 1 byte + - input streams + - container with contiguous storage of 1-byte values. Compatible container + types include `std::vector`, `std::string`, `std::array`, + `std::valarray`, and `std::initializer_list`. Furthermore, C-style + arrays can be used with `std::begin()`/`std::end()`. User-defined + containers can be used as long as they implement random-access iterators + and a contiguous storage. + + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @pre The container storage is contiguous. Violating this precondition + yields undefined behavior. **This precondition is enforced with an + assertion.** + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with a noncompliant container and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @param[in] i input to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 (contiguous containers) + */ + static basic_json parse(detail::input_adapter i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(i, cb, allow_exceptions).parse(true, result); + return result; + } + + /*! + @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) + */ + static basic_json parse(detail::input_adapter& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(i, cb, allow_exceptions).parse(true, result); + return result; + } + + static bool accept(detail::input_adapter i) + { + return parser(i).accept(true); + } + + static bool accept(detail::input_adapter& i) + { + return parser(i).accept(true); + } + + /*! + @brief deserialize from an iterator range with contiguous storage + + This function reads from an iterator range of a container with contiguous + storage of 1-byte values. Compatible container types include + `std::vector`, `std::string`, `std::array`, `std::valarray`, and + `std::initializer_list`. Furthermore, C-style arrays can be used with + `std::begin()`/`std::end()`. User-defined containers can be used as long + as they implement random-access iterators and a contiguous storage. + + @pre The iterator range is contiguous. Violating this precondition yields + undefined behavior. **This precondition is enforced with an assertion.** + @pre Each element in the range has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with noncompliant iterators and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam IteratorType iterator of container with contiguous storage + @param[in] first begin of the range to parse (included) + @param[in] last end of the range to parse (excluded) + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an iterator range.,parse__iteratortype__parser_callback_t} + + @since version 2.0.3 + */ + template::iterator_category>::value, int>::type = 0> + static basic_json parse(IteratorType first, IteratorType last, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); + return result; + } + + template::iterator_category>::value, int>::type = 0> + static bool accept(IteratorType first, IteratorType last) + { + return parser(detail::input_adapter(first, last)).accept(true); + } + + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in + version 4.0.0 of the library. Please use + @ref operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_DEPRECATED + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + return operator>>(i, j); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + parser(detail::input_adapter(i)).parse(false, j); + return i; + } + + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @sa @ref type() -- return the type of the JSON value + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 + */ + const char* type_name() const noexcept + { + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + } + + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + + public: + /*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value* | Double-Precision Float | 0xFB + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The following CBOR types are not used in the conversion: + - byte strings (0x40..0x5F) + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half and single-precision floats (0xF9-0xFA) + - break (0xFF) + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(detail::input_adapter, const bool strict) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ + static std::vector to_cbor(const basic_json& j) + { + std::vector result; + to_cbor(j, result); + return result; + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note The following MessagePack types are not used in the conversion: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - float 32 (0xCA) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ + static std::vector to_msgpack(const basic_json& j) + { + std::vector result; + to_msgpack(j, result); + return result; + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + /*! + @brief create a UBJSON serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the UBJSON + (Universal Binary JSON) serialization format. UBJSON aims to be more compact + than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + UBJSON types according to the UBJSON specification: + + JSON value type | value/range | UBJSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | `Z` + boolean | `true` | true | `T` + boolean | `false` | false | `F` + number_integer | -9223372036854775808..-2147483649 | int64 | `L` + number_integer | -2147483648..-32769 | int32 | `l` + number_integer | -32768..-129 | int16 | `I` + number_integer | -128..127 | int8 | `i` + number_integer | 128..255 | uint8 | `U` + number_integer | 256..32767 | int16 | `I` + number_integer | 32768..2147483647 | int32 | `l` + number_integer | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 0..127 | int8 | `i` + number_unsigned | 128..255 | uint8 | `U` + number_unsigned | 256..32767 | int16 | `I` + number_unsigned | 32768..2147483647 | int32 | `l` + number_unsigned | 2147483648..9223372036854775807 | int64 | `L` + number_float | *any value* | float64 | `D` + string | *with shortest length indicator* | string | `S` + array | *see notes on optimized format* | array | `[` + object | *see notes on optimized format* | map | `{` + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a UBJSON value. + + @note The following values can **not** be converted to a UBJSON value: + - strings with more than 9223372036854775807 bytes (theoretical) + - unsigned integer numbers above 9223372036854775807 + + @note The following markers are not used in the conversion: + - `Z`: no-op values are not created. + - `C`: single-byte strings are serialized with `S` markers. + + @note Any UBJSON output created @ref to_ubjson can be successfully parsed + by @ref from_ubjson. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The optimized formats for containers are supported: Parameter + @a use_size adds size information to the beginning of a container and + removes the closing marker. Parameter @a use_type further checks + whether all elements of a container have the same type and adds the + type marker to the beginning of the container. The @a use_type + parameter must only be used together with @a use_size = true. Note + that @a use_size = true alone may result in larger representations - + the benefit of this parameter is that the receiving side is + immediately informed on the number of elements of the container. + + @param[in] j JSON value to serialize + @param[in] use_size whether to add size annotations to container types + @param[in] use_type whether to add type annotations to container types + (must be combined with @a use_size = true) + @return UBJSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in UBJSON format.,to_ubjson} + + @sa http://ubjson.org + @sa @ref from_ubjson(detail::input_adapter, const bool strict) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + + @since version 3.1.0 + */ + static std::vector to_ubjson(const basic_json& j, + const bool use_size = false, + const bool use_type = false) + { + std::vector result; + to_ubjson(j, result, use_size, use_type); + return result; + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + /*! + @brief create a JSON value from an input in CBOR format + + Deserializes a given input @a i to a JSON value using the CBOR (Concise + Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B + Negative integer | number_integer | 0x40..0x57 + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Nill | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - byte strings (0x40..0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] i an input in CBOR format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @return deserialized JSON value + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from CBOR were + used in the given input @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(detail::input_adapter, const bool) for the + related MessagePack format + @sa @ref from_ubjson(detail::input_adapter, const bool) for the related + UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ + static basic_json from_cbor(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_cbor(strict); + } + + /*! + @copydoc from_cbor(detail::input_adapter, const bool) + */ + template::value, int> = 0> + static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_cbor(strict); + } + + /*! + @brief create a JSON value from an input in MessagePack format + + Deserializes a given input @a i to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + negative fixint | number_integer | 0xE0-0xFF + + @warning The mapping is **incomplete** in the sense that not all + MessagePack types can be converted to a JSON value. The following + MessagePack types are not supported and will yield parse errors: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] i an input in MessagePack format convertible to an input + adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from MessagePack were + used in the given input @a i or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + @sa @ref from_ubjson(detail::input_adapter, const bool) for the related + UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ + static basic_json from_msgpack(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_msgpack(strict); + } + + /*! + @copydoc from_msgpack(detail::input_adapter, const bool) + */ + template::value, int> = 0> + static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_msgpack(strict); + } + + /*! + @brief create a JSON value from an input in UBJSON format + + Deserializes a given input @a i to a JSON value using the UBJSON (Universal + Binary JSON) serialization format. + + The library maps UBJSON types to JSON value types as follows: + + UBJSON type | JSON value type | marker + ----------- | --------------------------------------- | ------ + no-op | *no value, next value is read* | `N` + null | `null` | `Z` + false | `false` | `F` + true | `true` | `T` + float32 | number_float | `d` + float64 | number_float | `D` + uint8 | number_unsigned | `U` + int8 | number_integer | `i` + int16 | number_integer | `I` + int32 | number_integer | `l` + int64 | number_integer | `L` + string | string | `S` + char | string | `C` + array | array (optimized values are supported) | `[` + object | object (optimized values are supported) | `{` + + @note The mapping is **complete** in the sense that any UBJSON value can + be converted to a JSON value. + + @param[in] i an input in UBJSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if a parse error occurs + @throw parse_error.113 if a string could not be parsed successfully + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + UBJSON format to a JSON value.,from_ubjson} + + @sa http://ubjson.org + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + @sa @ref from_msgpack(detail::input_adapter, const bool) for the related + MessagePack format + + @since version 3.1.0 + */ + static basic_json from_ubjson(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_ubjson(strict); + } + + template::value, int> = 0> + static basic_json from_ubjson(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_ubjson(strict); + } + + /// @} + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + basic_json patch(const basic_json& json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; + + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const std::string & op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.is_root()) + { + result = val; + } + else + { + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) + { + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = json_pointer::array_index(last_path); + if (JSON_UNLIKELY(static_cast(idx) > parent.size())) + { + // avoid undefined behavior + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + else + { + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + } + break; + } + + default: + { + // if there exists a parent it cannot be primitive + assert(false); // LCOV_EXCL_LINE + } + } + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (JSON_LIKELY(it != parent.end())) + { + parent.erase(it); + } + else + { + JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(static_cast(json_pointer::array_index(last_path))); + } + }; + + // type check: top level value must be an array + if (JSON_UNLIKELY(not json_patch.is_array())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // iterate and apply the operations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json & + { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (JSON_UNLIKELY(it == val.m_value.object->end())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); + } + + // check if result is of type string + if (JSON_UNLIKELY(string_type and not it->second.is_string())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); + } + + // no error: return value + return it->second; + }; + + // type check: every element of the array must be an object + if (JSON_UNLIKELY(not val.is_object())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // collect mandatory members + const std::string op = get_value("op", "op", true); + const std::string path = get_value(op, "path", true); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const std::string from_path = get_value("move", "from", true); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const std::string from_path = get_value("copy", "from", true); + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; + } + + case patch_operations::test: + { + bool success = false; + JSON_TRY + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + JSON_CATCH (out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (JSON_UNLIKELY(not success)) + { + JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); + } + + break; + } + + case patch_operations::invalid: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); + } + } + } + + return result; + } + + /*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + @sa @ref merge_patch -- apply a JSON Merge Patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + static basic_json diff(const basic_json& source, const basic_json& target, + const std::string& path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + } + else + { + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + std::size_t i = 0; + while (i < source.size() and i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + std::to_string(i)}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.cbegin(); it != source.cend(); ++it) + { + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, {"path", path + "/" + key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.cbegin(); it != target.cend(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back( + { + {"op", "add"}, {"path", path + "/" + key}, + {"value", it.value()} + }); + } + } + + break; + } + + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + break; + } + } + } + + return result; + } + + /// @} + + //////////////////////////////// + // JSON Merge Patch functions // + //////////////////////////////// + + /// @name JSON Merge Patch functions + /// @{ + + /*! + @brief applies a JSON Merge Patch + + The merge patch format is primarily intended for use with the HTTP PATCH + method as a means of describing a set of modifications to a target + resource's content. This function applies a merge patch to the current + JSON value. + + The function implements the following algorithm from Section 2 of + [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396): + + ``` + define MergePatch(Target, Patch): + if Patch is an Object: + if Target is not an Object: + Target = {} // Ignore the contents and set it to an empty Object + for each Name/Value pair in Patch: + if Value is null: + if Name exists in Target: + remove the Name/Value pair from Target + else: + Target[Name] = MergePatch(Target[Name], Value) + return Target + else: + return Patch + ``` + + Thereby, `Target` is the current object; that is, the patch is applied to + the current value. + + @param[in] patch the patch to apply + + @complexity Linear in the lengths of @a patch. + + @liveexample{The following code shows how a JSON Merge Patch is applied to + a JSON document.,merge_patch} + + @sa @ref patch -- apply a JSON patch + @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396) + + @since version 3.0.0 + */ + void merge_patch(const basic_json& patch) + { + if (patch.is_object()) + { + if (not is_object()) + { + *this = object(); + } + for (auto it = patch.begin(); it != patch.end(); ++it) + { + if (it.value().is_null()) + { + erase(it.key()); + } + else + { + operator[](it.key()).merge_patch(it.value()); + } + } + } + else + { + *this = patch; + } + } + + /// @} +}; +} // namespace nlohmann + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +/// hash value for JSON objects +template<> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + const auto& h = hash(); + return h(j.dump()); + } +}; + +/// specialization for std::less +/// @note: do not remove the space after '<', +/// see https://github.com/nlohmann/json/pull/679 +template<> +struct less< ::nlohmann::detail::value_t> +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, + nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } +}; + +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ + return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +// #include + + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif +#if defined(__clang__) + #pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_LIKELY +#undef JSON_UNLIKELY +#undef JSON_DEPRECATED +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef NLOHMANN_JSON_HAS_HELPER + + +#endif diff --git a/deps/game_ai_lib/utils/memory.cpp b/deps/game_ai_lib/utils/memory.cpp new file mode 100644 index 0000000000..2dda5dc7b3 --- /dev/null +++ b/deps/game_ai_lib/utils/memory.cpp @@ -0,0 +1,521 @@ +// Adapted from OpenAI's retro source code: +// https://github.com/openai/retro + +#include "memory.h" + +#include +#include +#include +#include + +using namespace Retro; +using namespace std; + +Endian Retro::reduce(Endian e) { + switch (e) { + case Endian::BIG: + case Endian::LITTLE: + case Endian::UNDEF: + case Endian::MIXED_BL: + case Endian::MIXED_LB: + return e; + case Endian::NATIVE: + return Endian::REAL_NATIVE; + case Endian::MIXED_BN: + return Endian::REAL_MIXED_BN; + case Endian::MIXED_LN: + return Endian::REAL_MIXED_LN; + } + return e; +} + +bool Retro::reduceCompare(Endian a, Endian b) { + return reduce(a) == reduce(b); +} + +DataType::DataType(const char* type) + : width(type[strlen(type) - 1] - '0') + , endian( + type[0] == '=' ? Endian::NATIVE : type[0] == '>' ? (type[1] == '<' ? Endian::MIXED_BL : type[1] == '=' ? Endian::MIXED_BN : Endian::BIG) : type[0] == '<' ? (type[1] == '>' ? Endian::MIXED_LB : type[1] == '=' ? Endian::MIXED_LN : Endian::LITTLE) : Endian::UNDEF) + , repr(static_cast(type[strlen(type) - 2])) + , type{ type[0], type[1], type[2], type[3] } + , maskLo(repr == Repr::LN_BCD || repr == Repr::BCD ? 0xF : 0xFF) + , maskHi(repr == Repr::BCD ? 0xF0 : 0x0) + , cvt(repr == Repr::BCD || repr == Repr::LN_BCD ? 10 : 256) { + uint64_t shiftInc = + repr == Repr::BCD ? 100 : repr == Repr::LN_BCD ? 10 : 256; + + int baseLoc; + int baseEnd; + int halfLoc = -1; + int diff; + + if (width > 8) { + throw std::out_of_range("Invalid DataType width"); + } + + switch (reduce(endian)) { + case Endian::LITTLE: + default: + baseLoc = 0; + baseEnd = width; + diff = 1; + break; + case Endian::BIG: + baseLoc = width - 1; + baseEnd = -1; + diff = -1; + break; + case Endian::MIXED_LB: + baseLoc = width / 2 - 1; + baseEnd = -1; + halfLoc = width - 1; + diff = -1; + break; + case Endian::MIXED_BL: + baseLoc = width / 2; + baseEnd = width; + halfLoc = 0; + diff = 1; + break; + } + + uint64_t baseShift = 1; + for (int i = baseLoc; i != baseEnd; i += diff, baseShift *= shiftInc) { + shift[i] = baseShift; + } + if (halfLoc >= 0) { + for (int i = halfLoc; i != baseLoc; i += diff, baseShift *= shiftInc) { + shift[i] = baseShift; + } + } +} + +DataType::DataType(const string& type) + : DataType(type.c_str()) { +} + +Datum DataType::operator()(void* base) const { + return Datum(base, *this); +} + +Datum DataType::operator()(void* base, size_t offset, const MemoryOverlay& overlay) const { + return Datum(base, offset, *this, overlay); +} + +bool DataType::operator==(const DataType& other) const { + return width == other.width && endian == other.endian && repr == other.repr; +} + +bool DataType::operator!=(const DataType& other) const { + return !(*this == other); +} + +void DataType::encode(void* buffer, int64_t value) const { + for (size_t i = 0; i < width; ++i) { + uint64_t b = (uint64_t) value / shift[i]; + b = b % cvt + b / cvt % cvt * (~maskHi + 1); + static_cast(buffer)[i] = b; + } +} + +int64_t DataType::decode(const void* buffer) const { + int64_t datum = 0; + for (size_t i = 0; i < width; ++i) { + uint8_t b = static_cast(buffer)[i]; + datum += ((b & maskLo) % cvt + ((b & maskHi) >> 4) % cvt * 10) * shift[i]; + } + if (repr == Repr::SIGNED) { + datum <<= 8 * (8 - width); + datum >>= 8 * (8 - width); + } + return datum; +} + +size_t hash::operator()(const DataType& type) const { + return hash()(*reinterpret_cast(type.type)); +} + +static constexpr char endianTag(Endian e) { + switch (e) { + case Endian::BIG: + return '>'; + case Endian::LITTLE: + return '<'; + default: + case Endian::UNDEF: + return '|'; + case Endian::NATIVE: + return '='; + } +} + +MemoryOverlay::MemoryOverlay(Endian backing, Endian real, size_t width) + : width(width) + , m_backing({ endianTag(backing), 'u', static_cast('0' + width) }) + , m_real({ endianTag(real), 'u', static_cast('0' + width) }) { +} + +MemoryOverlay::MemoryOverlay(char backing, char real, size_t width) + : width(width) + , m_backing({ backing, 'u', static_cast('0' + width) }) + , m_real({ real, 'u', static_cast('0' + width) }) { +} + +void* MemoryOverlay::parse(const void* in, size_t offset, void* out, size_t size) const { + size_t offsetEdge = offset & (width - 1); + uintptr_t base = reinterpret_cast(in); + base += offset & ~(width - 1); + size += offsetEdge; + uintptr_t outBase = reinterpret_cast(out); + for (size_t i = 0; i < size; i += width) { + int64_t val = m_backing.decode(reinterpret_cast(base + i)); + m_real.encode(reinterpret_cast(outBase + i), val); + } + return reinterpret_cast(outBase + offsetEdge); +} + +void MemoryOverlay::unparse(void* out, size_t offset, const void* in, size_t size) const { + size_t offsetEdge = offset & (width - 1); + uintptr_t base = reinterpret_cast(out); + base += offset & ~(width - 1); + size += offsetEdge; + uintptr_t inBase = reinterpret_cast(in); + for (size_t i = 0; i < size; i += width) { + int64_t val = m_real.decode(reinterpret_cast(inBase + i)); + m_backing.encode(reinterpret_cast(base + i), val); + } +} + +Variant::Variant(int64_t i) + : m_type(Type::INT) + , m_vi(i) { +} + +Variant::Variant(double d) + : m_type(Type::FLOAT) + , m_vf(d) { +} + +Variant::Variant(bool b) + : m_type(Type::BOOL) + , m_vb(b) { +} + +Variant::operator int64_t() const { + return cast(); +} + +Variant::operator int() const { + return cast(); +} + +Variant::operator float() const { + return cast(); +} + +Variant::operator double() const { + return cast(); +} + +Variant::operator bool() const { + return cast(); +} + +void Variant::clear() { + m_type = Type::VOID; +} + +Variant& Variant::operator=(int64_t v) { + m_type = Type::INT; + m_vi = v; + return *this; +} + +Variant& Variant::operator=(double v) { + m_type = Type::FLOAT; + m_vf = v; + return *this; +} + +Variant& Variant::operator=(bool v) { + m_type = Type::BOOL; + m_vb = v; + return *this; +} + +Datum::Datum(void* base, const DataType& type) + : m_base(base) + , m_type(type) { +} + +Datum::Datum(void* base, size_t offset, const DataType& type, const MemoryOverlay& overlay) + : m_base(base) + , m_offset(offset) + , m_type(type) + , m_overlay(overlay) { +} + +Datum::Datum(void* base, const Variable& var, const MemoryOverlay& overlay) + : m_base(base) + , m_offset(var.address) + , m_type(var.type) + , m_mask(var.mask) + , m_overlay(overlay) { +} + +Datum::Datum(Variant* variant) + : m_type("=i8") + , m_variant(variant) { +} + +Datum& Datum::operator=(int64_t value) { + if (m_base) { + if (m_overlay.width > 1 || m_offset) { + uint8_t fakeBase[16]{}; + m_type.encode(m_overlay.parse(m_base, m_offset, reinterpret_cast(fakeBase), m_type.width), value); + m_overlay.unparse(m_base, m_offset, reinterpret_cast(fakeBase), m_type.width); + } else { + m_type.encode(m_base, value); + } + } else if (m_variant) { + *m_variant = value; + } + return *this; +} + +Datum::operator int64_t() const { + if (!m_base) { + if (m_variant) { + return *m_variant; + } + return 0; + } + int64_t value; + if (m_overlay.width > 1 || m_offset) { + uint8_t fakeBase[16]{}; + value = m_type.decode(m_overlay.parse(m_base, m_offset, reinterpret_cast(fakeBase), m_type.width)); + } else { + value = m_type.decode(m_base); + } + return value & m_mask; +} + +Datum::operator Variant() const { + if (m_variant) { + return *m_variant; + } + return static_cast(*this); +} + +DynamicMemoryView::DynamicMemoryView(void* buffer, size_t bytes, const DataType& dtype, const MemoryOverlay& overlay) + : dtype(dtype) + , overlay(overlay) { + m_mem.open(buffer, bytes); +} + +Datum DynamicMemoryView::operator[](size_t offset) { + return dtype(m_mem.offset(0), offset, overlay); +} + +int64_t DynamicMemoryView::operator[](size_t offset) const { + if (overlay.width > 1) { + uint8_t fakeBase[16]{}; + return dtype.decode(overlay.parse(m_mem.offset(0), offset, reinterpret_cast(fakeBase), dtype.width)); + } + return dtype.decode(m_mem.offset(offset)); +} + +const DataType AddressSpace::s_type{ "|u1" }; + +void AddressSpace::addBlock(size_t offset, size_t size, void* data) { + if (data) { + m_blocks[offset].open(data, size); + } else { + m_blocks[offset].open(size); + } +} + +void AddressSpace::addBlock(size_t offset, size_t size, const void* data) { + if (data) { + m_blocks[offset].clone(data, size); + } else { + m_blocks[offset].open(size); + } +} + +void AddressSpace::addBlock(size_t offset, const MemoryView<>& base) { + m_blocks[offset].clone(base); +} + +void AddressSpace::updateBlock(size_t offset, void* data) { + m_blocks[offset].open(data, m_blocks[offset].size()); +} + +void AddressSpace::updateBlock(size_t offset, const void* data) { + m_blocks[offset].clone(data, m_blocks[offset].size()); +} + +void AddressSpace::updateBlock(size_t offset, const MemoryView<>& base) { + m_blocks[offset].clone(base); +} + +bool AddressSpace::hasBlock(size_t offset) const { + for (const auto& block : m_blocks) { + if (offset < block.first) { + continue; + } + if (offset < block.first + block.second.size()) { + return true; + } + } + return false; +} + +const MemoryView<>& AddressSpace::block(size_t offset) const { + for (const auto& block : m_blocks) { + if (offset < block.first) { + continue; + } + if (offset < block.first + block.second.size()) { + return block.second; + } + } + throw std::out_of_range("No known mapping 1"); +} + +MemoryView<>& AddressSpace::block(size_t offset) { + for (auto& block : m_blocks) { + if (offset < block.first) { + continue; + } + if (offset < block.first + block.second.size()) { + return block.second; + } + } + throw std::out_of_range("No known mapping 2"); +} + +bool AddressSpace::ok() const { + return m_blocks.size() > 0; +} + +void AddressSpace::reset() { + m_blocks.clear(); +} + +void AddressSpace::clone(const AddressSpace& as) { + m_blocks.clear(); + m_overlay = make_unique(*as.m_overlay); + for (auto& kv : as.m_blocks) { + m_blocks[kv.first].clone(kv.second); + } +} + +void AddressSpace::clone() { + for (auto& kv : m_blocks) { + kv.second.clone(); + } +} + +void AddressSpace::setOverlay(const MemoryOverlay& overlay) { + m_overlay = make_unique(overlay); +} + +Datum AddressSpace::operator[](size_t offset) { + for (auto& kv : m_blocks) { + if (offset < kv.first) { + throw std::out_of_range("No known mapping 3"); + } + if (offset - kv.first >= kv.second.size()) { + continue; + } + return Datum(kv.second.offset(0), offset - kv.first, s_type, *m_overlay); + } + throw std::out_of_range("No known mapping 4"); +} + +Datum AddressSpace::operator[](const Variable& var) { + for (auto& kv : m_blocks) { + if (var.address < kv.first) { + throw std::out_of_range("No known mapping 5"); + } + if (var.address - kv.first >= kv.second.size()) { + continue; + } + return Datum(kv.second.offset(0), Variable{ var.type, var.address - kv.first, var.mask }, *m_overlay); + } + throw std::out_of_range("No known mapping 6"); +} + +uint8_t AddressSpace::operator[](size_t offset) const { + for (const auto& kv : m_blocks) { + if (offset < kv.first) { + throw std::out_of_range("No known mapping 7"); + } + if (offset - kv.first >= kv.second.size()) { + continue; + } + uint8_t fakeBase[16]{}; + return s_type.decode(m_overlay->parse(kv.second.offset(0), offset - kv.first, reinterpret_cast(fakeBase), s_type.width)); + } + throw std::out_of_range("No known mapping 8"); +} + +int64_t AddressSpace::operator[](const Variable& var) const { + for (const auto& kv : m_blocks) { + if (var.address < kv.first) { + throw std::out_of_range("No known mapping 9"); + } + if (var.address - kv.first >= kv.second.size()) { + continue; + } + int64_t value; + if (m_overlay->width > 1) { + uint8_t fakeBase[16]; + value = var.type.decode(m_overlay->parse(kv.second.offset(0), var.address - kv.first, reinterpret_cast(fakeBase), var.type.width)); + } else { + value = var.type.decode(kv.second.offset(var.address - kv.first)); + } + value &= var.mask; + return value; + } + throw std::out_of_range("No known mapping 10"); +} + +AddressSpace& AddressSpace::operator=(AddressSpace&& as) { + m_blocks.clear(); + m_overlay = move(as.m_overlay); + for (auto& kv : as.m_blocks) { + m_blocks[kv.first] = move(as.m_blocks[kv.first]); + } + as.m_blocks.clear(); + return *this; +} + +int64_t Retro::toBcd(int64_t value) { + int64_t out = 0; + int shift = 0; + while (value) { + out |= (value % 10) << (shift * 4); + ++shift; + value /= 10; + } + return out; +} + +int64_t Retro::toLNBcd(int64_t value) { + int64_t out = 0; + int shift = 0; + while (value) { + out |= (value % 10) << (shift * 8); + ++shift; + value /= 10; + } + return out; +} + +bool Retro::isBcd(uint64_t value) { + uint64_t halfdigits = (value >> 1) & 0x7777777777777777; + return !((halfdigits + 0x3333333333333333) & 0x8888888888888888); +} diff --git a/deps/game_ai_lib/utils/memory.h b/deps/game_ai_lib/utils/memory.h new file mode 100644 index 0000000000..be2c8b3f6b --- /dev/null +++ b/deps/game_ai_lib/utils/memory.h @@ -0,0 +1,474 @@ +// Adapted from OpenAI's retro source code: +// https://github.com/openai/retro + +#pragma once + +//#include "gtest/gtest.h" + +#include +#include +#include +#include +#include + +#include +#ifndef _WIN32 +#include +#include +#else +#include +#include "unistd.h" +#endif + + + +#ifdef VOID +#undef VOID +#endif + +namespace Retro { + +template +class MemoryView { +public: + MemoryView() {} + MemoryView(const MemoryView&) = delete; + ~MemoryView(); + + bool open(const std::string& file, size_t bytes = 0); + void open(void* buffer, size_t bytes); + void open(size_t bytes); + void open(std::initializer_list); + void close(); + + bool ok() const; + void clone(const void* buffer, size_t bytes); + void clone(const MemoryView&); + void clone(); + + T& operator[](size_t); + const T& operator[](size_t) const; + MemoryView& operator=(MemoryView&&); + + void* offset(size_t); + const void* offset(size_t) const; + + size_t size() const; + +private: + T* m_buffer = nullptr; + int m_backingFd = -1; + bool m_managed = false; + size_t m_size = 0; +#ifdef _WIN32 + HANDLE m_mapView; +#endif +}; + +template +MemoryView::~MemoryView() { + close(); +} + +template +bool MemoryView::open(const std::string& file, size_t bytes) { + if (ok()) { + close(); + } + int flags = O_RDWR; + if (bytes) { + flags |= O_CREAT; + } + m_backingFd = ::open(file.c_str(), flags, 0600); + if (m_backingFd < 0) { + return false; + } + if (bytes) { + ftruncate(m_backingFd, bytes); + m_size = bytes; + } else { + m_size = lseek(m_backingFd, 0, SEEK_END); + } + m_managed = true; +#ifdef _WIN32 + m_mapView = CreateFileMapping(reinterpret_cast(_get_osfhandle(m_backingFd)), 0, PAGE_READWRITE, 0, m_size, 0); + m_buffer = reinterpret_cast(static_cast(MapViewOfFile(m_mapView, FILE_MAP_WRITE, 0, 0, m_size))); +#else + m_buffer = reinterpret_cast(static_cast(mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_backingFd, 0))); +#endif + if (m_buffer == reinterpret_cast(-1)) { + m_buffer = nullptr; + m_managed = false; + ::close(m_backingFd); + return false; + } + return true; +} + +template +void MemoryView::open(void* buffer, size_t bytes) { + if (ok()) { + close(); + } + m_backingFd = -1; + m_size = bytes; + m_managed = false; + m_buffer = static_cast(buffer); +} + +template +void MemoryView::open(size_t bytes) { + if (ok()) { + close(); + } + m_backingFd = -1; + m_size = bytes; + m_managed = true; +#ifdef _WIN32 + m_buffer = static_cast(VirtualAlloc(nullptr, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); +#else + m_buffer = static_cast(mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0)); +#endif +} + +template +void MemoryView::open(std::initializer_list list) { + open(list.size()); + std::copy(list.begin(), list.end(), m_buffer); +} + +template +void MemoryView::close() { + if (!ok()) { + return; + } + if (m_managed) { + if (m_buffer) { +#ifdef _WIN32 + if (m_backingFd >= 0) { + UnmapViewOfFile(m_buffer); + CloseHandle(m_mapView); + } else { + VirtualFree(m_buffer, 0, MEM_RELEASE); + } +#else + munmap(m_buffer, m_size); +#endif + } + if (m_backingFd >= 0) { + ::close(m_backingFd); + m_backingFd = -1; + } + } + m_buffer = nullptr; + m_size = 0; + m_managed = false; +} + +template +bool MemoryView::ok() const { + return m_buffer && m_size; +} + +template +void MemoryView::clone() { + if (!ok() || m_managed) { + return; + } + + clone(static_cast(m_buffer), m_size); +} + +template +void MemoryView::clone(const void* buffer, size_t bytes) { + if (m_managed && bytes == m_size) { + memmove(m_buffer, buffer, bytes); + return; + } + if (static_cast(m_buffer) != buffer || !m_managed) { + close(); + } + +#ifdef _WIN32 + T* newBuffer = static_cast(VirtualAlloc(nullptr, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); +#else + T* newBuffer = static_cast(mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0)); +#endif + memcpy(newBuffer, buffer, bytes); + m_buffer = newBuffer; + m_size = bytes; + m_managed = true; +} + +template +void MemoryView::clone(const MemoryView& other) { + clone(static_cast(other.m_buffer), other.m_size); +} + +template +T& MemoryView::operator[](size_t index) { + return m_buffer[index]; +} + +template +const T& MemoryView::operator[](size_t index) const { + return m_buffer[index]; +} + +template +MemoryView& MemoryView::operator=(MemoryView&& other) { + close(); + m_buffer = other.m_buffer; + m_backingFd = other.m_backingFd; + m_managed = other.m_managed; + m_size = other.m_size; + other.m_managed = false; + return *this; +} + +template +void* MemoryView::offset(size_t index) { + return reinterpret_cast(&m_buffer[index]); +} + +template +const void* MemoryView::offset(size_t index) const { + return reinterpret_cast(&m_buffer[index]); +} + +template +size_t MemoryView::size() const { + return m_size; +} + +enum class Endian : char { + BIG = 0b01, + LITTLE = 0b10, + NATIVE = 0b11, + MIXED_BL = 0b1001, + MIXED_LB = 0b0110, + MIXED_BN = 0b1101, + MIXED_LN = 0b1110, +#if defined(__LITTLE_ENDIAN__) || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + REAL_NATIVE = LITTLE, + REAL_MIXED_BN = MIXED_BL, + REAL_MIXED_LN = LITTLE, +#else + REAL_NATIVE = BIG, + REAL_MIXED_BN = BIG, + REAL_MIXED_LN = MIXED_LN, +#endif + UNDEF = 0 +}; + +Endian reduce(Endian); +bool reduceCompare(Endian, Endian); + +enum class Repr : char { + SIGNED = 'i', + UNSIGNED = 'u', + BCD = 'd', + LN_BCD = 'n' +}; + +class Datum; +class MemoryOverlay; +class DataType { +public: + DataType(const char*); + DataType(const std::string&); + DataType(const DataType&) = default; + + Datum operator()(void*) const; + Datum operator()(void*, size_t offset, const MemoryOverlay&) const; + bool operator==(const DataType&) const; + bool operator!=(const DataType&) const; + + void encode(void* buffer, int64_t value) const; + int64_t decode(const void* buffer) const; + + const size_t width; + const Endian endian; + const Repr repr; + + const char type[5]; + +private: +#if 0 + FRIEND_TEST(DataTypeShift, 1); + FRIEND_TEST(DataTypeShift, 2); + FRIEND_TEST(DataTypeShift, 3); + FRIEND_TEST(DataTypeShift, 4); + FRIEND_TEST(DataTypeShift, 5); + FRIEND_TEST(DataTypeShift, 6); + FRIEND_TEST(DataTypeShift, 7); + FRIEND_TEST(DataTypeShift, 8); +#endif + + const uint8_t maskLo; + const uint8_t maskHi; + const unsigned cvt; + int64_t shift[8]{}; +}; + +struct Variable { + Variable(const DataType&, size_t address, uint64_t mask = UINT64_MAX); + Variable(const Variable&) = default; + bool operator==(const Variable&) const; + + const DataType type; + const size_t address; + const uint64_t mask = UINT64_MAX; +}; + +class MemoryOverlay { +public: + MemoryOverlay(Endian backing = Endian::NATIVE, Endian real = Endian::NATIVE, size_t width = 1); + MemoryOverlay(char backing, char real, size_t width = 1); + + void* parse(const void* in, size_t offset, void* out, size_t size) const; + void unparse(void* out, size_t offset, const void* in, size_t size) const; + + const size_t width; + +private: + DataType m_backing; + DataType m_real; +}; + +class Variant { +public: + enum class Type { + BOOL, + INT, + FLOAT, + VOID + }; + + Variant() {} + Variant(int64_t); + Variant(double); + Variant(bool); + + template + T cast() const { + switch (m_type) { + case Type::BOOL: + return m_vb; + case Type::INT: + return m_vi; + case Type::FLOAT: + return m_vf; + case Type::VOID: + default: + return T(); + } + } + + operator int() const; + operator int64_t() const; + operator float() const; + operator double() const; + operator bool() const; + + void clear(); + Variant& operator=(int64_t); + Variant& operator=(double); + Variant& operator=(bool); + + Type type() { return m_type; } + +private: + Type m_type = Type::VOID; + union { + bool m_vb; + int64_t m_vi; + double m_vf; + }; +}; + +class Datum { +public: + Datum() {} + Datum(void*, const DataType&); + Datum(void* base, const Variable&, const MemoryOverlay& overlay = {}); + Datum(void* base, size_t offset, const DataType&, const MemoryOverlay& overlay = {}); + Datum(Variant*); + + Datum& operator=(int64_t); + operator int64_t() const; + operator Variant() const; + bool operator==(int64_t); + +private: + void* const m_base = nullptr; + const size_t m_offset = 0; + const DataType m_type{ "|u1" }; + const uint64_t m_mask = UINT64_MAX; + const MemoryOverlay m_overlay{}; + Variant* m_variant = nullptr; +}; + +class DynamicMemoryView { +public: + DynamicMemoryView(void* buffer, size_t bytes, const DataType&, const MemoryOverlay& = {}); + + Datum operator[](size_t); + int64_t operator[](size_t) const; + + const DataType dtype; + const MemoryOverlay overlay; + +private: + MemoryView<> m_mem; +}; + +class AddressSpace { +public: + void addBlock(size_t offset, size_t size, void* data = nullptr); + void addBlock(size_t offset, size_t size, const void* data); + void addBlock(size_t offset, const MemoryView<>& base); + void updateBlock(size_t offset, void* data); + void updateBlock(size_t offset, const void* data); + void updateBlock(size_t offset, const MemoryView<>& base); + + bool hasBlock(size_t offset) const; + const MemoryView<>& block(size_t offset) const; + MemoryView<>& block(size_t offset); + + const std::map>& blocks() const { return m_blocks; } + std::map>& blocks() { return m_blocks; } + + bool ok() const; + void reset(); + void clone(const AddressSpace&); + void clone(); + + void setOverlay(const MemoryOverlay& overlay); + const MemoryOverlay& overlay() const { return *m_overlay; }; + + Datum operator[](size_t); + Datum operator[](const Variable&); + uint8_t operator[](size_t) const; + int64_t operator[](const Variable&) const; + + AddressSpace& operator=(AddressSpace&&); + +private: + static const DataType s_type; + ; + std::map> m_blocks; + std::unique_ptr m_overlay = std::make_unique(); +}; + +int64_t toBcd(int64_t); +int64_t toLNBcd(int64_t); +bool isBcd(uint64_t); +} + +namespace std { +template<> +struct hash { + size_t operator()(const Retro::DataType&) const; +}; +} diff --git a/deps/game_ai_lib/utils/unistd.h b/deps/game_ai_lib/utils/unistd.h new file mode 100644 index 0000000000..531e0e5221 --- /dev/null +++ b/deps/game_ai_lib/utils/unistd.h @@ -0,0 +1,59 @@ +#ifndef _UNISTD_H +#define _UNISTD_H 1 + +/* This file intended to serve as a drop-in replacement for + * unistd.h on Windows. + * Please add functionality as neeeded. + * Original file from: http://stackoverflow.com/a/826027 + */ + +#include +#include +//#include /* getopt at: https://gist.github.com/bikerm16/1b75e2dd20d839dcea58 */ +#include /* for getpid() and the exec..() family */ +#include /* for _getcwd() and _chdir() */ + +#define srandom srand +#define random rand + +/* Values for the second argument to access. + These may be OR'd together. */ +#define R_OK 4 /* Test for read permission. */ +#define W_OK 2 /* Test for write permission. */ +#define X_OK R_OK /* execute permission - unsupported in Windows, + use R_OK instead. */ +#define F_OK 0 /* Test for existence. */ + +#define access _access +#define dup2 _dup2 +#define execve _execve +#define ftruncate _chsize +#define unlink _unlink +#define fileno _fileno +#define getcwd _getcwd +#define chdir _chdir +#define isatty _isatty +#define lseek _lseek +/* read, write, and close are NOT being #defined here, + * because while there are file handle specific versions for Windows, + * they probably don't work for sockets. + * You need to look at your app and consider whether + * to call e.g. closesocket(). + */ + +#define ssize_t int + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +/* should be in some equivalent to */ +//typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#endif /* unistd.h */ \ No newline at end of file diff --git a/deps/game_ai_lib/utils/utils.cpp b/deps/game_ai_lib/utils/utils.cpp new file mode 100644 index 0000000000..b9e5fe1ed8 --- /dev/null +++ b/deps/game_ai_lib/utils/utils.cpp @@ -0,0 +1,91 @@ +// Adapted from OpenAI's retro source code: +// https://github.com/openai/retro +#include "utils.h" + +#include +#include +#include + +using namespace std; + +namespace Retro { + +int64_t calculate(Operation op, int64_t reference, int64_t value) { + switch (op) { + case Operation::NOOP: + return value; + case Operation::EQUAL: + return value == reference; + case Operation::NEGATIVE_EQUAL: + return value == -reference; + case Operation::NOT_EQUAL: + return value != reference; + case Operation::LESS_THAN: + return value < reference; + case Operation::GREATER_THAN: + return value > reference; + case Operation::LESS_OR_EQUAL: + return value <= reference; + case Operation::GREATER_OR_EQUAL: + return value >= reference; + case Operation::NONZERO: + return value != 0; + case Operation::ZERO: + return value == 0; + case Operation::POSITIVE: + return value > 0; + case Operation::NEGATIVE: + return value < 0; + case Operation::SIGN: + return value < 0 ? -1 : value > 0 ? 1 : 0; + } + return 0; +} + +string drillUp(const vector& targets, const string& fail, const string& hint) +{ + #if 0 + char rpath[PATH_MAX]; + string path("."); +#ifndef _WIN32 + if (!hint.empty() && realpath(hint.c_str(), rpath)) { + path = rpath; + } +#else + if (!hint.empty()) { + path = hint; + } +#endif + while (!path.empty() && path != "/") { + for (const auto& target : targets) { + struct stat statbuf; + string testPath = path + "/" + target; + if (stat(testPath.c_str(), &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { + return testPath; + } + } +#ifndef _WIN32 + string new_path = path.substr(0, path.find_last_of('/')); +#else + string new_path = path.substr(0, path.find_last_of("/\\")); +#endif + if (new_path == path) { + break; + } + path = new_path; +#ifndef _WIN32 + if (!path.empty() && realpath(path.c_str(), rpath)) { + path = rpath; + } +#endif + } + if (!fail.empty()) { + return fail + "/" + targets[0]; + } + return {}; + +#else +return {}; +#endif +} +} diff --git a/deps/game_ai_lib/utils/utils.h b/deps/game_ai_lib/utils/utils.h new file mode 100644 index 0000000000..f47672e62b --- /dev/null +++ b/deps/game_ai_lib/utils/utils.h @@ -0,0 +1,29 @@ +// Adapted from OpenAI's retro source code: +// https://github.com/openai/retro +#pragma once + +#include +#include + +namespace Retro { + +enum class Operation { + NOOP, + EQUAL, + NEGATIVE_EQUAL, + NOT_EQUAL, + LESS_THAN, + GREATER_THAN, + LESS_OR_EQUAL, + GREATER_OR_EQUAL, + NONZERO, + ZERO, + POSITIVE, + NEGATIVE, + SIGN, +}; + +int64_t calculate(Operation op, int64_t reference, int64_t value); + +std::string drillUp(const std::vector& targets, const std::string& fail = {}, const std::string& hint = "."); +} diff --git a/deps/mbedtls/mbedtls/config.h b/deps/mbedtls/mbedtls/config.h index fa1a83897f..8c566e2a81 100644 --- a/deps/mbedtls/mbedtls/config.h +++ b/deps/mbedtls/mbedtls/config.h @@ -28,6 +28,14 @@ #ifndef MBEDTLS_CONFIG_H #define MBEDTLS_CONFIG_H +#ifdef _3DS +#define unix +#define MBEDTLS_NO_IPV6 +#ifndef _SOCKLEN_T_DECLARED +#define _SOCKLEN_T_DECLARED +#endif +#endif + #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) #define _CRT_SECURE_NO_DEPRECATE 1 #endif @@ -2020,7 +2028,9 @@ * * This module is used by the HAVEGE random number generator. */ +#ifndef _3DS #define MBEDTLS_TIMING_C +#endif /** * \def MBEDTLS_VERSION_C diff --git a/deps/mbedtls/net_sockets.c b/deps/mbedtls/net_sockets.c index fc1aaa6ef4..a05b0c26df 100644 --- a/deps/mbedtls/net_sockets.c +++ b/deps/mbedtls/net_sockets.c @@ -400,6 +400,7 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx, memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len ); } +#ifndef MBEDTLS_NO_IPV6 else { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; @@ -410,6 +411,7 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx, memcpy( client_ip, &addr6->sin6_addr.s6_addr, *ip_len); } +#endif } return( 0 ); diff --git a/deps/rcheevos/src/rc_compat.c b/deps/rcheevos/src/rc_compat.c index 6a8a5de57a..80044d37de 100644 --- a/deps/rcheevos/src/rc_compat.c +++ b/deps/rcheevos/src/rc_compat.c @@ -120,22 +120,47 @@ void rc_mutex_unlock(rc_mutex_t* mutex) void rc_mutex_init(rc_mutex_t* mutex) { - LWP_MutexInit(mutex, NULL); + /* LWP_MutexInit has the handle passed by reference */ + /* Other LWP_Mutex* calls have the handle passed by value */ + LWP_MutexInit(&mutex->handle, 1); } void rc_mutex_destroy(rc_mutex_t* mutex) { - LWP_MutexDestroy(mutex); + LWP_MutexDestroy(mutex->handle); } void rc_mutex_lock(rc_mutex_t* mutex) { - LWP_MutexLock(mutex); + LWP_MutexLock(mutex->handle); } void rc_mutex_unlock(rc_mutex_t* mutex) { - LWP_MutexUnlock(mutex); + LWP_MutexUnlock(mutex->handle); +} + +#elif defined(_3DS) + +void rc_mutex_init(rc_mutex_t* mutex) +{ + RecursiveLock_Init(mutex); +} + +void rc_mutex_destroy(rc_mutex_t* mutex) +{ + /* Nothing to do here */ + (void)mutex; +} + +void rc_mutex_lock(rc_mutex_t* mutex) +{ + RecursiveLock_Lock(mutex); +} + +void rc_mutex_unlock(rc_mutex_t* mutex) +{ + RecursiveLock_Unlock(mutex); } #else diff --git a/deps/rcheevos/src/rc_compat.h b/deps/rcheevos/src/rc_compat.h index 2ef9ae0c5b..614d1bc273 100644 --- a/deps/rcheevos/src/rc_compat.h +++ b/deps/rcheevos/src/rc_compat.h @@ -81,6 +81,14 @@ RC_BEGIN_C_DECLS typedef struct rc_mutex_t { void* handle; /* HANDLE is defined as "void*" */ } rc_mutex_t; + #elif defined(GEKKO) + #include + typedef struct rc_mutex_t { + mutex_t handle; + } rc_mutex_t; + #elif defined(_3DS) + #include <3ds/synchronization.h> + typedef RecursiveLock rc_mutex_t; #else #include typedef pthread_mutex_t rc_mutex_t; diff --git a/deps/rcheevos/src/rcheevos/runtime.c b/deps/rcheevos/src/rcheevos/runtime.c index 25e9885dcf..292b21b5d9 100644 --- a/deps/rcheevos/src/rcheevos/runtime.c +++ b/deps/rcheevos/src/rcheevos/runtime.c @@ -316,7 +316,7 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema rc_lboard_t* lboard; rc_parse_state_t parse; rc_runtime_lboard_t* runtime_lboard; - int size; + int32_t size; uint32_t i; if (memaddr == 0) @@ -834,7 +834,7 @@ void rc_runtime_invalidate_address(rc_runtime_t* self, uint32_t address) { } } -void rc_runtime_validate_addresses(rc_runtime_t* self, rc_runtime_event_handler_t event_handler, +void rc_runtime_validate_addresses(rc_runtime_t* self, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler) { rc_memref_t** last_memref = &self->memrefs; rc_memref_t* memref = self->memrefs; diff --git a/disk_control_interface.c b/disk_control_interface.c index 225f4c9755..a5f1541f86 100644 --- a/disk_control_interface.c +++ b/disk_control_interface.c @@ -243,9 +243,9 @@ unsigned disk_control_get_image_index( **/ void disk_control_get_image_label( disk_control_interface_t *disk_control, - unsigned index, char *label, size_t len) + unsigned index, char *s, size_t len) { - if (!label || len < 1) + if (!s || len < 1) return; if (!disk_control) @@ -254,13 +254,13 @@ void disk_control_get_image_label( if (!disk_control->cb.get_image_label) goto error; - if (!disk_control->cb.get_image_label(index, label, len)) + if (!disk_control->cb.get_image_label(index, s, len)) goto error; return; error: - label[0] = '\0'; + s[0] = '\0'; } /***********/ @@ -273,58 +273,55 @@ error: * Generates an appropriate log/notification message * for a disk index change event **/ -static void disk_control_get_index_set_msg( +static size_t disk_control_get_index_set_msg( disk_control_interface_t *disk_control, unsigned num_images, unsigned index, bool success, - unsigned *msg_duration, char *msg, size_t len) + unsigned *msg_duration, char *s, size_t len) { - bool has_label = false; - char image_label[128]; - - image_label[0] = '\0'; - - if (!disk_control || !msg_duration || !msg || len < 1) - return; - - /* Attempt to get image label */ - if (index < num_images) - { - disk_control_get_image_label( - disk_control, index, image_label, sizeof(image_label)); - has_label = !string_is_empty(image_label); - } - - /* Get message duration - * > Default is 60 - * > If a label is shown, then increase duration by 50% - * > For errors, duration is always 180 */ - *msg_duration = success ? - (has_label ? 90 : 60) : - 180; - + size_t _len = 0; + if (!disk_control || !msg_duration || !s || len < 1) + return 0; /* Check whether image was inserted or removed */ if (index < num_images) { - size_t _len = strlcpy(msg, + char image_label[128]; + bool has_label = false; + image_label[0] = '\0'; + disk_control_get_image_label( + disk_control, index, image_label, sizeof(image_label)); + + has_label = !string_is_empty(image_label); + + /* Get message duration + * > Default is 60 + * > If a label is shown, then increase duration by 50% + * > For errors, duration is always 180 */ + *msg_duration = success ? (has_label ? 90 : 60) : 180; + + _len = strlcpy(s, success ? msg_hash_to_str(MSG_SETTING_DISK_IN_TRAY) : msg_hash_to_str(MSG_FAILED_TO_SET_DISK), len); if (has_label) - snprintf( - msg + _len, len - _len, ": %u/%u - %s", + _len += snprintf( + s + _len, len - _len, ": %u/%u - %s", index + 1, num_images, image_label); else - snprintf( - msg + _len, len - _len, ": %u/%u", + _len += snprintf( + s + _len, len - _len, ": %u/%u", index + 1, num_images); } else - strlcpy( - msg, + { + *msg_duration = success ? 60 : 180; + _len += strlcpy( + s, success ? msg_hash_to_str(MSG_REMOVED_DISK_FROM_TRAY) : msg_hash_to_str(MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY), len); + } + return _len; } /** @@ -404,6 +401,7 @@ bool disk_control_set_index( disk_control_interface_t *disk_control, unsigned index, bool verbosity) { + size_t _len; bool error = false; unsigned num_images = 0; unsigned msg_duration = 0; @@ -430,12 +428,12 @@ bool disk_control_set_index( error = !disk_control->cb.set_image_index(index); /* Get log/notification message */ - disk_control_get_index_set_msg( + _len = disk_control_get_index_set_msg( disk_control, num_images, index, !error, &msg_duration, msg, sizeof(msg)); /* Output log/notification message */ - if (!string_is_empty(msg)) + if (_len > 0) { if (error) RARCH_ERR("[Disc]: %s\n", msg); @@ -444,7 +442,7 @@ bool disk_control_set_index( /* Errors should always be displayed */ if (verbosity || error) - runloop_msg_queue_push(msg, strlen(msg), 1, msg_duration, true, NULL, + runloop_msg_queue_push(msg, _len, 1, msg_duration, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } @@ -625,7 +623,7 @@ bool disk_control_append_image( goto error; /* Display log */ - _len = strlcpy(msg, msg_hash_to_str(MSG_APPENDED_DISK), sizeof(msg)); + _len = strlcpy(msg, msg_hash_to_str(MSG_APPENDED_DISK), sizeof(msg) - 3); msg[ _len] = ':'; msg[++_len] = ' '; msg[++_len] = '\0'; @@ -655,7 +653,7 @@ error: disk_control_set_eject_state(disk_control, false, false); _len = strlcpy(msg, - msg_hash_to_str(MSG_FAILED_TO_APPEND_DISK), sizeof(msg)); + msg_hash_to_str(MSG_FAILED_TO_APPEND_DISK), sizeof(msg) - 3); msg[ _len] = ':'; msg[++_len] = ' '; msg[++_len] = '\0'; @@ -799,7 +797,10 @@ bool disk_control_verify_initial_index( /* If current disk is incorrect, notify user */ if (!success && enabled) { - const char *_msg = msg_hash_to_str(MSG_FAILED_TO_SET_INITIAL_DISK); + char _msg[128]; + size_t _len = strlcpy(_msg, + msg_hash_to_str(MSG_FAILED_TO_SET_INITIAL_DISK), sizeof(_msg)); + RARCH_ERR( "[Disc]: Failed to set initial disc index:\n> Expected" " [%u] %s\n> Detected [%u] %s\n", @@ -810,7 +811,7 @@ bool disk_control_verify_initial_index( /* Ignore 'verbosity' setting - errors should * always be displayed */ - runloop_msg_queue_push(_msg, strlen(_msg), 0, 60, true, NULL, + runloop_msg_queue_push(_msg, _len, 0, 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); /* Since a failure here typically means that the @@ -835,12 +836,13 @@ bool disk_control_verify_initial_index( * is available */ if (disk_control->initial_num_images > 1) { + size_t _len; unsigned msg_duration = 0; char msg[128]; msg[0] = '\0'; - disk_control_get_index_set_msg( + _len = disk_control_get_index_set_msg( disk_control, disk_control->initial_num_images, image_index, true, &msg_duration, msg, sizeof(msg)); @@ -852,7 +854,7 @@ bool disk_control_verify_initial_index( * we do not want to 'overwrite' them */ if (verbosity) runloop_msg_queue_push( - msg, strlen(msg), 0, msg_duration, false, NULL, + msg, _len, 0, msg_duration, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); #ifdef HAVE_CHEEVOS diff --git a/disk_control_interface.h b/disk_control_interface.h index 1efb364d65..b9bd9d0afa 100644 --- a/disk_control_interface.h +++ b/disk_control_interface.h @@ -100,7 +100,7 @@ bool disk_control_append_enabled( * * Leaf function. * - * @return true if core supports image labels + * @return true if core supports image labels * - get_image_label **/ bool disk_control_image_label_enabled( @@ -155,7 +155,7 @@ unsigned disk_control_get_image_index( **/ void disk_control_get_image_label( disk_control_interface_t *disk_control, - unsigned index, char *label, size_t len); + unsigned index, char *s, size_t len); /***********/ /* Setters */ diff --git a/disk_index_file.c b/disk_index_file.c index 9f49606ca8..67b359a34e 100644 --- a/disk_index_file.c +++ b/disk_index_file.c @@ -43,7 +43,7 @@ typedef struct char *image_path; } DCifJSONContext; -static bool DCifJSONObjectMemberHandler(void* context, const char *pValue, size_t length) +static bool DCifJSONObjectMemberHandler(void* context, const char *pValue, size_t len) { DCifJSONContext *pCtx = (DCifJSONContext*)context; @@ -51,7 +51,7 @@ static bool DCifJSONObjectMemberHandler(void* context, const char *pValue, size_ if (pCtx->current_entry_str_val) return false; - if (length) + if (len) { if (string_is_equal(pValue, "image_index")) pCtx->current_entry_uint_val = &pCtx->image_index; @@ -63,11 +63,11 @@ static bool DCifJSONObjectMemberHandler(void* context, const char *pValue, size_ return true; } -static bool DCifJSONNumberHandler(void* context, const char *pValue, size_t length) +static bool DCifJSONNumberHandler(void* context, const char *pValue, size_t len) { DCifJSONContext *pCtx = (DCifJSONContext*)context; - if (pCtx->current_entry_uint_val && length && !string_is_empty(pValue)) + if (pCtx->current_entry_uint_val && len && !string_is_empty(pValue)) *pCtx->current_entry_uint_val = string_to_unsigned(pValue); /* ignore unknown members */ @@ -76,14 +76,13 @@ static bool DCifJSONNumberHandler(void* context, const char *pValue, size_t leng return true; } -static bool DCifJSONStringHandler(void* context, const char *pValue, size_t length) +static bool DCifJSONStringHandler(void* context, const char *pValue, size_t len) { DCifJSONContext *pCtx = (DCifJSONContext*)context; - if (pCtx->current_entry_str_val && length && !string_is_empty(pValue)) + if (pCtx->current_entry_str_val && len && !string_is_empty(pValue)) { - if (*pCtx->current_entry_str_val) - free(*pCtx->current_entry_str_val); + free(*pCtx->current_entry_str_val); *pCtx->current_entry_str_val = strdup(pValue); } @@ -227,12 +226,9 @@ bool disk_index_file_init( /* > Get disk index file directory */ if (!string_is_empty(dir_savefile)) strlcpy(disk_index_file_dir, dir_savefile, sizeof(disk_index_file_dir)); - else - { - /* Use content directory */ - strlcpy(disk_index_file_dir, content_path, sizeof(disk_index_file_dir)); - path_basedir(disk_index_file_dir); - } + else /* Use content directory */ + fill_pathname_basedir(disk_index_file_dir, content_path, + sizeof(disk_index_file_dir)); /* > Create directory, if required */ if ( !path_is_directory(disk_index_file_dir) diff --git a/dist-scripts/dist-cores.sh b/dist-scripts/dist-cores.sh index 5c4c675e4c..1c08c451d9 100755 --- a/dist-scripts/dist-cores.sh +++ b/dist-scripts/dist-cores.sh @@ -61,6 +61,7 @@ mkdir -p ../pkg/${platform}/build/rom # Emscripten elif [ $PLATFORM = "emscripten" ] ; then platform=emscripten +# todo: change this to a EXT=bc if [ -z "$EMSCRIPTEN" ] ; then @@ -199,15 +200,10 @@ for f in `ls -v *_${platform}.${EXT}`; do echo Buildbot: building ${name} for ${platform} name=`echo "$f" | sed "s/\(_libretro_${platform}\|\).${EXT}$//"` - async=0 - pthread=${pthread:-0} lto=0 whole_archive= big_stack= - if [ $PLATFORM = "emscripten" ]; then - async=1 #emscripten needs async to sleep - fi if [ $name = "nxengine" ] ; then echo "Applying whole archive linking..." whole_archive="WHOLE_ARCHIVE_LINK=1" @@ -215,10 +211,33 @@ for f in `ls -v *_${platform}.${EXT}`; do echo "Applying big stack..." lto=0 big_stack="BIG_STACK=1" - elif [ $name = "mupen64plus" ] ; then - async=1 - elif [ $name = "dosbox" ] ; then - async=0 + fi + if [ $PLATFORM = "emscripten" ]; then + async=${ASYNC:-0} + have_threads=${HAVE_THREADS:-0} + proxy_to_pthread=${PROXY_TO_PTHREAD:-0} + gles3=${HAVE_OPENGLES3:-0} + stack_mem=4194304 + heap_mem=134217728 + if [ $name = "mupen64plus_next" ] ; then + gles3=1 + async=1 + #proxy_to_pthread=0 + stack_mem=134217728 + heap_mem=268435456 + elif [ $name = "parallel_n64" ] ; then + gles3=1 + async=1 + elif [ $name = "mednafen_psx" ] ; then + heap_mem=536870912 + elif [ $name = "mednafen_psx_hw" ] ; then + gles3=1 + heap_mem=536870912 + elif [ $name = "dosbox" ] ; then + async=1 + elif [ $name = "scummvm" ] ; then + async=1 + fi fi echo "-- Building core: $name --" if [ $PLATFORM = "unix" ]; then @@ -227,15 +246,22 @@ for f in `ls -v *_${platform}.${EXT}`; do cp -f "$f" ../libretro_${platform}.${EXT} fi echo NAME: $name - echo ASYNC: $async echo LTO: $lto + if [ $PLATFORM = "emscripten" ]; then + echo ASYNC: $async + echo HAVE_THREADS: $have_threads + echo PROXY_TO_PTHREAD: $proxy_to_pthread + echo GLES3: $gles3 + echo STACK_MEMORY: $stack_mem + echo HEAP_MEMORY: $heap_mem + fi # Do cleanup if this is a big stack core if [ "$big_stack" = "BIG_STACK=1" ] ; then if [ $MAKEFILE_GRIFFIN = "yes" ]; then make -C ../ -f Makefile.griffin platform=${platform} clean || exit 1 elif [ $PLATFORM = "emscripten" ]; then - make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 clean || exit 1 + make -C ../ -f Makefile.emscripten HAVE_THREADS=$have_threads ASYNC=$async LTO=$lto HAVE_OPENGLES3=$gles3 -j7 clean || exit 1 elif [ $PLATFORM = "unix" ]; then make -C ../ -f Makefile LINK=g++ LTO=$lto -j7 clean || exit 1 else @@ -247,8 +273,8 @@ for f in `ls -v *_${platform}.${EXT}`; do if [ $MAKEFILE_GRIFFIN = "yes" ]; then make -C ../ -f Makefile.griffin $OPTS platform=${platform} $whole_archive $big_stack -j3 || exit 1 elif [ $PLATFORM = "emscripten" ]; then - echo "BUILD COMMAND: make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 LIBRETRO=${name} TARGET=${name}_libretro.js" - make -C ../ -f Makefile.emscripten $OPTS PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 LIBRETRO=${name} TARGET=${name}_libretro.js || exit 1 + echo "BUILD COMMAND: make -C ../ -f Makefile.emscripten $OPTS LTO=$lto ASYNC=$async HAVE_THREADS=$have_threads PROXY_TO_PTHREAD=$proxy_to_pthread HAVE_OPENGLES3=$gles3 STACK_SIZE=$stack_mem INITIAL_HEAP=$heap_mem -j7 LIBRETRO=${name} TARGET=${name}_libretro.js" + make -C ../ -f Makefile.emscripten $OPTS LTO=$lto ASYNC=$async HAVE_THREADS=$have_threads PROXY_TO_PTHREAD=$proxy_to_pthread HAVE_OPENGLES3=$gles3 STACK_SIZE=$stack_mem INITIAL_HEAP=$heap_mem -j7 LIBRETRO=${name} TARGET=${name}_libretro.js || exit 1 elif [ $PLATFORM = "unix" ]; then make -C ../ -f Makefile LINK=g++ $whole_archive $big_stack -j3 || exit 1 elif [ $PLATFORM = "ctr" ]; then @@ -315,9 +341,12 @@ for f in `ls -v *_${platform}.${EXT}`; do mkdir -p ../pkg/emscripten/ mv -f ../${name}_libretro.js ../pkg/emscripten/${name}_libretro.js mv -f ../${name}_libretro.wasm ../pkg/emscripten/${name}_libretro.wasm - if [ $pthread != 0 ] ; then + if [ -f ../${name}_libretro.worker.js ] ; then mv -f ../${name}_libretro.worker.js ../pkg/emscripten/${name}_libretro.worker.js fi + if [ -f ../${name}_libretro.wasm.map ] ; then + mv -f ../${name}_libretro.wasm.map ../pkg/emscripten/${name}_libretro.wasm.map + fi fi # Do manual executable step @@ -364,7 +393,7 @@ for f in `ls -v *_${platform}.${EXT}`; do if [ $MAKEFILE_GRIFFIN = "yes" ]; then make -C ../ -f Makefile.griffin platform=${platform} clean || exit 1 elif [ $PLATFORM = "emscripten" ]; then - make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 clean || exit 1 + make -C ../ -f Makefile.emscripten HAVE_THREADS=$have_threads ASYNC=$async LTO=$lto -j7 clean || exit 1 elif [ $PLATFORM = "unix" ]; then make -C ../ -f Makefile LTO=$lto -j7 clean || exit 1 else diff --git a/docs/retroarch.6 b/docs/retroarch.6 index 7478040e17..d38a8ee565 100644 --- a/docs/retroarch.6 +++ b/docs/retroarch.6 @@ -1,6 +1,6 @@ .\" retroarch.6: -.TH "RETROARCH" "6" "November 1, 2011" "RETROARCH" "System Manager's Manual: retroarch" +.TH "RETROARCH" "6" "January 20, 2025" "RETROARCH" "System Manager's Manual: retroarch" .SH NAME @@ -239,3 +239,54 @@ Disables all kinds of content patching. .TP \fB-D, --detach\fR Detach from the current console. This is currently only relevant for Microsoft Windows. + +.SH ENVIRONMENT +\fBretroarch\fR honors the following environment variables: + +.TP +\fBLIBRETRO_DIRECTORY\fR +Specify the directory where RetroArch looks for core and info files, +overriding the value of the "libretro_directory" configuration file +option. + +.TP +\fBLIBRETRO_ASSETS_DIRECTORY\fR +Specify the directory where RetroArch looks for assets, overriding +the value of the "assets_directory" configuration file +option. + +.TP +\fBLIBRETRO_AUTOCONFIG_DIRECTORY\fR +Specify the directory where RetroArch looks for controller +auto-configuration files, overriding the value of the +"joypad_autoconfig_dir" configuration file option. + +.TP +\fBLIBRETRO_CHEATS_DIRECTORY\fR +Specify the directory where RetroArch looks for cheat files, +overriding the value of the "cheat_database_path" configuration file +option. + +.TP +\fBLIBRETRO_DATABASE_DIRECTORY\fR +Specify the directory where RetroArch looks for database files, +overriding the value of the "content_database_path" configuration file +option. + +.TP +\fBLIBRETRO_SYSTEM_DIRECTORY\fR +Specify the directory where RetroArch looks for system files, +overriding the value of the "system_directory" configuration file +option. + +.TP +\fBLIBRETRO_VIDEO_FILTER_DIRECTORY\fR +Specify the directory where RetroArch looks for video filters, +overriding the value of the "video_filter_dir" configuration file +option. + +.TP +\fBLIBRETRO_VIDEO_SHADER_DIRECTORY\fR +Specify the directory where RetroArch looks for video shaders, +overriding the value of the "video_shader_dir" configuration file +option. diff --git a/dynamic.h b/dynamic.h index 79ed70ab16..af4a0cdd15 100644 --- a/dynamic.h +++ b/dynamic.h @@ -66,7 +66,7 @@ struct retro_core_t void *(*retro_get_memory_data)(unsigned); size_t (*retro_get_memory_size)(unsigned); - unsigned poll_type; + enum poll_type poll_type; uint8_t flags; }; diff --git a/emscripten/library_errno_codes.js b/emscripten/library_errno_codes.js deleted file mode 100644 index 7ec23ac3b4..0000000000 --- a/emscripten/library_errno_codes.js +++ /dev/null @@ -1,15 +0,0 @@ -//"use strict"; - -// HACK: This is a dummy library that forces ERRNO_CODES to be used, so it's not optimized away. -// Needed for BrowserFS. - -var LibraryErrnoCodes = { - dummyErrnoCodes__deps: ['$ERRNO_CODES'], - dummyErrnoCodes: function() { - if (!ERRNO_CODES) { - console.error("ERRNO_CODES not imported!"); - } - } -}; - -mergeInto(LibraryManager.library, LibraryErrnoCodes); diff --git a/emscripten/library_platform_emscripten.js b/emscripten/library_platform_emscripten.js new file mode 100644 index 0000000000..3d015a5649 --- /dev/null +++ b/emscripten/library_platform_emscripten.js @@ -0,0 +1,85 @@ +//"use strict"; + +var LibraryPlatformEmscripten = { + $RPE: { + powerStateChange: function(e) { + _platform_emscripten_update_power_state(true, Number.isFinite(e.target.dischargingTime) ? e.target.dischargingTime : 0x7FFFFFFF, e.target.level, e.target.charging); + }, + + updateMemoryUsage: function() { + // unfortunately this will be innacurate in threaded (worker) builds + var used = BigInt(performance.memory.usedJSHeapSize || 0); + var limit = BigInt(performance.memory.jsHeapSizeLimit || 0); + // emscripten currently only supports passing 32 bit ints, so pack it + _platform_emscripten_update_memory_usage(Number(used & 0xFFFFFFFFn), Number(used >> 32n), Number(limit & 0xFFFFFFFFn), Number(limit >> 32n)); + setTimeout(RPE.updateMemoryUsage, 5000); + }, + command_queue: [], + command_reply_queue: [] + }, + + PlatformEmscriptenWatchCanvasSizeAndDpr__deps: ["platform_emscripten_update_canvas_dimensions"], + PlatformEmscriptenWatchCanvasSizeAndDpr: function(dpr) { + if (RPE.observer) { + RPE.observer.unobserve(Module.canvas); + RPE.observer.observe(Module.canvas); + return; + } + RPE.observer = new ResizeObserver(function(e) { + var width, height; + var entry = e.find(i => i.target == Module.canvas); + if (!entry) return; + if (entry.devicePixelContentBoxSize) { + width = entry.devicePixelContentBoxSize[0].inlineSize; + height = entry.devicePixelContentBoxSize[0].blockSize; + } else { + width = Math.round(entry.contentRect.width * window.devicePixelRatio); + height = Math.round(entry.contentRect.height * window.devicePixelRatio); + } + // doubles are too big to pass as an argument to exported functions + {{{ makeSetValue("dpr", "0", "window.devicePixelRatio", "double") }}}; + _platform_emscripten_update_canvas_dimensions(width, height, dpr); + }); + RPE.observer.observe(Module.canvas); + window.addEventListener("resize", function() { + RPE.observer.unobserve(Module.canvas); + RPE.observer.observe(Module.canvas); + }, false); + }, + + PlatformEmscriptenWatchWindowVisibility__deps: ["platform_emscripten_update_window_hidden"], + PlatformEmscriptenWatchWindowVisibility: function() { + document.addEventListener("visibilitychange", function() { + _platform_emscripten_update_window_hidden(document.visibilityState == "hidden"); + }, false); + }, + + PlatformEmscriptenPowerStateInit__deps: ["platform_emscripten_update_power_state"], + PlatformEmscriptenPowerStateInit: function() { + if (!navigator.getBattery) return; + navigator.getBattery().then(function(battery) { + battery.addEventListener("chargingchange", RPE.powerStateChange); + battery.addEventListener("levelchange", RPE.powerStateChange); + RPE.powerStateChange({target: battery}); + }); + }, + + PlatformEmscriptenMemoryUsageInit__deps: ["platform_emscripten_update_memory_usage"], + PlatformEmscriptenMemoryUsageInit: function() { + if (!performance.memory) return; + RPE.updateMemoryUsage(); + }, + + $EmscriptenSendCommand__deps: ["platform_emscripten_command_raise_flag"], + $EmscriptenSendCommand: function(str) { + RPE.command_queue.push(str); + _platform_emscripten_command_raise_flag(); + }, + + $EmscriptenReceiveCommandReply: function() { + return RPE.command_reply_queue.shift(); + } +}; + +autoAddDeps(LibraryPlatformEmscripten, '$RPE'); +mergeInto(LibraryManager.library, LibraryPlatformEmscripten); diff --git a/emscripten/library_rwebcam.js b/emscripten/library_rwebcam.js index 5c0bec5dc3..2aaef6e44d 100644 --- a/emscripten/library_rwebcam.js +++ b/emscripten/library_rwebcam.js @@ -17,18 +17,13 @@ var LibraryRWebCam = { RWebCamInit__deps: ['malloc'], RWebCamInit: function(caps1, caps2, width, height) { if (!navigator) return 0; - - navigator.getMedia = navigator.getUserMedia || - navigator.webkitGetUserMedia || - navigator.mozGetUserMedia || - navigator.msGetUserMedia; - - if (!navigator.getMedia) return 0; + if (!navigator.mediaDevices.getUserMedia) return 0; var c = ++RWC.counter; RWC.contexts[c] = []; RWC.contexts[c].videoElement = document.createElement("video"); + RWC.contexts[c].videoElement.classList.add("retroarchWebcamVideo"); if (width !== 0 && height !== 0) { RWC.contexts[c].videoElement.width = width; RWC.contexts[c].videoElement.height = height; @@ -37,11 +32,11 @@ var LibraryRWebCam = { RWC.contexts[c].glTex = caps1 & (1 << RWC.RETRO_CAMERA_BUFFER_OPENGL_TEXTURE); RWC.contexts[c].rawFb = caps1 & (1 << RWC.RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER); - navigator.getMedia({video: true, audio: false}, function(stream) { + navigator.mediaDevices.getUserMedia({video: true, audio: false}).then(function(stream) { RWC.contexts[c].videoElement.autoplay = true; - RWC.contexts[c].videoElement.src = URL.createObjectURL(stream); + RWC.contexts[c].videoElement.srcObject = stream; RWC.contexts[c].runMode = 2; - }, function (err) { + }).catch(function (err) { console.log("webcam request failed", err); RWC.runMode = 0; }); @@ -53,7 +48,6 @@ var LibraryRWebCam = { RWebCamFree: function(data) { RWC.contexts[data].videoElement.pause(); - URL.revokeObjectURL(RWC.contexts[data].videoElement.src); RWC.contexts[data].videoElement = null; RWC.contexts[data] = null; }, @@ -81,6 +75,7 @@ var LibraryRWebCam = { } if (RWC.contexts[data].rawFb) { RWC.contexts[data].rawFbCanvas = document.createElement("canvas"); + RWC.contexts[data].rawFbCanvas.classList.add("retroarchWebcamCanvas"); ret = 1; } diff --git a/emscripten/pre.js b/emscripten/pre.js index ae4d12534f..863d45b545 100644 --- a/emscripten/pre.js +++ b/emscripten/pre.js @@ -1,2 +1,6 @@ // To work around a bug in emscripten's polyfills for setImmediate in strict mode var setImmediate; + +// To work around a deadlock in firefox +// Use platform_emscripten_has_async_atomics() to determine actual availability +if (Atomics && !Atomics.waitAsync) Atomics.waitAsync = true; diff --git a/file_path_special.c b/file_path_special.c index b8167068ff..78007d0738 100644 --- a/file_path_special.c +++ b/file_path_special.c @@ -146,7 +146,7 @@ bool fill_pathname_application_data(char *s, size_t len) if (appdata) { fill_pathname_join(s, appdata, - "Library/Application Support/RetroArch", len); + "Library/Application Support/RetroArch", len); return true; } #endif diff --git a/frontend/drivers/platform_ctr.c b/frontend/drivers/platform_ctr.c index aa36b99b36..309e63f70c 100644 --- a/frontend/drivers/platform_ctr.c +++ b/frontend/drivers/platform_ctr.c @@ -61,6 +61,9 @@ #endif #endif +#include "../../audio/audio_driver.h" +#include "../../menu/menu_entries.h" + static enum frontend_fork ctr_fork_mode = FRONTEND_FORK_NONE; static const char* elf_path_cst = "sdmc:/retroarch/retroarch.3dsx"; @@ -139,6 +142,12 @@ static void frontend_ctr_get_env(int* argc, char* argv[], #endif } +#ifdef USE_CTRULIB_2 +u8* gfxTopLeftFramebuffers[2]; +u8* gfxTopRightFramebuffers[2]; +u8* gfxBottomFramebuffers[2]; +#endif + static void frontend_ctr_deinit(void* data) { Handle lcd_handle; @@ -371,10 +380,6 @@ __attribute__((weak)) u32 __ctr_patch_services; void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id); #ifdef USE_CTRULIB_2 -u8* gfxTopLeftFramebuffers[2]; -u8* gfxTopRightFramebuffers[2]; -u8* gfxBottomFramebuffers[2]; - void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id) { if (screen==GFX_TOP) diff --git a/frontend/drivers/platform_darwin.m b/frontend/drivers/platform_darwin.m index 0e2cd1bcc9..47f0a481ec 100644 --- a/frontend/drivers/platform_darwin.m +++ b/frontend/drivers/platform_darwin.m @@ -273,10 +273,10 @@ static void frontend_darwin_get_name(char *s, size_t len) if (uname(&buffer) == 0) strlcpy(s, buffer.machine, len); #elif defined(OSX) - size_t length = 0; - sysctlbyname("hw.model", NULL, &length, NULL, 0); - if (length) - sysctlbyname("hw.model", s, &length, NULL, 0); + size_t _len = 0; + sysctlbyname("hw.model", NULL, &_len, NULL, 0); + if (_len) + sysctlbyname("hw.model", s, &_len, NULL, 0); #endif } @@ -454,7 +454,7 @@ static void frontend_darwin_get_env(int *argc, char *argv[], application_data ); NSString *bundleVersionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; - NSInteger bundleVersion = [bundleVersionString integerValue]; + NSInteger bundleVersion = [bundleVersionString integerValue] || 1; configuration_set_uint(settings, settings->uints.bundle_assets_extract_version_current, (uint)bundleVersion); } @@ -685,10 +685,8 @@ static enum frontend_architecture frontend_darwin_get_arch(void) return FRONTEND_ARCH_ARMV8; #else cpu_type_t type; - size_t size = sizeof(type); - - sysctlbyname("hw.cputype", &type, &size, NULL, 0); - + size_t _len = sizeof(type); + sysctlbyname("hw.cputype", &type, &_len, NULL, 0); if (type == CPU_TYPE_X86_64) return FRONTEND_ARCH_X86_64; else if (type == CPU_TYPE_X86) @@ -704,7 +702,7 @@ static enum frontend_architecture frontend_darwin_get_arch(void) static int frontend_darwin_parse_drive_list(void *data, bool load_content) { int ret = -1; -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE || defined(HAVE_APPLE_STORE) #ifdef HAVE_MENU struct string_list *str_list = NULL; file_list_t *list = (file_list_t*)data; @@ -733,7 +731,7 @@ static int frontend_darwin_parse_drive_list(void *data, bool load_content) FILE_TYPE_DIRECTORY, 0, 0, NULL); string_list_free(str_list); -#if TARGET_OS_IOS +#if !TARGET_OS_TV if ( filebrowser_get_type() == FILEBROWSER_NONE || filebrowser_get_type() == FILEBROWSER_SCAN_FILE || filebrowser_get_type() == FILEBROWSER_SELECT_FILE) @@ -756,14 +754,14 @@ static uint64_t frontend_darwin_get_total_mem(void) uint64_t size; int mib[2] = { CTL_HW, HW_MEMSIZE }; u_int namelen = ARRAY_SIZE(mib); - size_t len = sizeof(size); - if (sysctl(mib, namelen, &size, &len, NULL, 0) >= 0) + size_t _len = sizeof(size); + if (sysctl(mib, namelen, &size, &_len, NULL, 0) >= 0) return size; #elif defined(IOS) - task_vm_info_data_t vmInfo; + task_vm_info_data_t vm_info; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; - if (task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count) == KERN_SUCCESS) - return vmInfo.phys_footprint + vmInfo.limit_bytes_remaining; + if (task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vm_info, &count) == KERN_SUCCESS) + return vm_info.phys_footprint + vm_info.limit_bytes_remaining; #endif return 0; } @@ -776,8 +774,8 @@ static uint64_t frontend_darwin_get_free_mem(void) mach_port_t mach_port = mach_host_self(); mach_msg_type_number_t count = sizeof(vm_stats) / sizeof(natural_t); - if (KERN_SUCCESS == host_page_size(mach_port, &page_size) && - KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO, + if ( KERN_SUCCESS == host_page_size(mach_port, &page_size) + && KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO, (host_info64_t)&vm_stats, &count)) { long long used_memory = ( @@ -787,10 +785,10 @@ static uint64_t frontend_darwin_get_free_mem(void) return used_memory; } #elif defined(IOS) - task_vm_info_data_t vmInfo; + task_vm_info_data_t vm_info; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; - if (task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count) == KERN_SUCCESS) - return vmInfo.limit_bytes_remaining; + if (task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vm_info, &count) == KERN_SUCCESS) + return vm_info.limit_bytes_remaining; #endif return 0; } @@ -808,7 +806,8 @@ static enum retro_language frontend_darwin_get_user_language(void) CFArrayRef langs = CFLocaleCopyPreferredLanguages(); CFStringRef langCode = CFArrayGetValueAtIndex(langs, 0); CFStringGetCString(langCode, s, sizeof(s), kCFStringEncodingUTF8); - /* iOS and OS X only support the language ID syntax consisting of a language designator and optional region or script designator. */ + /* iOS and OS X only support the language ID syntax consisting + * of a language designator and optional region or script designator. */ string_replace_all_chars(s, '-', '_'); return retroarch_get_language_from_iso(s); } diff --git a/frontend/drivers/platform_dos.c b/frontend/drivers/platform_dos.c index 17d3541f64..fd2c5b06d8 100644 --- a/frontend/drivers/platform_dos.c +++ b/frontend/drivers/platform_dos.c @@ -107,11 +107,11 @@ static void frontend_dos_get_env_settings(int *argc, char *argv[], static void frontend_dos_exec(const char *path, bool should_load_game) { char *newargv[] = { NULL, NULL }; - size_t len = strlen(path); + size_t _len = strlen(path); - newargv[0] = (char*)malloc(len); + newargv[0] = (char*)malloc(_len); - strlcpy(newargv[0], path, len); + strlcpy(newargv[0], path, _len); execv(path, newargv); } diff --git a/frontend/drivers/platform_emscripten.c b/frontend/drivers/platform_emscripten.c index 5c0511e35d..ff2cb3ec6f 100644 --- a/frontend/drivers/platform_emscripten.c +++ b/frontend/drivers/platform_emscripten.c @@ -18,6 +18,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -46,9 +51,60 @@ #include "../../retroarch.h" #include "../../verbosity.h" #include "../../tasks/tasks_internal.h" +#include "../../cheat_manager.h" +#include "../../audio/audio_driver.h" + +#ifdef HAVE_EXTRA_WASMFS +#include +#endif + +#ifdef PROXY_TO_PTHREAD +#include +#include +#include +#include +#define PLATFORM_SETVAL(type, addr, val) emscripten_atomic_store_##type(addr, val) +#define PLATFORM_GETVAL(type, addr) emscripten_atomic_load_##type(addr) +#else +#define PLATFORM_SETVAL(type, addr, val) *addr = val +#define PLATFORM_GETVAL(type, addr) *addr +#endif + +#include "platform_emscripten.h" -void dummyErrnoCodes(void); void emscripten_mainloop(void); +void PlatformEmscriptenWatchCanvasSizeAndDpr(double *dpr); +void PlatformEmscriptenWatchWindowVisibility(void); +void PlatformEmscriptenPowerStateInit(void); +void PlatformEmscriptenMemoryUsageInit(void); + +typedef struct +{ +#ifdef PROXY_TO_PTHREAD + pthread_t program_thread_id; + emscripten_lock_t raf_lock; + emscripten_condvar_t raf_cond; +#endif + uint64_t memory_used; + uint64_t memory_limit; + double device_pixel_ratio; + int raf_interval; + int canvas_width; + int canvas_height; + int power_state_discharge_time; + float power_state_level; + bool has_async_atomics; + volatile bool power_state_charging; + volatile bool power_state_supported; + volatile bool window_hidden; + volatile bool command_flag; +} emscripten_platform_data_t; + +static emscripten_platform_data_t *emscripten_platform_data = NULL; + +/* begin exported functions */ + +/* saves and states */ void cmd_savefiles(void) { @@ -65,53 +121,360 @@ void cmd_load_state(void) command_event(CMD_EVENT_LOAD_STATE, NULL); } +void cmd_undo_save_state(void) +{ + command_event(CMD_EVENT_UNDO_SAVE_STATE, NULL); +} + +void cmd_undo_load_state(void) +{ + command_event(CMD_EVENT_UNDO_LOAD_STATE, NULL); +} + +/* misc */ + void cmd_take_screenshot(void) { command_event(CMD_EVENT_TAKE_SCREENSHOT, NULL); } +void cmd_toggle_menu(void) +{ + command_event(CMD_EVENT_MENU_TOGGLE, NULL); +} + +void cmd_reload_config(void) +{ + command_event(CMD_EVENT_RELOAD_CONFIG, NULL); +} + +void cmd_toggle_grab_mouse(void) +{ + command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); +} + +void cmd_toggle_game_focus(void) +{ + command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, NULL); +} + +void cmd_reset(void) +{ + command_event(CMD_EVENT_RESET, NULL); +} + +void cmd_toggle_pause(void) +{ + command_event(CMD_EVENT_PAUSE_TOGGLE, NULL); +} + +void cmd_pause(void) +{ + command_event(CMD_EVENT_PAUSE, NULL); +} + +void cmd_unpause(void) +{ + command_event(CMD_EVENT_UNPAUSE, NULL); +} + +void cmd_set_volume(float volume) +{ + audio_set_float(AUDIO_ACTION_VOLUME_GAIN, volume); +} + +#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) +bool cmd_set_shader(const char *path) +{ + return command_set_shader(NULL, path); +} +#endif + +/* cheats */ + +void cmd_cheat_set_code(unsigned index, const char *str) +{ + cheat_manager_set_code(index, str); +} + +const char *cmd_cheat_get_code(unsigned index) +{ + return cheat_manager_get_code(index); +} + +void cmd_cheat_toggle_index(bool apply_cheats_after_toggle, unsigned index) +{ + cheat_manager_toggle_index(apply_cheats_after_toggle, + config_get_ptr()->bools.notification_show_cheats_applied, + index); +} + +bool cmd_cheat_get_code_state(unsigned index) +{ + return cheat_manager_get_code_state(index); +} + +bool cmd_cheat_realloc(unsigned new_size) +{ + return cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_EMU); +} + +unsigned cmd_cheat_get_size(void) +{ + return cheat_manager_get_size(); +} + +void cmd_cheat_apply_cheats(void) +{ + cheat_manager_apply_cheats( + config_get_ptr()->bools.notification_show_cheats_applied); +} + +/* javascript callbacks */ + +void platform_emscripten_update_canvas_dimensions(int width, int height, double *dpr) +{ + printf("[INFO] Setting real canvas size: %d x %d\n", width, height); + emscripten_set_canvas_element_size("#canvas", width, height); + if (!emscripten_platform_data) + return; + PLATFORM_SETVAL(u32, &emscripten_platform_data->canvas_width, width); + PLATFORM_SETVAL(u32, &emscripten_platform_data->canvas_height, height); + PLATFORM_SETVAL(f64, &emscripten_platform_data->device_pixel_ratio, *dpr); +} + +void platform_emscripten_update_window_hidden(bool hidden) +{ + if (!emscripten_platform_data) + return; + emscripten_platform_data->window_hidden = hidden; +} + +void platform_emscripten_update_power_state(bool supported, int discharge_time, float level, bool charging) +{ + if (!emscripten_platform_data) + return; + emscripten_platform_data->power_state_supported = supported; + emscripten_platform_data->power_state_charging = charging; + PLATFORM_SETVAL(u32, &emscripten_platform_data->power_state_discharge_time, discharge_time); + PLATFORM_SETVAL(f32, &emscripten_platform_data->power_state_level, level); +} + +void platform_emscripten_update_memory_usage(uint32_t used1, uint32_t used2, uint32_t limit1, uint32_t limit2) +{ + if (!emscripten_platform_data) + return; + PLATFORM_SETVAL(u64, &emscripten_platform_data->memory_used, used1 | ((uint64_t)used2 << 32)); + PLATFORM_SETVAL(u64, &emscripten_platform_data->memory_limit, limit1 | ((uint64_t)limit2 << 32)); +} + +void platform_emscripten_command_raise_flag() +{ + if (!emscripten_platform_data) + return; + emscripten_platform_data->command_flag = true; +} + +/* platform specific c helpers */ +/* see platform_emscripten.h for documentation. */ + +void platform_emscripten_run_on_browser_thread_sync(void (*func)(void*), void* arg) +{ +#ifdef PROXY_TO_PTHREAD + emscripten_proxy_sync(emscripten_proxy_get_system_queue(), emscripten_main_runtime_thread_id(), func, arg); +#else + func(arg); +#endif +} + +void platform_emscripten_run_on_browser_thread_async(void (*func)(void*), void* arg) +{ +#ifdef PROXY_TO_PTHREAD + emscripten_proxy_async(emscripten_proxy_get_system_queue(), emscripten_main_runtime_thread_id(), func, arg); +#else + emscripten_async_call(func, arg, 0); +#endif +} + +void platform_emscripten_run_on_program_thread_async(void (*func)(void*), void* arg) +{ +#ifdef PROXY_TO_PTHREAD + emscripten_proxy_async(emscripten_proxy_get_system_queue(), emscripten_platform_data->program_thread_id, func, arg); +#else + emscripten_async_call(func, arg, 0); +#endif +} + +void platform_emscripten_command_reply(const char *msg, size_t len) +{ + MAIN_THREAD_EM_ASM({ + var message = UTF8ToString($0, $1); + RPE.command_reply_queue.push(message); + }, msg, len); +} + +size_t platform_emscripten_command_read(char **into, size_t max_len) +{ + if (!emscripten_platform_data || !emscripten_platform_data->command_flag) + return 0; + return MAIN_THREAD_EM_ASM_INT({ + var next_command = RPE.command_queue.shift(); + var length = lengthBytesUTF8(next_command); + if (length > $2) { + console.error("[CMD] Command too long, skipping", next_command); + return 0; + } + stringToUTF8(next_command, $1, $2); + if (RPE.command_queue.length == 0) { + setValue($0, 0, 'i8'); + } + return length; + }, &emscripten_platform_data->command_flag, into, max_len); +} + +void platform_emscripten_get_canvas_size(int *width, int *height) +{ + if (!emscripten_platform_data) + goto error; + + *width = PLATFORM_GETVAL(u32, &emscripten_platform_data->canvas_width); + *height = PLATFORM_GETVAL(u32, &emscripten_platform_data->canvas_height); + + if (*width != 0 || *height != 0) + return; + +error: + *width = 800; + *height = 600; + RARCH_ERR("[EMSCRIPTEN]: Could not get screen dimensions!\n"); +} + +double platform_emscripten_get_dpr(void) +{ + return PLATFORM_GETVAL(f64, &emscripten_platform_data->device_pixel_ratio); +} + +bool platform_emscripten_has_async_atomics(void) +{ + return emscripten_platform_data->has_async_atomics; +} + +bool platform_emscripten_is_window_hidden(void) +{ + return emscripten_platform_data->window_hidden; +} + +bool platform_emscripten_should_drop_iter(void) +{ + return (emscripten_platform_data->window_hidden && emscripten_platform_data->raf_interval); +} + +#ifdef PROXY_TO_PTHREAD + +static void set_raf_interval(void *data) +{ + emscripten_set_main_loop_timing(EM_TIMING_RAF, (int)data); +} + +void platform_emscripten_wait_for_frame(void) +{ + if (emscripten_platform_data->raf_interval) + emscripten_condvar_waitinf(&emscripten_platform_data->raf_cond, &emscripten_platform_data->raf_lock); +} + +#else + +void platform_emscripten_enter_fake_block(int ms) +{ + if (ms == 0) + emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0); + else + emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, ms); +} + +void platform_emscripten_exit_fake_block(void) +{ + command_event(CMD_EVENT_VIDEO_SET_BLOCKING_STATE, NULL); +} + +#endif + +void platform_emscripten_set_main_loop_interval(int interval) +{ + emscripten_platform_data->raf_interval = interval; +#ifdef PROXY_TO_PTHREAD + if (interval != 0) + platform_emscripten_run_on_browser_thread_sync(set_raf_interval, (void *)interval); +#else + if (interval == 0) + emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0); + else + emscripten_set_main_loop_timing(EM_TIMING_RAF, interval); +#endif +} + +/* frontend driver impl */ + static void frontend_emscripten_get_env(int *argc, char *argv[], void *args, void *params_data) { char base_path[PATH_MAX]; char user_path[PATH_MAX]; - const char *home = getenv("HOME"); + char bundle_path[PATH_MAX]; + const char *home = getenv("HOME"); if (home) { size_t _len = strlcpy(base_path, home, sizeof(base_path)); strlcpy(base_path + _len, "/retroarch", sizeof(base_path) - _len); +#ifndef HAVE_EXTRA_WASMFS + /* can be removed when the new web player replaces the old one */ _len = strlcpy(user_path, home, sizeof(user_path)); strlcpy(user_path + _len, "/retroarch/userdata", sizeof(user_path) - _len); + _len = strlcpy(bundle_path, home, sizeof(bundle_path)); + strlcpy(bundle_path + _len, "/retroarch/bundle", sizeof(bundle_path) - _len); +#else + _len = strlcpy(user_path, home, sizeof(user_path)); + strlcpy(user_path + _len, "/retroarch", sizeof(user_path) - _len); + _len = strlcpy(bundle_path, home, sizeof(bundle_path)); + strlcpy(bundle_path + _len, "/retroarch", sizeof(bundle_path) - _len); +#endif } else { strlcpy(base_path, "retroarch", sizeof(base_path)); +#ifndef HAVE_EXTRA_WASMFS + /* can be removed when the new web player replaces the old one */ strlcpy(user_path, "retroarch/userdata", sizeof(user_path)); + strlcpy(bundle_path, "retroarch/bundle", sizeof(bundle_path)); +#else + strlcpy(user_path, "retroarch", sizeof(user_path)); + strlcpy(bundle_path, "retroarch", sizeof(bundle_path)); +#endif } fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], base_path, "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE])); /* bundle data */ - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], base_path, - "bundle/assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], base_path, - "bundle/autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], base_path, - "bundle/database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path, - "bundle/info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], base_path, - "bundle/overlays", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OSK_OVERLAY], base_path, - "bundle/overlays/keyboards", sizeof(g_defaults.dirs[DEFAULT_DIR_OSK_OVERLAY])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], base_path, - "bundle/shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER], base_path, - "bundle/filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], base_path, - "bundle/filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], bundle_path, + "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], bundle_path, + "autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], bundle_path, + "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], bundle_path, + "info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], bundle_path, + "overlays", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OSK_OVERLAY], bundle_path, + "overlays/keyboards", sizeof(g_defaults.dirs[DEFAULT_DIR_OSK_OVERLAY])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], bundle_path, + "shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER], bundle_path, + "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], bundle_path, + "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER])); /* user data dirs */ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS], user_path, @@ -121,7 +484,7 @@ static void frontend_emscripten_get_env(int *argc, char *argv[], fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT], user_path, "content", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], user_path, - "content/downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], user_path, "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], @@ -143,67 +506,311 @@ static void frontend_emscripten_get_env(int *argc, char *argv[], fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CACHE], "/tmp/", "retroarch", sizeof(g_defaults.dirs[DEFAULT_DIR_CACHE])); - /* history and main config */ + /* history */ strlcpy(g_defaults.dirs[DEFAULT_DIR_CONTENT_HISTORY], user_path, sizeof(g_defaults.dirs[DEFAULT_DIR_CONTENT_HISTORY])); - fill_pathname_join(g_defaults.path_config, user_path, - FILE_PATH_MAIN_CONFIG, sizeof(g_defaults.path_config)); #ifndef IS_SALAMANDER dir_check_defaults("custom.ini"); #endif } -int main(int argc, char *argv[]) +static enum frontend_powerstate frontend_emscripten_get_powerstate(int *seconds, int *percent) { - dummyErrnoCodes(); + enum frontend_powerstate ret = FRONTEND_POWERSTATE_NONE; + float level; - EM_ASM({ - specialHTMLTargets["!canvas"] = Module.canvas; - }); + if (!emscripten_platform_data || !emscripten_platform_data->power_state_supported) + return ret; + + level = PLATFORM_GETVAL(f32, &emscripten_platform_data->power_state_level); + + if (!emscripten_platform_data->power_state_charging) + ret = FRONTEND_POWERSTATE_ON_POWER_SOURCE; + else if (level == 1) + ret = FRONTEND_POWERSTATE_CHARGED; + else + ret = FRONTEND_POWERSTATE_CHARGING; + + *seconds = PLATFORM_GETVAL(u32, &emscripten_platform_data->power_state_discharge_time); + *percent = (int)(level * 100); + + return ret; +} + +static uint64_t frontend_emscripten_get_total_mem(void) +{ + if (!emscripten_platform_data) + return 0; + return PLATFORM_GETVAL(u64, &emscripten_platform_data->memory_limit); +} + +static uint64_t frontend_emscripten_get_free_mem(void) +{ + if (!emscripten_platform_data) + return 0; +#ifndef PROXY_TO_PTHREAD + uint64_t used = PLATFORM_GETVAL(u64, &emscripten_platform_data->memory_used); +#else + uint64_t used = mallinfo().uordblks; +#endif + return (PLATFORM_GETVAL(u64, &emscripten_platform_data->memory_limit) - used); +} + +/* program entry and startup */ + +#ifdef HAVE_EXTRA_WASMFS +static void platform_emscripten_mount_filesystems(void) +{ + char *opfs_mount = getenv("OPFS_MOUNT"); + char *fetch_manifest = getenv("FETCH_MANIFEST"); + char *fetch_base_dir = getenv("FETCH_BASE_DIR"); + if (opfs_mount) + { + int res; + printf("[OPFS] Mount OPFS at %s\n", opfs_mount); + backend_t opfs = wasmfs_create_opfs_backend(); + { + char *parent = strdup(opfs_mount); + path_parent_dir(parent, strlen(parent)); + if (!path_mkdir(parent)) + { + printf("mkdir error %d\n", errno); + abort(); + } + free(parent); + } + res = wasmfs_create_directory(opfs_mount, 0777, opfs); + if (res) + { + printf("[OPFS] error result %d\n", res); + if (errno) + { + printf("[OPFS] errno %d\n", errno); + abort(); + } + abort(); + } + } + if (fetch_manifest || fetch_base_dir) + { + /* fetch_manifest should be a path to a manifest file. + manifest files have this format: + + BASEURL + URL PATH + URL PATH + URL PATH + ... + + Where URL may not contain spaces, but PATH may. + URL segments are relative to BASEURL. + */ + int max_line_len = 1024; + if (!(fetch_manifest && fetch_base_dir)) + { + printf("[FetchFS] must specify both FETCH_MANIFEST and FETCH_BASE_DIR\n"); + abort(); + } + printf("[FetchFS] read fetch manifest from %s\n", fetch_manifest); + FILE *file = fopen(fetch_manifest, "r"); + if (!file) + { + printf("[FetchFS] missing manifest file\n"); + abort(); + } + char *line = calloc(sizeof(char), max_line_len); + size_t len = max_line_len; + if (getline(&line, &len, file) == -1 || len == 0) + printf("[FetchFS] missing base URL suggest empty manifest, skipping fetch initialization\n"); + else + { + char *base_url = strdup(line); + base_url[strcspn(base_url, "\r\n")] = '\0'; // drop newline + base_url[len-1] = '\0'; // drop newline + backend_t fetch = NULL; + len = max_line_len; + // Don't create fetch backend unless manifest actually has entries + while (getline(&line, &len, file) != -1) + { + if (!fetch) + { + fetch = wasmfs_create_fetch_backend(base_url, 16*1024*1024); + if(!fetch) { + printf("[FetchFS] couldn't create fetch backend for %s\n", base_url); + abort(); + } + wasmfs_create_directory(fetch_base_dir, 0777, fetch); + } + char *realfs_path = strstr(line, " "), *url = line; + int fd; + if (len <= 2 || !realfs_path) + { + printf("[FetchFS] Manifest file has invalid line %s\n",line); + continue; + } + *realfs_path = '\0'; + realfs_path += 1; + realfs_path[strcspn(realfs_path, "\r\n")] = '\0'; + char fetchfs_path[PATH_MAX]; + fill_pathname_join(fetchfs_path, fetch_base_dir, url, sizeof(fetchfs_path)); + /* Make the directories for link path */ + { + char *parent = strdup(realfs_path); + path_parent_dir(parent, strlen(parent)); + if (!path_mkdir(parent)) + { + printf("[FetchFS] mkdir error %s %d\n", realfs_path, errno); + abort(); + } + free(parent); + } + /* Make the directories for URL path */ + { + char *parent = strdup(fetchfs_path); + path_parent_dir(parent, strlen(parent)); + if (!path_mkdir(parent)) + { + printf("[FetchFS] mkdir error %s %d\n", fetchfs_path, errno); + abort(); + } + free(parent); + } + fd = wasmfs_create_file(fetchfs_path, 0777, fetch); + if (!fd) + { + printf("[FetchFS] couldn't create fetch file %s\n", fetchfs_path); + abort(); + } + close(fd); + if (symlink(fetchfs_path, realfs_path) != 0) + { + printf("[FetchFS] couldn't create link %s to fetch file %s (errno %d)\n", realfs_path, fetchfs_path, errno); + abort(); + } + len = max_line_len; + } + free(base_url); + } + fclose(file); + free(line); + } +} +#endif /* HAVE_EXTRA_WASMFS */ + +static int thread_main(int argc, char *argv[]) +{ +#ifdef HAVE_EXTRA_WASMFS + platform_emscripten_mount_filesystems(); +#endif - emscripten_set_canvas_element_size("!canvas", 800, 600); - emscripten_set_element_css_size("!canvas", 800.0, 600.0); emscripten_set_main_loop(emscripten_mainloop, 0, 0); +#ifdef PROXY_TO_PTHREAD + emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0); +#else + emscripten_set_main_loop_timing(EM_TIMING_RAF, 1); +#endif rarch_main(argc, argv, NULL); return 0; } +#ifdef PROXY_TO_PTHREAD + +static int _main_argc; +static char** _main_argv; + +static void *main_pthread(void* arg) +{ + emscripten_set_thread_name(pthread_self(), "Application main thread"); + emscripten_platform_data->program_thread_id = pthread_self(); + thread_main(_main_argc, _main_argv); + return NULL; +} + +static void raf_signaler(void) +{ + emscripten_condvar_signal(&emscripten_platform_data->raf_cond, 1); +} +#endif + +int main(int argc, char *argv[]) +{ + int ret = 0; +#ifdef PROXY_TO_PTHREAD + pthread_attr_t attr; + pthread_t thread; +#endif + /* this never gets freed */ + emscripten_platform_data = (emscripten_platform_data_t *)calloc(1, sizeof(emscripten_platform_data_t)); + + emscripten_platform_data->has_async_atomics = EM_ASM_INT({ + return Atomics?.waitAsync?.toString().includes("[native code]"); + }); + + PlatformEmscriptenWatchCanvasSizeAndDpr(malloc(sizeof(double))); + PlatformEmscriptenWatchWindowVisibility(); + PlatformEmscriptenPowerStateInit(); + PlatformEmscriptenMemoryUsageInit(); + + emscripten_platform_data->raf_interval = 1; +#ifdef PROXY_TO_PTHREAD + /* run requestAnimationFrame on the browser thread, as some browsers (chrome on linux) */ + /* seem to have issues running at full speed with requestAnimationFrame in workers. */ + /* instead, we run the RetroArch main loop with setImmediate and just wait on a signal if we need RAF */ + emscripten_lock_init(&emscripten_platform_data->raf_lock); + emscripten_condvar_init(&emscripten_platform_data->raf_cond); + emscripten_set_main_loop(raf_signaler, 0, 0); + emscripten_set_main_loop_timing(EM_TIMING_RAF, 1); + + _main_argc = argc; + _main_argv = argv; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize(&attr, EMSCRIPTEN_STACK_SIZE); + emscripten_pthread_attr_settransferredcanvases(&attr, (const char*)-1); + ret = pthread_create(&thread, &attr, main_pthread, NULL); + pthread_attr_destroy(&attr); +#else + ret = thread_main(argc, argv); +#endif + return ret; +} + frontend_ctx_driver_t frontend_ctx_emscripten = { - frontend_emscripten_get_env, /* environment_get */ - NULL, /* init */ - NULL, /* deinit */ - NULL, /* exitspawn */ - NULL, /* process_args */ - NULL, /* exec */ - NULL, /* set_fork */ - NULL, /* shutdown */ - NULL, /* get_name */ - NULL, /* get_os */ - NULL, /* get_rating */ - NULL, /* load_content */ - NULL, /* get_architecture */ - NULL, /* get_powerstate */ - NULL, /* parse_drive_list */ - NULL, /* get_total_mem */ - NULL, /* get_free_mem */ - NULL, /* install_sighandlers */ - NULL, /* get_signal_handler_state */ - NULL, /* set_signal_handler_state */ - NULL, /* destroy_signal_handler_state */ - NULL, /* attach_console */ - NULL, /* detach_console */ - NULL, /* get_lakka_version */ - NULL, /* set_screen_brightness */ - NULL, /* watch_path_for_changes */ - NULL, /* check_for_path_changes */ - NULL, /* set_sustained_performance_mode */ - NULL, /* get_cpu_model_name */ - NULL, /* get_user_language */ - NULL, /* is_narrator_running */ - NULL, /* accessibility_speak */ - NULL, /* set_gamemode */ - "emscripten", /* ident */ - NULL /* get_video_driver */ + frontend_emscripten_get_env, /* environment_get */ + NULL, /* init */ + NULL, /* deinit */ + NULL, /* exitspawn */ + NULL, /* process_args */ + NULL, /* exec */ + NULL, /* set_fork */ + NULL, /* shutdown */ + NULL, /* get_name */ + NULL, /* get_os */ + NULL, /* get_rating */ + NULL, /* load_content */ + NULL, /* get_architecture */ + frontend_emscripten_get_powerstate, /* get_powerstate */ + NULL, /* parse_drive_list */ + frontend_emscripten_get_total_mem, /* get_total_mem */ + frontend_emscripten_get_free_mem, /* get_free_mem */ + NULL, /* install_sighandlers */ + NULL, /* get_signal_handler_state */ + NULL, /* set_signal_handler_state */ + NULL, /* destroy_signal_handler_state */ + NULL, /* attach_console */ + NULL, /* detach_console */ + NULL, /* get_lakka_version */ + NULL, /* set_screen_brightness */ + NULL, /* watch_path_for_changes */ + NULL, /* check_for_path_changes */ + NULL, /* set_sustained_performance_mode */ + NULL, /* get_cpu_model_name */ + NULL, /* get_user_language */ + NULL, /* is_narrator_running */ + NULL, /* accessibility_speak */ + NULL, /* set_gamemode */ + "emscripten", /* ident */ + NULL /* get_video_driver */ }; diff --git a/frontend/drivers/platform_emscripten.h b/frontend/drivers/platform_emscripten.h new file mode 100644 index 0000000000..add2ad03c6 --- /dev/null +++ b/frontend/drivers/platform_emscripten.h @@ -0,0 +1,131 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2012-2015 - Michael Lelli + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef _PLATFORM_EMSCRIPTEN_H +#define _PLATFORM_EMSCRIPTEN_H + +#include + +/** + * Synchronously run a function on the browser thread. + * + * @param func Function to call + * @param arg Argument to pass to \c func + */ +void platform_emscripten_run_on_browser_thread_sync(void (*func)(void*), void* arg); + +/** + * Asynchronously run a function on the browser thread. Returns immediately. + * + * @param func Function to call + * @param arg Argument to pass to \c func + */ +void platform_emscripten_run_on_browser_thread_async(void (*func)(void*), void* arg); + +/** + * Asynchronously run a function on the program thread. Returns immediately. + * + * @param func Function to call + * @param arg Argument to pass to \c func + */ +void platform_emscripten_run_on_program_thread_async(void (*func)(void*), void* arg); + +/** + * Send command reply. + * + * @param msg Reply string + * @param len Length of \c msg + */ +void platform_emscripten_command_reply(const char *msg, size_t len); + +/** + * Read a command from the command queue. + * + * @param into Pointer to store command string + * @param max_len Length of \c *into + * @return Length of stored command. + * Returns 0 if there are no commands in queue. + */ +size_t platform_emscripten_command_read(char **into, size_t max_len); + +/** + * Get the real screen dimensions of the canvas on the page. + * + * @param width Pointer to store canvas width + * @param height Pointer to store canvas height + */ +void platform_emscripten_get_canvas_size(int *width, int *height); + +/** + * Get the ratio of CSS pixels to real screen pixels. Useful for input scaling. + * + * @return devicePixelRatio + */ +double platform_emscripten_get_dpr(void); + +/** + * Check if the browser supports Atomics.waitAsync. + * + * @return True if async atomics are available. + */ +bool platform_emscripten_has_async_atomics(void); + +/** + * Check if the window is hidden. + * + * @return True if the window is hidden. + */ +bool platform_emscripten_is_window_hidden(void); + +/** + * Whether the frame should be dropped. + * Currently returns true if the window is hidden and vsync is on. + * + * @return True if the frame should be dropped. + */ +bool platform_emscripten_should_drop_iter(void); + +/** + * Block until a vsync interval, if vsync is enabled. + * PROXY_TO_PTHREAD only. + */ +void platform_emscripten_wait_for_frame(void); + +/** + * Enter a loop that blocks the main loop function. + * !PROXY_TO_PTHREAD only. + * + * @param ms Milliseconds between iterations. + * Use 1 for balanced performance and CPU usage. + */ +void platform_emscripten_enter_fake_block(int ms); + +/** + * Exit the main loop blocking function. + * !PROXY_TO_PTHREAD only. + */ +void platform_emscripten_exit_fake_block(void); + +/** + * Set the vsync interval for the main loop. + * + * @param interval Vsync interval to set. + * Use 0 to disable vsync. + */ +void platform_emscripten_set_main_loop_interval(int interval); + +#endif diff --git a/frontend/drivers/platform_ps2.c b/frontend/drivers/platform_ps2.c index 3e2b242ab0..f8e7e9b897 100644 --- a/frontend/drivers/platform_ps2.c +++ b/frontend/drivers/platform_ps2.c @@ -343,7 +343,7 @@ static void frontend_ps2_exec(const char *path, bool should_load_game) deinit_drivers(true, true); reset_IOP(); common_init_drivers(false); - waitUntilDeviceIsReady(path); + waitUntilDeviceIsReady((char *)path); #ifndef IS_SALAMANDER char game_path[FILENAME_MAX]; diff --git a/frontend/drivers/platform_ps3.c b/frontend/drivers/platform_ps3.c index c197379868..0b2003fd3d 100644 --- a/frontend/drivers/platform_ps3.c +++ b/frontend/drivers/platform_ps3.c @@ -436,16 +436,16 @@ static void frontend_ps3_exec(const char *path, bool should_load_game) { #ifndef IS_SALAMANDER #ifdef HAVE_NETWORKING - char *arg_data[NETPLAY_FORK_MAX_ARGS]; + const char *arg_data[NETPLAY_FORK_MAX_ARGS]; #else - char *arg_data[2]; + const char *arg_data[2]; #endif char game_path[PATH_MAX_LENGTH]; bool verbosity = verbosity_is_enabled(); verbosity_enable(); #else - char *arg_data[1]; + const char *arg_data[1]; #endif arg_data[0] = NULL; diff --git a/frontend/drivers/platform_switch.c b/frontend/drivers/platform_switch.c index ed9bb7ce45..105d87e0f8 100644 --- a/frontend/drivers/platform_switch.c +++ b/frontend/drivers/platform_switch.c @@ -76,6 +76,37 @@ static enum frontend_fork switch_fork_mode = FRONTEND_FORK_NONE; bool platform_switch_has_focus = true; #ifdef HAVE_LIBNX +char *SWITCH_CPU_PROFILES[] = { + "Maximum Performance", + "High Performance", + "Boost Performance", + "Stock Performance", + "Powersaving Mode 1", + "Powersaving Mode 2", + "Powersaving Mode 3", + NULL +}; +char *SWITCH_CPU_SPEEDS[] = { + "1785 MHz", + "1581 MHz", + "1224 MHz", + "1020 MHz", + "918 MHz", + "816 MHz", + "714 MHz", + NULL +}; +unsigned SWITCH_CPU_SPEEDS_VALUES[] = { + 1785000000, + 1581000000, + 1224000000, + 1020000000, + 918000000, + 816000000, + 714000000, + 0 +}; + static bool psmInitialized = false; static AppletHookCookie applet_hook_cookie; @@ -87,7 +118,7 @@ extern bool nxlink_connected; void libnx_apply_overclock(void) { const size_t profiles_count = sizeof(SWITCH_CPU_PROFILES) - / sizeof(SWITCH_CPU_PROFILES[1]); + / sizeof(SWITCH_CPU_PROFILES[1]) - 1; settings_t *settings = config_get_ptr(); unsigned libnx_overclock = settings->uints.libnx_overclock; diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index 778f54eeda..e1db1da096 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c @@ -1323,6 +1323,13 @@ static void frontend_unix_get_env(int *argc, { unsigned i; const char* libretro_directory = getenv("LIBRETRO_DIRECTORY"); + const char* libretro_assets_directory = getenv("LIBRETRO_ASSETS_DIRECTORY"); + const char* libretro_autoconfig_directory = getenv("LIBRETRO_AUTOCONFIG_DIRECTORY"); + const char* libretro_cheats_directory = getenv("LIBRETRO_CHEATS_DIRECTORY"); + const char* libretro_database_directory = getenv("LIBRETRO_DATABASE_DIRECTORY"); + const char* libretro_system_directory = getenv("LIBRETRO_SYSTEM_DIRECTORY"); + const char* libretro_video_filter_directory = getenv("LIBRETRO_VIDEO_FILTER_DIRECTORY"); + const char* libretro_video_shader_directory = getenv("LIBRETRO_VIDEO_SHADER_DIRECTORY"); #ifdef ANDROID int32_t major, minor, rel; char device_model[PROP_VALUE_MAX] = {0}; @@ -1764,12 +1771,20 @@ static void frontend_unix_get_env(int *argc, "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); else #endif - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path, - "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); + if (!string_is_empty(libretro_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], libretro_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); + else + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path, + "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); #endif - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], base_path, - "autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG])); - + if (!string_is_empty(libretro_autoconfig_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], + libretro_autoconfig_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG])); + else + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], base_path, + "autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG])); #ifdef ASSETS_DIR if (path_is_directory(ASSETS_DIR "/assets")) fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], @@ -1777,7 +1792,10 @@ static void frontend_unix_get_env(int *argc, "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); else #endif - if (path_is_directory("/usr/local/share/retroarch/assets")) + if (!string_is_empty(libretro_assets_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_ASSETS], libretro_assets_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); + else if (path_is_directory("/usr/local/share/retroarch/assets")) fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], "/usr/local/share/retroarch", "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); @@ -1837,7 +1855,11 @@ static void frontend_unix_get_env(int *argc, "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER])); else #endif - if (path_is_directory("/usr/local/share/retroarch/filters/video")) + if (!string_is_empty(libretro_video_filter_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], + libretro_video_filter_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER])); + else if (path_is_directory("/usr/local/share/retroarch/filters/video")) fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], "/usr/local/share/retroarch", "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER])); @@ -1869,12 +1891,27 @@ static void frontend_unix_get_env(int *argc, "records_config", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT], base_path, "records", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], base_path, - "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], base_path, - "shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS], base_path, - "cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS])); + if (!string_is_empty(libretro_database_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_DATABASE], + libretro_database_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); + else + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], base_path, + "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); + if (!string_is_empty(libretro_video_shader_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_SHADER], + libretro_video_shader_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); + else + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], base_path, + "shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); + if (!string_is_empty(libretro_cheats_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_CHEATS], + libretro_cheats_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS])); + else + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS], base_path, + "cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], base_path, "overlays", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OSK_OVERLAY], base_path, @@ -1891,8 +1928,13 @@ static void frontend_unix_get_env(int *argc, "saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], base_path, "states", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], base_path, - "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); + if (!string_is_empty(libretro_system_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_SYSTEM], + libretro_system_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); + else + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], base_path, + "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); #endif #ifndef IS_SALAMANDER @@ -2353,11 +2395,11 @@ static bool frontend_unix_set_fork(enum frontend_fork fork_mode) static void frontend_unix_exec(const char *path, bool should_load_content) { char *newargv[] = { NULL, NULL }; - size_t len = strlen(path); + size_t _len = strlen(path); - newargv[0] = (char*)malloc(len); + newargv[0] = (char*)malloc(_len); - strlcpy(newargv[0], path, len); + strlcpy(newargv[0], path, _len); execv(path, newargv); } diff --git a/frontend/drivers/platform_wii.c b/frontend/drivers/platform_wii.c index 45c7a0368c..a319d1fd54 100644 --- a/frontend/drivers/platform_wii.c +++ b/frontend/drivers/platform_wii.c @@ -80,10 +80,10 @@ static void dol_copy_argv_path(const char *dolpath, const char *argpath) } /* a relative path */ else if ( - (strstr(dolpath, "sd:/") != dolpath) && - (strstr(dolpath, "usb:/") != dolpath) && - (strstr(dolpath, "carda:/") != dolpath) && - (strstr(dolpath, "cardb:/") != dolpath) + (strstr(dolpath, "sd:/") != dolpath) + && (strstr(dolpath, "usb:/") != dolpath) + && (strstr(dolpath, "carda:/") != dolpath) + && (strstr(dolpath, "cardb:/") != dolpath) ) { fill_pathname_parent_dir(tmp, @@ -126,7 +126,7 @@ static void dol_copy_argv_path(const char *dolpath, const char *argpath) } static void dol_copy_raw_argv(const char *dolpath, - const void *args, size_t size) + const void *args, size_t len) { struct __argv *argv = (struct __argv*)ARGS_ADDR; char *cmdline = (char*)++argv; @@ -154,8 +154,8 @@ static void dol_copy_raw_argv(const char *dolpath, argv->length = (int)strlcat(cmdline, dolpath, PATH_MAX_LENGTH); argv->length += 1; - memcpy(cmdline + argv->length, args, size); - argv->length += size; + memcpy(cmdline + argv->length, args, len); + argv->length += len; DCFlushRange(argv, sizeof(*argv) + argv->length); } @@ -165,17 +165,16 @@ static void dol_copy_raw_argv(const char *dolpath, * heap memory and are restricted to the stack only. */ void system_exec_wii(const char *_path, bool should_load_game) { - char path[PATH_MAX_LENGTH]; - char args[PATH_MAX_LENGTH]; - size_t args_size; - size_t size; FILE *fp; void *dol; + char path[PATH_MAX_LENGTH]; + char args[PATH_MAX_LENGTH]; + size_t _len, __len; #ifndef IS_SALAMANDER bool verbosity = verbosity_is_enabled(); #endif - args_size = 0; + __len = 0; /* copy heap info into stack so it survives * us moving the .dol into MEM2. */ @@ -190,7 +189,7 @@ void system_exec_wii(const char *_path, bool should_load_game) if (net_st->fork_args.size) { memcpy(args, net_st->fork_args.args, net_st->fork_args.size); - args_size = net_st->fork_args.size; + __len = net_st->fork_args.size; } else #endif @@ -208,11 +207,11 @@ void system_exec_wii(const char *_path, bool should_load_game) } fseek(fp, 0, SEEK_END); - size = ftell(fp); + _len = ftell(fp); fseek(fp, 0, SEEK_SET); /* try to allocate a buffer for it. if we can't, fail. */ - dol = malloc(size); + dol = malloc(_len); if (!dol) { RARCH_ERR("Could not execute DOL file %s.\n", path); @@ -220,7 +219,7 @@ void system_exec_wii(const char *_path, bool should_load_game) goto exit; } - fread(dol, 1, size, fp); + fread(dol, 1, _len, fp); fclose(fp); fatUnmount("carda:"); @@ -231,17 +230,17 @@ void system_exec_wii(const char *_path, bool should_load_game) __io_usbstorage.shutdown(); /* don't use memcpy, there might be an overlap. */ - memmove(EXECUTE_ADDR, dol, size); - DCFlushRange(EXECUTE_ADDR, size); + memmove(EXECUTE_ADDR, dol, _len); + DCFlushRange(EXECUTE_ADDR, _len); - if (args_size) - dol_copy_raw_argv(path, args, args_size); + if (__len) + dol_copy_raw_argv(path, args, __len); else dol_copy_argv_path(path, should_load_game ? args : NULL); - size = booter_end - booter_start; - memcpy(BOOTER_ADDR, booter_start, size); - DCFlushRange(BOOTER_ADDR, size); + _len = booter_end - booter_start; + memcpy(BOOTER_ADDR, booter_start, _len); + DCFlushRange(BOOTER_ADDR, _len); SYS_ResetSystem(SYS_SHUTDOWN, 0, 0); __lwp_thread_stopmultitasking((void (*)(void))BOOTER_ADDR); diff --git a/frontend/drivers/platform_win32.c b/frontend/drivers/platform_win32.c index adb27b425c..4ecb7ed353 100644 --- a/frontend/drivers/platform_win32.c +++ b/frontend/drivers/platform_win32.c @@ -25,6 +25,11 @@ #include #endif +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 +#include +#include +#endif + #include #include #include @@ -278,15 +283,25 @@ static size_t frontend_win32_get_os(char *s, size_t len, int *major, int *minor) /* Windows 2000 and later */ SYSTEM_INFO si = {{0}}; OSVERSIONINFOEX vi = {0}; +#ifndef _MSC_VER + /* Vista and later, MSYS2/MINGW64 build */ + const char win_ver_reg_key[] = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; + const DWORD reg_read_flags = RRF_RT_REG_SZ; /* Only read strings (REG_SZ) */ + const int ProductName_2nd_digit = 9; /* second digit in the string 'Windows 10' */ + char str_ProductName[64] = {0}; + char str_DisplayVersion[64] = {0}; + char str_LCUVer[64] = {0}; + char str_CurrentBuild[64] = {0}; + DWORD key_type = 0; /* null pointer */ + DWORD data_size = 0; + long reg_read_result; + bool read_success = TRUE; + /* end Vista and later; still within Windows 2000 and later block */ +#endif + vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetSystemInfo(&si); - - /* Available from NT 3.5 and Win95 */ - GetVersionEx((OSVERSIONINFO*)&vi); - - server = vi.wProductType != VER_NT_WORKSTATION; - switch (si.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_AMD64: @@ -301,6 +316,73 @@ static size_t frontend_win32_get_os(char *s, size_t len, int *major, int *minor) default: break; } + +#ifndef _MSC_VER + /* Vista and later, MSYS2/MINGW64 build + * Check for Win11 by looking for a specific Registry value. + * The behavior of GetVersionEx is changed under Win11 and no longer provides + * relevant data. If the specific Registry value is present, read version data + * directly from registry and skip remainder of function. + * Each read is paired for string values; the first gets the size of the + * string (read into data_size); the second passes data_size back as an + * argument and reads the actual string. */ + reg_read_result = RegGetValue(HKEY_LOCAL_MACHINE, win_ver_reg_key, "LCUVer", + reg_read_flags, &key_type, 0, &data_size); + + if (reg_read_result == ERROR_SUCCESS) + { + if (RegGetValue(HKEY_LOCAL_MACHINE, win_ver_reg_key, "LCUVer", + reg_read_flags, &key_type, str_LCUVer, &data_size) != ERROR_SUCCESS) + read_success = FALSE; + + if (RegGetValue(HKEY_LOCAL_MACHINE, win_ver_reg_key, "ProductName", + reg_read_flags, &key_type, 0, &data_size) != ERROR_SUCCESS) + read_success = FALSE; + + if (RegGetValue(HKEY_LOCAL_MACHINE, win_ver_reg_key, "ProductName", + reg_read_flags, &key_type, str_ProductName, &data_size) != ERROR_SUCCESS) + read_success = FALSE; + + if (RegGetValue(HKEY_LOCAL_MACHINE, win_ver_reg_key, "DisplayVersion", + reg_read_flags, &key_type, 0, &data_size) != ERROR_SUCCESS) + read_success = FALSE; + + if (RegGetValue(HKEY_LOCAL_MACHINE, win_ver_reg_key, "DisplayVersion", + reg_read_flags, &key_type, str_DisplayVersion, &data_size) != ERROR_SUCCESS) + read_success = FALSE; + + if (read_success) + { + str_ProductName[ProductName_2nd_digit] = '1'; + /* Even the version in the Registry still says Windows 10 and requires + * string manipulation. */ + + _len = strlcpy(s, str_ProductName, len); + if (!string_is_empty(arch)) + { + _len += strlcat(s, " ", len); + _len += strlcat(s, arch, len); + } + _len = strlcat(s, " ", len); + _len = strlcat(s, str_DisplayVersion, len); + _len = strlcat(s, " (", len); + _len = strlcat(s, str_LCUVer, len); + _len = strlcat(s, ")", len); + + *major = 10; + *minor = 0; + + return _len; + } + } + /* End registry-check-and-read code; still within 2000-and-later block */ +#endif + + /* GetVersionEx call changed in Win2K and later */ + GetVersionEx((OSVERSIONINFO*)&vi); + + server = vi.wProductType != VER_NT_WORKSTATION; + #else OSVERSIONINFO vi = {0}; vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); @@ -566,24 +648,51 @@ static void frontend_win32_env_get(int *argc, char *argv[], { const char *tmp_dir = getenv("TMP"); const char *libretro_directory = getenv("LIBRETRO_DIRECTORY"); + const char *libretro_assets_directory = getenv("LIBRETRO_ASSETS_DIRECTORY"); + const char* libretro_autoconfig_directory = getenv("LIBRETRO_AUTOCONFIG_DIRECTORY"); + const char* libretro_cheats_directory = getenv("LIBRETRO_CHEATS_DIRECTORY"); + const char* libretro_database_directory = getenv("LIBRETRO_DATABASE_DIRECTORY"); + const char* libretro_system_directory = getenv("LIBRETRO_SYSTEM_DIRECTORY"); + const char* libretro_video_filter_directory = getenv("LIBRETRO_VIDEO_FILTER_DIRECTORY"); + const char* libretro_video_shader_directory = getenv("LIBRETRO_VIDEO_SHADER_DIRECTORY"); if (!string_is_empty(tmp_dir)) fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CACHE], tmp_dir, sizeof(g_defaults.dirs[DEFAULT_DIR_CACHE])); gfx_set_dwm(); - fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_ASSETS], - ":\\assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); + if (!string_is_empty(libretro_assets_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_ASSETS], libretro_assets_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); + else + fill_pathname_expand_special( + g_defaults.dirs[DEFAULT_DIR_ASSETS], + ":\\assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER], ":\\filters\\audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER])); - fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], - ":\\filters\\video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER])); - fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CHEATS], - ":\\cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS])); - fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_DATABASE], - ":\\database\\rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); + if (!string_is_empty(libretro_video_filter_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], + libretro_video_filter_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER])); + else + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], + ":\\filters\\video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER])); + if (!string_is_empty(libretro_cheats_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_CHEATS], + libretro_cheats_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS])); + else + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CHEATS], + ":\\cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS])); + if (!string_is_empty(libretro_database_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_DATABASE], + libretro_database_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); + else + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_DATABASE], + ":\\database\\rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], - ":\\playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); + ":\\playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG], ":\\config\\record", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT], @@ -606,12 +715,26 @@ static void frontend_win32_env_get(int *argc, char *argv[], else fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE], ":\\cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE])); - fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], - ":\\info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); - fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], - ":\\autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG])); - fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SHADER], - ":\\shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); + if (!string_is_empty(libretro_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], libretro_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); + else + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], + ":\\info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); + if (!string_is_empty(libretro_autoconfig_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], + libretro_autoconfig_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG])); + else + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], + ":\\autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG])); + if (!string_is_empty(libretro_video_filter_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_SHADER], + libretro_video_shader_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); + else + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SHADER], + ":\\shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], ":\\downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], @@ -620,8 +743,13 @@ static void frontend_win32_env_get(int *argc, char *argv[], ":\\saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], ":\\states", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); - fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SYSTEM], - ":\\system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); + if (!string_is_empty(libretro_system_directory)) + strlcpy(g_defaults.dirs[DEFAULT_DIR_SYSTEM], + libretro_system_directory, + sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); + else + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SYSTEM], + ":\\system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_LOGS], ":\\logs", sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS])); @@ -1078,9 +1206,12 @@ static bool accessibility_speak_windows(int speed, if (!wc || res != 0) { RARCH_ERR("Error communicating with NVDA\n"); + /* Fallback on powershell immediately and retry */ + g_plat_win32_flags &= ~PLAT_WIN32_FLAG_USE_NVDA; + g_plat_win32_flags |= PLAT_WIN32_FLAG_USE_POWERSHELL; if (wc) free(wc); - return false; + return accessibility_speak_windows(speed, speak_text, priority); } nvdaController_cancelSpeech_func(); diff --git a/frontend/frontend_driver.c b/frontend/frontend_driver.c index eb1caaa951..3937c9e968 100644 --- a/frontend/frontend_driver.c +++ b/frontend/frontend_driver.c @@ -388,8 +388,7 @@ enum frontend_architecture frontend_driver_get_cpu_architecture(void) return FRONTEND_ARCH_NONE; } -const void *frontend_driver_get_cpu_architecture_str( - char *s, size_t len) +const void *frontend_driver_get_cpu_architecture_str(char *s, size_t len) { frontend_state_t *frontend_st = &frontend_driver_st; frontend_ctx_driver_t *frontend = frontend_st->current_frontend_ctx; diff --git a/frontend/frontend_driver.h b/frontend/frontend_driver.h index 01caeb27cf..b1d9214000 100644 --- a/frontend/frontend_driver.h +++ b/frontend/frontend_driver.h @@ -162,8 +162,7 @@ void frontend_driver_free(void); enum frontend_architecture frontend_driver_get_cpu_architecture(void); -const void *frontend_driver_get_cpu_architecture_str( - char *frontend_architecture, size_t size); +const void *frontend_driver_get_cpu_architecture_str(char *s, size_t len); bool frontend_driver_has_get_video_driver_func(void); diff --git a/gfx/common/ctr_defines.h b/gfx/common/ctr_defines.h index 8523b6aff1..facbeb57ba 100644 --- a/gfx/common/ctr_defines.h +++ b/gfx/common/ctr_defines.h @@ -92,8 +92,8 @@ typedef struct ctr_video void *texture_linear; void *texture_swizzled; int display_list_size; - int texture_width; - int texture_height; + unsigned int texture_width; + unsigned int texture_height; ctr_scale_vector_t scale_vector; ctr_vertex_t* frame_coords; @@ -119,7 +119,7 @@ typedef struct ctr_video { ctr_vertex_t* buffer; ctr_vertex_t* current; - int size; + size_t size; }vertex_cache; int state_slot; @@ -158,10 +158,10 @@ typedef struct ctr_video typedef struct ctr_texture { - int width; - int height; - int active_width; - int active_height; + unsigned int width; + unsigned int height; + unsigned int active_width; + unsigned int active_height; enum texture_filter_type type; void* data; diff --git a/gfx/common/d3d10_common.c b/gfx/common/d3d10_common.c index 5da28cbab6..8626132e06 100644 --- a/gfx/common/d3d10_common.c +++ b/gfx/common/d3d10_common.c @@ -14,6 +14,7 @@ */ #define CINTERFACE +#define WIN32_LEAN_AND_MEAN #include "d3d10_defines.h" #include "d3dcompiler_common.h" diff --git a/gfx/common/d3d11_common.c b/gfx/common/d3d11_common.c index ead91a8806..84ef7458f4 100644 --- a/gfx/common/d3d11_common.c +++ b/gfx/common/d3d11_common.c @@ -14,6 +14,7 @@ */ #define CINTERFACE +#define WIN32_LEAN_AND_MEAN #include diff --git a/gfx/common/d3d9_common.h b/gfx/common/d3d9_common.h index 24ffeaa9ba..1340fee856 100644 --- a/gfx/common/d3d9_common.h +++ b/gfx/common/d3d9_common.h @@ -43,27 +43,14 @@ RETRO_BEGIN_DECLS -typedef struct d3d9_video d3d9_video_t; - typedef struct d3d9_video { - bool keep_aspect; - bool should_resize; - bool quitting; - bool needs_restore; - bool overlays_enabled; - /* TODO - refactor this away properly. */ - bool resolution_hd_enable; - - /* Only used for Xbox */ - bool widescreen_mode; - - unsigned cur_mon_id; - unsigned dev_rotation; - overlay_t *menu; void *renderchain_data; + char *shader_path; + overlay_t *overlays; + RECT font_rect; RECT font_rect_shifted; math_matrix_4x4 mvp; @@ -81,8 +68,6 @@ typedef struct d3d9_video float translate_x; float translate_y; - char *shader_path; - struct { int size; @@ -92,7 +77,20 @@ typedef struct d3d9_video }menu_display; size_t overlays_size; - overlay_t *overlays; + + unsigned cur_mon_id; + unsigned dev_rotation; + + bool keep_aspect; + bool should_resize; + bool quitting; + bool needs_restore; + bool overlays_enabled; + /* TODO - refactor this away properly. */ + bool resolution_hd_enable; + + /* Only used for Xbox */ + bool widescreen_mode; } d3d9_video_t; void *d3d9_vertex_buffer_new(void *dev, diff --git a/gfx/common/d3dcompiler_common.c b/gfx/common/d3dcompiler_common.c index 8ea35ad303..1adbe3a15d 100644 --- a/gfx/common/d3dcompiler_common.c +++ b/gfx/common/d3dcompiler_common.c @@ -115,7 +115,7 @@ HRESULT WINAPI } #endif -bool d3d_compile(const char* src, size_t size, +bool d3d_compile(const char* src, size_t len, LPCSTR src_name, LPCSTR entrypoint, LPCSTR target, D3DBlob* out) { D3DBlob error_msg; @@ -125,18 +125,18 @@ bool d3d_compile(const char* src, size_t size, UINT compileflags = 0; #endif - if (!size) - size = strlen(src); + if (!len) + len = strlen(src); if (FAILED(D3DCompile( - src, size, src_name, NULL, NULL, + src, len, src_name, NULL, NULL, entrypoint, target, compileflags, 0, out, &error_msg))) { if (error_msg) { const char* msg = (const char*)error_msg->lpVtbl->GetBufferPointer(error_msg); RARCH_ERR("D3DCompile failed :\n%s\n", msg); - /* Place a breakpoint here, if you want, + /* Place a breakpoint here, if you want, to see shader compilation issues */ Release(error_msg); } diff --git a/gfx/common/d3dcompiler_common.h b/gfx/common/d3dcompiler_common.h index 292cf13fe6..3c4c4ba758 100644 --- a/gfx/common/d3dcompiler_common.h +++ b/gfx/common/d3dcompiler_common.h @@ -24,7 +24,7 @@ typedef ID3DBlob* D3DBlob; -bool d3d_compile(const char* src, size_t size, +bool d3d_compile(const char* src, size_t len, LPCSTR src_name, LPCSTR entrypoint, LPCSTR target, D3DBlob* out); bool d3d_compile_from_file(LPCWSTR filename, LPCSTR entrypoint, LPCSTR target, D3DBlob* out); diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 4b02ceb298..c1b3fe3dab 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -43,7 +43,7 @@ #define VENDOR_ID_NV 0x10DE #define VENDOR_ID_INTEL 0x8086 -#if defined(_WIN32) +#if defined(_WIN32) || defined(__APPLE__) #define VULKAN_EMULATE_MAILBOX #endif @@ -277,9 +277,9 @@ static void vulkan_debug_mark_object(VkDevice device, } static bool vulkan_buffer_chain_suballoc(struct vk_buffer_chain *chain, - size_t size, struct vk_buffer_range *range) + size_t len, struct vk_buffer_range *range) { - VkDeviceSize next_offset = chain->offset + size; + VkDeviceSize next_offset = chain->offset + len; if (next_offset <= chain->current->buffer.size) { range->data = (uint8_t*)chain->current->buffer.mapped + chain->offset; @@ -287,24 +287,21 @@ static bool vulkan_buffer_chain_suballoc(struct vk_buffer_chain *chain, range->offset = chain->offset; chain->offset = (next_offset + chain->alignment - 1) & ~(chain->alignment - 1); - return true; } - return false; } static struct vk_buffer_node *vulkan_buffer_chain_alloc_node( const struct vulkan_context *context, - size_t size, VkBufferUsageFlags usage) + size_t len, VkBufferUsageFlags usage) { struct vk_buffer_node *node = (struct vk_buffer_node*) malloc(sizeof(*node)); if (!node) return NULL; - node->buffer = vulkan_create_buffer( - context, size, usage); + context, len, usage); node->next = NULL; return node; } @@ -701,12 +698,16 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk) &vk->context.memory_properties); #ifdef VULKAN_EMULATE_MAILBOX +#if defined(_WIN32) /* Win32 windowed mode seems to deal just fine with toggling VSync. * Fullscreen however ... */ if (vk->flags & VK_DATA_FLAG_FULLSCREEN) vk->flags |= VK_DATA_FLAG_EMULATE_MAILBOX; else vk->flags &= ~VK_DATA_FLAG_EMULATE_MAILBOX; +#else + vk->flags |= VK_DATA_FLAG_EMULATE_MAILBOX; +#endif #endif /* If we're emulating mailbox, stick to using fences rather than semaphores. @@ -1355,7 +1356,7 @@ static void vulkan_create_wait_fences(gfx_ctx_vulkan_data_t *vk) bool vulkan_buffer_chain_alloc(const struct vulkan_context *context, struct vk_buffer_chain *chain, - size_t size, struct vk_buffer_range *range) + size_t len, struct vk_buffer_range *range) { if (!chain->head) { @@ -1367,7 +1368,7 @@ bool vulkan_buffer_chain_alloc(const struct vulkan_context *context, chain->offset = 0; } - if (!vulkan_buffer_chain_suballoc(chain, size, range)) + if (!vulkan_buffer_chain_suballoc(chain, len, range)) { /* We've exhausted the current chain, traverse list until we * can find a block we can use. Usually, we just step once. */ @@ -1375,24 +1376,24 @@ bool vulkan_buffer_chain_alloc(const struct vulkan_context *context, { chain->current = chain->current->next; chain->offset = 0; - if (vulkan_buffer_chain_suballoc(chain, size, range)) + if (vulkan_buffer_chain_suballoc(chain, len, range)) return true; } /* We have to allocate a new node, might allocate larger * buffer here than block_size in case we have * a very large allocation. */ - if (size < chain->block_size) - size = chain->block_size; + if (len < chain->block_size) + len = chain->block_size; if (!(chain->current->next = vulkan_buffer_chain_alloc_node( - context, size, chain->usage))) + context, len, chain->usage))) return false; chain->current = chain->current->next; chain->offset = 0; /* This cannot possibly fail. */ - retro_assert(vulkan_buffer_chain_suballoc(chain, size, range)); + retro_assert(vulkan_buffer_chain_suballoc(chain, len, range)); } return true; } @@ -1418,7 +1419,7 @@ void vulkan_debug_mark_memory(VkDevice device, VkDeviceMemory memory) struct vk_buffer vulkan_create_buffer( const struct vulkan_context *context, - size_t size, VkBufferUsageFlags usage) + size_t len, VkBufferUsageFlags usage) { struct vk_buffer buffer; VkMemoryRequirements mem_reqs; @@ -1428,7 +1429,7 @@ struct vk_buffer vulkan_create_buffer( info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; info.pNext = NULL; info.flags = 0; - info.size = size; + info.size = len; info.usage = usage; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.queueFamilyIndexCount = 0; @@ -1450,7 +1451,7 @@ struct vk_buffer vulkan_create_buffer( vulkan_debug_mark_memory(context->device, buffer.memory); vkBindBufferMemory(context->device, buffer.buffer, buffer.memory, 0); - buffer.size = size; + buffer.size = len; vkMapMemory(context->device, buffer.memory, 0, buffer.size, 0, &buffer.mapped); @@ -1532,7 +1533,7 @@ bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk, enum vulkan_wsi_type type, void *display, void *surface, unsigned width, unsigned height, - unsigned swap_interval) + int8_t swap_interval) { switch (type) { @@ -1913,7 +1914,7 @@ bool vulkan_is_hdr10_format(VkFormat format) bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, unsigned width, unsigned height, - unsigned swap_interval) + int8_t swap_interval) { unsigned i; uint32_t format_count; @@ -1931,6 +1932,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, VkCompositeAlphaFlagBitsKHR composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; settings_t *settings = config_get_ptr(); bool vsync = settings->bools.video_vsync; + bool adaptive_vsync = settings->bools.video_adaptive_vsync; format.format = VK_FORMAT_UNDEFINED; format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; @@ -1950,7 +1952,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, && (vk->flags & VK_DATA_FLAG_EMULATE_MAILBOX) && vsync) { - swap_interval = 1; + swap_interval = (adaptive_vsync) ? -1 : 1; vk->flags |= VK_DATA_FLAG_EMULATING_MAILBOX; } else @@ -2027,6 +2029,9 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, vk->context.swap_interval = swap_interval; + for (i = 0; i < present_mode_count; i++) + vk->context.present_modes[i] = present_modes[i]; + /* Prefer IMMEDIATE without vsync */ for (i = 0; i < present_mode_count; i++) { @@ -2037,6 +2042,13 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, swapchain_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; break; } + + if ( swap_interval < 0 + && present_modes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR) + { + swapchain_present_mode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; + break; + } } /* If still in FIFO with no swap interval, try MAILBOX */ diff --git a/gfx/common/vulkan_common.h b/gfx/common/vulkan_common.h index 29a489cde5..3a6dc9dd91 100644 --- a/gfx/common/vulkan_common.h +++ b/gfx/common/vulkan_common.h @@ -363,6 +363,7 @@ typedef struct vulkan_context VkPhysicalDeviceProperties gpu_properties; VkPhysicalDeviceMemoryProperties memory_properties; + VkPresentModeKHR present_modes[16]; VkImage swapchain_images[VULKAN_MAX_SWAPCHAIN_IMAGES]; VkFence swapchain_fences[VULKAN_MAX_SWAPCHAIN_IMAGES]; VkFormat swapchain_format; @@ -385,9 +386,9 @@ typedef struct vulkan_context unsigned swapchain_width; unsigned swapchain_height; - unsigned swap_interval; unsigned num_recycled_acquire_semaphores; + int8_t swap_interval; uint8_t flags; bool swapchain_fences_signalled[VULKAN_MAX_SWAPCHAIN_IMAGES]; @@ -683,7 +684,7 @@ typedef struct vk } vk_t; bool vulkan_buffer_chain_alloc(const struct vulkan_context *context, - struct vk_buffer_chain *chain, size_t size, + struct vk_buffer_chain *chain, size_t len, struct vk_buffer_range *range); struct vk_descriptor_pool *vulkan_alloc_descriptor_pool( @@ -703,7 +704,7 @@ void vulkan_debug_mark_buffer(VkDevice device, VkBuffer buffer); struct vk_buffer vulkan_create_buffer( const struct vulkan_context *context, - size_t size, VkBufferUsageFlags usage); + size_t len, VkBufferUsageFlags usage); void vulkan_destroy_buffer( VkDevice device, @@ -723,7 +724,7 @@ bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk, enum vulkan_wsi_type type, void *display, void *surface, unsigned width, unsigned height, - unsigned swap_interval); + int8_t swap_interval); void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index); @@ -731,7 +732,7 @@ void vulkan_acquire_next_image(gfx_ctx_vulkan_data_t *vk); bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, unsigned width, unsigned height, - unsigned swap_interval); + int8_t swap_interval); void vulkan_debug_mark_image(VkDevice device, VkImage image); void vulkan_debug_mark_memory(VkDevice device, VkDeviceMemory memory); diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index aa84bd7925..3e9b3ebc19 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -15,6 +15,8 @@ #if !defined(_XBOX) +#define WIN32_LEAN_AND_MEAN + #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0601 /* Windows 7 */ #endif @@ -333,10 +335,11 @@ static INT_PTR_COMPAT CALLBACK pick_core_proc( { case WM_INITDIALOG: { + const core_info_t *info = NULL; HWND hwndList; unsigned i; - /* Add items to list. */ + /* Add items to list. */ core_info_get_list(&core_info_list); core_info_list_get_supported_cores(core_info_list, path_get(RARCH_PATH_CONTENT), &core_info, &list_size); @@ -349,6 +352,12 @@ static INT_PTR_COMPAT CALLBACK pick_core_proc( SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)info->display_name); } + + /* Select the first item in the list */ + SendMessage(hwndList, LB_SETCURSEL, 0, 0); + info = (const core_info_t*)&core_info[0]; + path_set(RARCH_PATH_CORE, info->path); + SetFocus(hwndList); return TRUE; } @@ -1325,22 +1334,22 @@ static LRESULT CALLBACK wnd_proc_common_dinput_internal(HWND hwnd, if (gcs) { int i; - wchar_t wstr[4]={0,}; - int len1 = ImmGetCompositionStringW(hIMC, gcs, wstr, 4); - wstr[2] = wstr[1]; - wstr[1] = 0; - if ((len1 <= 0) || (len1 > 4)) + wchar_t wstr[4] = {0,}; + LONG _len = ImmGetCompositionStringW(hIMC, gcs, wstr, 4); + wstr[2] = wstr[1]; + wstr[1] = 0; + if ((_len <= 0) || (_len > 4)) break; - for (i = 0; i < len1; i = i + 2) + for (i = 0; i < _len; i = i + 2) { - size_t len2; + size_t __len; char *utf8 = utf16_to_utf8_string_alloc(wstr+i); if (!utf8) continue; - len2 = strlen(utf8) + 1; - if (len2 >= 1 && len2 <= 3) + __len = strlen(utf8) + 1; + if (__len >= 1 && __len <= 3) { - if (len2 >= 2) + if (__len >= 2) utf8[3] = (gcs) | (gcs >> 4); input_keyboard_event(true, 1, *((int*)utf8), 0, RETRO_DEVICE_KEYBOARD); } @@ -1373,8 +1382,10 @@ static LRESULT CALLBACK wnd_proc_common_dinput_internal(HWND hwnd, keysym |= 0x80; /* tell the driver about shift and alt key events */ - if (keysym == 0x2A/*DIK_LSHIFT*/ || keysym == 0x36/*DIK_RSHIFT*/ - || keysym == 0x38/*DIK_LMENU*/ || keysym == 0xB8/*DIK_RMENU*/) + if ( keysym == 0x2A/*DIK_LSHIFT*/ + || keysym == 0x36/*DIK_RSHIFT*/ + || keysym == 0x38/*DIK_LMENU*/ + || keysym == 0xB8/*DIK_RMENU*/) { void* input_data = (void*)(LONG_PTR)GetWindowLongPtr(main_window.hwnd, GWLP_USERDATA); if (input_data && dinput_handle_message(input_data, @@ -2115,7 +2126,7 @@ static void win32_localize_menu(HMENU menu) memset(&menu_item_info, 0, sizeof(menu_item_info)); menu_item_info.cbSize = sizeof(menu_item_info); menu_item_info.dwTypeData = NULL; -#if(WINVER >= 0x0500) +#if (WINVER >= 0x0500) menu_item_info.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_SUBMENU; #else menu_item_info.fMask = MIIM_ID | MIIM_STATE | MIIM_SUBMENU; @@ -2137,7 +2148,7 @@ static void win32_localize_menu(HMENU menu) if (label_enum != MSG_UNKNOWN) { int len; - size_t len2; + size_t __len; #ifndef LEGACY_WIN32 wchar_t* new_label_unicode = NULL; #else @@ -2156,38 +2167,38 @@ static void win32_localize_menu(HMENU menu) MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST) { meta_key_name = "Ctrl+O"; - len2 = STRLEN_CONST("Ctrl+O"); + __len = STRLEN_CONST("Ctrl+O"); } else if (label_enum == MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY) { meta_key_name = "Alt+Enter"; - len2 = STRLEN_CONST("Alt+Enter"); + __len = STRLEN_CONST("Alt+Enter"); } else if (meta_key != 0) { meta_key_name = win32_meta_key_to_name(meta_key); - len2 = strlen(meta_key_name); + __len = strlen(meta_key_name); } /* Append localized name, tab character, and Shortcut Key */ if (meta_key_name && string_is_not_equal(meta_key_name, "nul")) { - size_t len1 = strlen(new_label); - size_t buf_size = len1 + len2 + 2; + size_t _len = strlen(new_label); + size_t buf_size = _len + __len + 2; new_label_text = (char*)malloc(buf_size); if (new_label_text) { - size_t _len; + size_t __len; new_label2 = new_label_text; - _len = strlcpy(new_label_text, new_label, + __len = strlcpy(new_label_text, new_label, buf_size); - new_label_text[ _len] = '\t'; - new_label_text[++_len] = '\0'; - strlcpy(new_label_text + _len, meta_key_name, buf_size - _len); + new_label_text[ __len] = '\t'; + new_label_text[++__len] = '\0'; + strlcpy(new_label_text + __len, meta_key_name, buf_size - __len); /* Make first character of shortcut name uppercase */ - new_label_text[len1 + 1] = toupper(new_label_text[len1 + 1]); + new_label_text[_len + 1] = toupper(new_label_text[_len + 1]); } } diff --git a/gfx/common/x11_common.c b/gfx/common/x11_common.c index 8a7cc783d6..36efb980be 100644 --- a/gfx/common/x11_common.c +++ b/gfx/common/x11_common.c @@ -813,13 +813,13 @@ bool x11_connect(void) void x11_update_title(void *data) { - size_t len; + size_t _len; char title[128]; - title[0] = '\0'; - len = video_driver_get_window_title(title, sizeof(title)); + title[0] = '\0'; + _len = video_driver_get_window_title(title, sizeof(title)); if (title[0]) XChangeProperty(g_x11_dpy, g_x11_win, XA_WM_NAME, XA_STRING, - 8, PropModeReplace, (const unsigned char*)title, len); + 8, PropModeReplace, (const unsigned char*)title, _len); } bool x11_input_ctx_new(bool true_full) diff --git a/gfx/display_servers/dispserv_apple.m b/gfx/display_servers/dispserv_apple.m index 67652f8e14..ce30c47e08 100644 --- a/gfx/display_servers/dispserv_apple.m +++ b/gfx/display_servers/dispserv_apple.m @@ -140,7 +140,7 @@ static void *apple_display_server_get_resolution_list( UIScreen *mainScreen = [UIScreen mainScreen]; #if (TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000) || (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 150000) - if (@available(iOS 15, *)) + if (@available(iOS 15, tvOS 15, *)) currentRate = [CocoaView get].displayLink.preferredFrameRateRange.preferred; else #endif @@ -176,6 +176,55 @@ static void *apple_display_server_get_resolution_list( return conf; } +#if TARGET_OS_IOS +static void apple_display_server_set_screen_orientation(void *data, enum rotation rotation) +{ + switch (rotation) + { + case ORIENTATION_VERTICAL: + [[CocoaView get] setShouldLockCurrentInterfaceOrientation:YES]; + [[CocoaView get] setLockInterfaceOrientation:UIInterfaceOrientationLandscapeRight]; + break; + case ORIENTATION_FLIPPED: + [[CocoaView get] setShouldLockCurrentInterfaceOrientation:YES]; + [[CocoaView get] setLockInterfaceOrientation:UIInterfaceOrientationPortraitUpsideDown]; + break; + case ORIENTATION_FLIPPED_ROTATED: + [[CocoaView get] setShouldLockCurrentInterfaceOrientation:YES]; + [[CocoaView get] setLockInterfaceOrientation:UIInterfaceOrientationLandscapeLeft]; + break; + case ORIENTATION_NORMAL: + default: + [[CocoaView get] setShouldLockCurrentInterfaceOrientation:NO]; + break; + } +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000 + if (@available(iOS 16.0, *)) + { + [[CocoaView get] setNeedsUpdateOfSupportedInterfaceOrientations]; + } +#endif +} + +static enum rotation apple_display_server_get_screen_orientation(void *data) +{ + if (![[CocoaView get] shouldLockCurrentInterfaceOrientation]) + return ORIENTATION_NORMAL; + UIInterfaceOrientation orientation = [[CocoaView get] lockInterfaceOrientation]; + switch (orientation) + { + case UIInterfaceOrientationLandscapeRight: + return ORIENTATION_VERTICAL; + case UIInterfaceOrientationPortraitUpsideDown: + return ORIENTATION_FLIPPED; + case UIInterfaceOrientationLandscapeLeft: + return ORIENTATION_FLIPPED_ROTATED; + default: + return ORIENTATION_NORMAL; + } +} +#endif + const video_display_server_t dispserv_apple = { NULL, /* init */ NULL, /* destroy */ @@ -191,8 +240,13 @@ const video_display_server_t dispserv_apple = { apple_display_server_set_resolution, apple_display_server_get_resolution_list, NULL, /* get_output_options */ +#if TARGET_OS_IOS + apple_display_server_set_screen_orientation, + apple_display_server_get_screen_orientation, +#else NULL, /* set_screen_orientation */ NULL, /* get_screen_orientation */ +#endif NULL, /* get_flags */ "apple" }; diff --git a/gfx/display_servers/dispserv_win32.c b/gfx/display_servers/dispserv_win32.c index ffb952b33a..884ca35cab 100644 --- a/gfx/display_servers/dispserv_win32.c +++ b/gfx/display_servers/dispserv_win32.c @@ -15,6 +15,8 @@ * If not, see . */ +#define WIN32_LEAN_AND_MEAN + /* VC6 needs objbase included before initguid, but nothing else does */ #include #include diff --git a/gfx/drivers/ctr_gfx.c b/gfx/drivers/ctr_gfx.c index 85c583c13f..4f9400010f 100644 --- a/gfx/drivers/ctr_gfx.c +++ b/gfx/drivers/ctr_gfx.c @@ -39,7 +39,9 @@ #endif #include "../font_driver.h" +#define DEPRECATED #include "../../ctr/gpu_old.h" +#undef DEPRECATED #include "ctr_gu.h" #include "../../configuration.h" @@ -49,6 +51,7 @@ #include "../../retroarch.h" #include "../../runloop.h" #include "../../verbosity.h" +#include "../../paths.h" #include "../common/ctr_defines.h" #ifndef HAVE_THREADS @@ -232,7 +235,7 @@ gfx_display_ctx_driver_t gfx_display_ctx_ctr = { static void* ctr_font_init(void* data, const char* font_path, float font_size, bool is_threaded) { - int i, j; + unsigned int i, j; ctr_scale_vector_t *vec_top = NULL; ctr_scale_vector_t *vec_bottom = NULL; const uint8_t* src = NULL; @@ -321,7 +324,7 @@ static void ctr_font_free(void* data, bool is_threaded) static int ctr_font_get_message_width(void* data, const char* msg, size_t msg_len, float scale) { - int i; + size_t i; int delta_x = 0; const struct font_glyph* glyph_q = NULL; ctr_font_t* font = (ctr_font_t*)data; @@ -361,7 +364,7 @@ static void ctr_font_render_line( float pos_y, unsigned width, unsigned height, unsigned text_align) { - unsigned i; + unsigned int i; const struct font_glyph* glyph_q = NULL; ctr_vertex_t* v = NULL; int delta_x = 0; @@ -504,7 +507,7 @@ static void ctr_font_render_message( for (;;) { const char* delim = strchr(msg, '\n'); - size_t msg_len = delim ? (delim - msg) : strlen(msg); + size_t msg_len = delim ? (size_t)(delim - msg) : strlen(msg); /* Draw the line */ ctr_font_render_line(ctr, font, msg, msg_len, @@ -729,7 +732,7 @@ static INLINE void ctr_set_screen_coords(ctr_video_t * ctr) #ifdef HAVE_OVERLAY static void ctr_free_overlay(ctr_video_t *ctr) { - int i; + unsigned int i; for (i = 0; i < ctr->overlays; i++) { @@ -818,19 +821,17 @@ static void ctr_update_state_date(void *data) ctr_video_t *ctr = (ctr_video_t*)data; time_t now = time(NULL); struct tm *t = localtime(&now); - snprintf(ctr->state_date, sizeof(ctr->state_date), "%02d/%02d/%d", - t->tm_mon + 1, t->tm_mday, t->tm_year + 1900); + snprintf(ctr->state_date, sizeof(ctr->state_date), "%02u/%02u/%u", + ((unsigned)t->tm_mon + 1) % 100, + (unsigned)t->tm_mday % 100, + ((unsigned)t->tm_year + 1900) % 10000); } static bool ctr_update_state_date_from_file(void *data) { char state_path[PATH_MAX_LENGTH]; -#ifdef USE_CTRULIB_2 - time_t mtime; -#else - time_t ft; u64 mtime; -#endif + time_t ft; struct tm *t = NULL; ctr_video_t *ctr = (ctr_video_t*)data; @@ -848,16 +849,13 @@ static bool ctr_update_state_date_from_file(void *data) ctr->state_data_exist = true; -#ifdef USE_CTRULIB_2 - t = localtime(&mtime); -#else ft = mtime; t = localtime(&ft); -#endif - snprintf(ctr->state_date, sizeof(ctr->state_date), "%02d/%02d/%d", - t->tm_mon + 1, t->tm_mday, t->tm_year + 1900); - - return true; + snprintf(ctr->state_date, sizeof(ctr->state_date), "%02u/%02u/%u", + ((unsigned)t->tm_mon + 1) % 100, + (unsigned)t->tm_mday % 100, + ((unsigned)t->tm_year + 1900) % 10000); + return true; error: ctr->state_data_exist = false; @@ -1060,6 +1058,8 @@ static void ctr_bottom_menu_control(void* data, bool lcd_bottom, uint32_t flags) switch (ctr->bottom_menu) { + case CTR_BOTTOM_MENU_NOT_AVAILABLE: + return; case CTR_BOTTOM_MENU_DEFAULT: BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE); break; @@ -1150,8 +1150,7 @@ static void ctr_bottom_menu_control(void* data, bool lcd_bottom, uint32_t flags) ctr->refresh_bottom_menu = true; } - if ( ctr->bottom_menu == CTR_BOTTOM_MENU_NOT_AVAILABLE - || (!(flags & RUNLOOP_FLAG_CORE_RUNNING))) + if (!(flags & RUNLOOP_FLAG_CORE_RUNNING)) return; @@ -1588,6 +1587,9 @@ static void ctr_lcd_aptHook(APT_HookType hook, void* param) case APTHOOK_ONWAKEUP: command_event(CMD_EVENT_AUDIO_START, NULL); break; + case APTHOOK_ONEXIT: + case APTHOOK_COUNT: + break; } } @@ -1800,7 +1802,7 @@ static void* ctr_init(const video_info_t* video, video->is_threaded, FONT_DRIVER_RENDER_CTR); - ctr->msg_rendering_enabled = false; + ctr->msg_rendering_enabled = true; ctr->menu_texture_frame_enable = false; ctr->menu_texture_enable = false; @@ -2066,7 +2068,7 @@ static bool ctr_frame(void* data, const void* frame, } else { - int i; + unsigned int i; uint8_t *dst = (uint8_t*)ctr->texture_linear; const uint8_t *src = frame; @@ -2203,11 +2205,9 @@ static bool ctr_frame(void* data, const void* frame, } } - ctr->msg_rendering_enabled = true; #ifdef HAVE_MENU menu_driver_frame(menu_is_alive, video_info); #endif - ctr->msg_rendering_enabled = false; } else if (statistics_show) { @@ -2471,7 +2471,7 @@ static void ctr_free(void* data) static void ctr_set_texture_frame(void* data, const void* frame, bool rgb32, unsigned width, unsigned height, float alpha) { - int i; + unsigned int i; uint16_t *dst; const uint16_t *src; ctr_video_t *ctr = (ctr_video_t*)data; @@ -2571,10 +2571,10 @@ static uintptr_t ctr_load_texture(void *video_data, void *data, ctr_texture_t *texture = NULL; ctr_video_t *ctr = (ctr_video_t*)video_data; struct texture_image *image = (struct texture_image*)data; - int size = image->width + u32 size = image->width * image->height * sizeof(uint32_t); - if ((size * 3) > linearSpaceFree()) + if ((u64)size * 3 > linearSpaceFree()) return 0; if (!ctr || !image || image->width > 2048 || image->height > 2048) @@ -2599,7 +2599,7 @@ static uintptr_t ctr_load_texture(void *video_data, void *data, if ((image->width <= 32) || (image->height <= 32)) { - int i, j; + unsigned int i, j; uint32_t* src = (uint32_t*)image->pixels; for (j = 0; j < image->height; j++) @@ -2618,7 +2618,7 @@ static uintptr_t ctr_load_texture(void *video_data, void *data, } else { - int i; + unsigned int i; uint32_t *src = NULL; uint32_t *dst = NULL; @@ -2724,7 +2724,7 @@ static void ctr_overlay_vertex_geom(void *data, static bool ctr_overlay_load(void *data, const void *image_data, unsigned num_images) { - int i, j; + unsigned int i, j; void *tmpdata; ctr_texture_t *texture = NULL; ctr_video_t *ctr = (ctr_video_t *)data; @@ -2831,7 +2831,7 @@ static void ctr_overlay_set_alpha(void *data, unsigned image, float mod){ } static void ctr_render_overlay(ctr_video_t *ctr) { - int i; + unsigned int i; for (i = 0; i < ctr->overlays; i++) { @@ -2913,7 +2913,7 @@ static const video_poke_interface_t ctr_poke_interface = { ctr_apply_state_changes, ctr_set_texture_frame, ctr_set_texture_enable, - font_driver_render_msg, + ctr_set_osd_msg, NULL, /* show_mouse */ NULL, /* grab_mouse_toggle */ NULL, /* get_current_shader */ diff --git a/gfx/drivers/d3d10.c b/gfx/drivers/d3d10.c index 5c62612646..4e9e2bcfa5 100644 --- a/gfx/drivers/d3d10.c +++ b/gfx/drivers/d3d10.c @@ -22,6 +22,7 @@ */ #define CINTERFACE +#define WIN32_LEAN_AND_MEAN #define COBJMACROS #include @@ -1336,7 +1337,7 @@ static bool d3d10_gfx_set_shader(void* data, &d3d10->pass[i].frame_count, /* FrameCount */ &d3d10->pass[i].frame_direction, /* FrameDirection */ &d3d10->pass[i].frame_time_delta,/* FrameTimeDelta */ - &d3d10->pass[i].original_fps, /* OriginalFPS */ + &d3d10->pass[i].original_fps, /* OriginalFPS */ &d3d10->pass[i].rotation, /* Rotation */ &d3d10->pass[i].core_aspect, /* OriginalAspect */ &d3d10->pass[i].core_aspect_rot, /* OriginalAspectRotated */ @@ -2324,28 +2325,23 @@ static bool d3d10_gfx_frame( d3d10_set_shader(context, &d3d10->pass[i].shader); if (d3d10->shader_preset->pass[i].frame_count_mod) - d3d10->pass[i].frame_count = + d3d10->pass[i].frame_count = frame_count % d3d10->shader_preset->pass[i].frame_count_mod; else - d3d10->pass[i].frame_count = frame_count; + d3d10->pass[i].frame_count = frame_count; #ifdef HAVE_REWIND - d3d10->pass[i].frame_direction = state_manager_frame_is_reversed() + d3d10->pass[i].frame_direction = state_manager_frame_is_reversed() ? -1 : 1; #else - d3d10->pass[i].frame_direction = 1; + d3d10->pass[i].frame_direction = 1; #endif - - d3d10->pass[i].frame_time_delta = video_driver_get_frame_time_delta_usec(); - - d3d10->pass[i].original_fps = video_driver_get_original_fps(); - - d3d10->pass[i].rotation = retroarch_get_rotation(); - - d3d10->pass[i].core_aspect = video_driver_get_core_aspect(); - - /* OriginalAspectRotated: return 1/aspect for 90 and 270 rotated content */ - d3d10->pass[i].core_aspect_rot = video_driver_get_core_aspect(); + d3d10->pass[i].frame_time_delta = (uint32_t)video_driver_get_frame_time_delta_usec(); + d3d10->pass[i].original_fps = video_driver_get_original_fps(); + d3d10->pass[i].rotation = retroarch_get_rotation(); + d3d10->pass[i].core_aspect = video_driver_get_core_aspect(); + /* OriginalAspectRotated: return 1 / aspect for 90 and 270 rotated content */ + d3d10->pass[i].core_aspect_rot = video_driver_get_core_aspect(); uint32_t rot = retroarch_get_rotation(); if (rot == 1 || rot == 3) d3d10->pass[i].core_aspect_rot = 1/d3d10->pass[i].core_aspect_rot; diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 143877e296..29e81d591d 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -1538,7 +1538,7 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const &d3d11->pass[i].frame_count, /* FrameCount */ &d3d11->pass[i].frame_direction, /* FrameDirection */ &d3d11->pass[i].frame_time_delta,/* FrameTimeDelta */ - &d3d11->pass[i].original_fps, /* OriginalFPS */ + &d3d11->pass[i].original_fps, /* OriginalFPS */ &d3d11->pass[i].rotation, /* Rotation */ &d3d11->pass[i].core_aspect, /* OriginalAspect */ &d3d11->pass[i].core_aspect_rot, /* OriginalAspectRotated */ @@ -3081,25 +3081,21 @@ static bool d3d11_gfx_frame( } if (d3d11->shader_preset->pass[i].frame_count_mod) - d3d11->pass[i].frame_count = + d3d11->pass[i].frame_count = frame_count % d3d11->shader_preset->pass[i].frame_count_mod; else - d3d11->pass[i].frame_count = frame_count; + d3d11->pass[i].frame_count = frame_count; #ifdef HAVE_REWIND - d3d11->pass[i].frame_direction = state_manager_frame_is_reversed() ? -1 : 1; + d3d11->pass[i].frame_direction = state_manager_frame_is_reversed() ? -1 : 1; #else - d3d11->pass[i].frame_direction = 1; + d3d11->pass[i].frame_direction = 1; #endif - d3d11->pass[i].frame_time_delta = video_driver_get_frame_time_delta_usec(); - - d3d11->pass[i].original_fps = video_driver_get_original_fps(); - - d3d11->pass[i].rotation = retroarch_get_rotation(); - - d3d11->pass[i].core_aspect = video_driver_get_core_aspect(); - - /* OriginalAspectRotated: return 1/aspect for 90 and 270 rotated content */ + d3d11->pass[i].frame_time_delta = (uint32_t)video_driver_get_frame_time_delta_usec(); + d3d11->pass[i].original_fps = video_driver_get_original_fps(); + d3d11->pass[i].rotation = retroarch_get_rotation(); + d3d11->pass[i].core_aspect = video_driver_get_core_aspect(); + /* OriginalAspectRotated: return 1 / aspect for 90 and 270 rotated content */ d3d11->pass[i].core_aspect_rot = video_driver_get_core_aspect(); uint32_t rot = retroarch_get_rotation(); if (rot == 1 || rot == 3) diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index 77bfd78d14..b9dcbe9923 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -22,6 +22,7 @@ */ #define CINTERFACE +#define WIN32_LEAN_AND_MEAN #include #include @@ -1725,7 +1726,7 @@ static bool d3d12_gfx_set_shader(void* data, enum rarch_shader_type type, const &d3d12->pass[i].frame_count, /* FrameCount */ &d3d12->pass[i].frame_direction, /* FrameDirection */ &d3d12->pass[i].frame_time_delta,/* FrameTimeDelta */ - &d3d12->pass[i].original_fps, /* OriginalFPS */ + &d3d12->pass[i].original_fps, /* OriginalFPS */ &d3d12->pass[i].rotation, /* Rotation */ &d3d12->pass[i].core_aspect, /* OriginalAspect */ &d3d12->pass[i].core_aspect_rot, /* OriginalAspectRotated */ @@ -2373,11 +2374,11 @@ static bool d3d12_init_swapchain(d3d12_video_t* d3d12, if (max_latency == 0) { - d3d12->flags |= D3D12_ST_FLAG_WAIT_FOR_VBLANK; - max_latency = 1; + d3d12->flags |= D3D12_ST_FLAG_WAIT_FOR_VBLANK; + max_latency = 1; } else - d3d12->flags &= ~D3D12_ST_FLAG_WAIT_FOR_VBLANK; + d3d12->flags &= ~D3D12_ST_FLAG_WAIT_FOR_VBLANK; DXGISetMaximumFrameLatency(d3d12->chain.handle, max_latency); DXGIGetMaximumFrameLatency(d3d12->chain.handle, &cur_latency); @@ -2911,7 +2912,8 @@ static void *d3d12_gfx_init(const video_info_t* video, else d3d12->flags &= ~D3D12_ST_FLAG_WAITABLE_SWAPCHAINS; - d3d_input_driver(settings->arrays.input_driver, settings->arrays.input_joypad_driver, input, input_data); + d3d_input_driver(settings->arrays.input_driver, + settings->arrays.input_joypad_driver, input, input_data); d3d12_init_base(d3d12); d3d12_init_descriptors(d3d12); @@ -3513,7 +3515,7 @@ static bool d3d12_gfx_frame( if (d3d12->flags & D3D12_ST_FLAG_RESIZE_RTS) d3d12_init_render_targets(d3d12, width, height); - if(frame == RETRO_HW_FRAME_BUFFER_VALID) + if (frame == RETRO_HW_FRAME_BUFFER_VALID) { D3D12_BOX src_box; D3D12_TEXTURE_COPY_LOCATION src, dst; @@ -3595,21 +3597,16 @@ static bool d3d12_gfx_frame( d3d12->pass[i].frame_direction = -1; else #endif - d3d12->pass[i].frame_direction = 1; - - d3d12->pass[i].frame_time_delta = video_driver_get_frame_time_delta_usec(); - - d3d12->pass[i].original_fps = video_driver_get_original_fps(); - - d3d12->pass[i].rotation = retroarch_get_rotation(); - - d3d12->pass[i].core_aspect = video_driver_get_core_aspect(); - - /* OriginalAspectRotated: return 1/aspect for 90 and 270 rotated content */ - d3d12->pass[i].core_aspect_rot = video_driver_get_core_aspect(); + d3d12->pass[i].frame_direction = 1; + d3d12->pass[i].frame_time_delta = (uint32_t)video_driver_get_frame_time_delta_usec(); + d3d12->pass[i].original_fps = video_driver_get_original_fps(); + d3d12->pass[i].rotation = retroarch_get_rotation(); + d3d12->pass[i].core_aspect = video_driver_get_core_aspect(); + /* OriginalAspectRotated: return 1 / aspect for 90 and 270 rotated content */ + d3d12->pass[i].core_aspect_rot = video_driver_get_core_aspect(); uint32_t rot = retroarch_get_rotation(); if (rot == 1 || rot == 3) - d3d12->pass[i].core_aspect_rot = 1/d3d12->pass[i].core_aspect_rot; + d3d12->pass[i].core_aspect_rot = 1 / d3d12->pass[i].core_aspect_rot; /* Sub-frame info for multiframe shaders (per real content frame). Should always be 1 for non-use of subframes */ diff --git a/gfx/drivers/gl2.c b/gfx/drivers/gl2.c index 16dd269331..247667865d 100644 --- a/gfx/drivers/gl2.c +++ b/gfx/drivers/gl2.c @@ -185,9 +185,8 @@ enum gl2_renderchain_flags { GL2_CHAIN_FLAG_EGL_IMAGES = (1 << 0), GL2_CHAIN_FLAG_HAS_FP_FBO = (1 << 1), - GL2_CHAIN_FLAG_HAS_SRGB_FBO_GLES3 = (1 << 2), - GL2_CHAIN_FLAG_HAS_SRGB_FBO = (1 << 3), - GL2_CHAIN_FLAG_HW_RENDER_DEPTH_INIT = (1 << 4) + GL2_CHAIN_FLAG_HAS_SRGB_FBO = (1 << 2), + GL2_CHAIN_FLAG_HW_RENDER_DEPTH_INIT = (1 << 3) }; typedef struct video_shader_ctx_scale @@ -321,7 +320,8 @@ static const GLfloat white_color[16] = { */ static void gl2_set_viewport(gl2_t *gl, unsigned vp_width, unsigned vp_height, - bool force_full, bool allow_rotate); + bool force_full, bool allow_rotate, + bool video_scale_integer); #ifdef IOS /* There is no default frame buffer on iOS. */ @@ -944,9 +944,10 @@ static void gl2_raster_font_setup_viewport( gl2_t *gl, gl2_raster_t *font, unsigned width, unsigned height, - bool full_screen) + bool full_screen, + bool video_scale_integer) { - gl2_set_viewport(gl, width, height, full_screen, true); + gl2_set_viewport(gl, width, height, full_screen, true, video_scale_integer); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -974,6 +975,7 @@ static void gl2_raster_font_render_msg( gl2_t *gl = (gl2_t*)userdata; unsigned width = gl->video_width; unsigned height = gl->video_height; + bool video_scale_integer = config_get_ptr()->bools.video_scale_integer; if (!font || string_is_empty(msg) || !gl) return; @@ -1027,7 +1029,8 @@ static void gl2_raster_font_render_msg( if (font->block) font->block->fullscreen = full_screen; else - gl2_raster_font_setup_viewport(gl, font, width, height, full_screen); + gl2_raster_font_setup_viewport(gl, font, width, height, full_screen, + config_get_ptr()->bools.video_scale_integer); if ( !string_is_empty(msg) && font->font_data @@ -1056,7 +1059,7 @@ static void gl2_raster_font_render_msg( /* Restore viewport */ glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]); glDisable(GL_BLEND); - gl2_set_viewport(gl, width, height, false, true); + gl2_set_viewport(gl, width, height, false, true, video_scale_integer); } } @@ -1075,18 +1078,20 @@ static void gl2_raster_font_flush_block(unsigned width, unsigned height, gl2_raster_t *font = (gl2_raster_t*)data; video_font_raster_block_t *block = font ? font->block : NULL; gl2_t *gl = font ? font->gl : NULL; + bool video_scale_integer = config_get_ptr()->bools.video_scale_integer; if (!font || !block || !block->carr.coords.vertices || !gl) return; - gl2_raster_font_setup_viewport(gl, font, width, height, block->fullscreen); + gl2_raster_font_setup_viewport(gl, font, width, height, block->fullscreen, + video_scale_integer); gl2_raster_font_draw_vertices(gl, font, (video_coords_t*)&block->carr.coords); /* Restore viewport */ glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]); glDisable(GL_BLEND); - gl2_set_viewport(gl, width, height, block->fullscreen, true); + gl2_set_viewport(gl, width, height, block->fullscreen, true, video_scale_integer); } static void gl2_raster_font_bind_block(void *data, void *userdata) @@ -1269,16 +1274,16 @@ static void gl2_set_projection(gl2_t *gl, static void gl2_set_viewport(gl2_t *gl, unsigned vp_width, unsigned vp_height, - bool force_full, bool allow_rotate) + bool force_full, bool allow_rotate, + bool video_scale_integer) { - settings_t *settings = config_get_ptr(); float device_aspect = (float)vp_width / (float)vp_height; if (gl->ctx_driver->translate_aspect) device_aspect = gl->ctx_driver->translate_aspect( gl->ctx_data, vp_width, vp_height); - if (settings->bools.video_scale_integer && !force_full) + if (video_scale_integer && !force_full) { video_viewport_get_scaled_integer(&gl->vp, vp_width, vp_height, @@ -1323,7 +1328,8 @@ static void gl2_renderchain_render( gl2_renderchain_data_t *chain, uint64_t frame_count, const struct video_tex_info *tex_info, - const struct video_tex_info *feedback_info) + const struct video_tex_info *feedback_info, + bool video_scale_integer) { int i; video_shader_ctx_params_t params; @@ -1380,7 +1386,8 @@ static void gl2_renderchain_render( /* Render to FBO with certain size. */ gl2_set_viewport(gl, - rect->img_width, rect->img_height, true, false); + rect->img_width, rect->img_height, true, false, + video_scale_integer); params.data = gl; params.width = prev_rect->img_width; @@ -1445,8 +1452,7 @@ static void gl2_renderchain_render( glGenerateMipmap(GL_TEXTURE_2D); glClear(GL_COLOR_BUFFER_BIT); - gl2_set_viewport(gl, - width, height, false, true); + gl2_set_viewport(gl, width, height, false, true, video_scale_integer); params.data = gl; params.width = prev_rect->img_width; @@ -1603,22 +1609,13 @@ static GLenum gl2_min_filter_to_mag(GLenum type) static void gl2_create_fbo_texture(gl2_t *gl, gl2_renderchain_data_t *chain, - unsigned i, GLuint texture) + unsigned i, GLuint texture, + bool video_smooth, bool force_srgb_disable) { GLenum mag_filter, wrap_enum; enum gfx_wrap_type wrap_type; bool fp_fbo = false; bool smooth = false; - settings_t *settings = config_get_ptr(); - bool video_smooth = settings->bools.video_smooth; -#if HAVE_ODROIDGO2 - bool video_ctx_scaling = settings->bools.video_ctx_scaling; - if (video_ctx_scaling) - video_smooth = false; -#endif -#ifndef HAVE_OPENGLES - bool force_srgb_disable = settings->bools.video_force_srgb_disable; -#endif GLuint base_filt = video_smooth ? GL_LINEAR : GL_NEAREST; GLuint base_mip_filt = video_smooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; @@ -1650,19 +1647,21 @@ static void gl2_create_fbo_texture(gl2_t *gl, RARCH_ERR("[GL]: Floating-point FBO was requested, but is not supported. Falling back to UNORM. Result may band/clip/etc.!\n"); } -#if !defined(HAVE_OPENGLES2) if ( fp_fbo && (chain->flags & GL2_CHAIN_FLAG_HAS_FP_FBO)) { RARCH_LOG("[GL]: FBO pass #%d is floating-point.\n", i); - gl2_load_texture_image(GL_TEXTURE_2D, 0, GL_RGBA32F, + gl2_load_texture_image(GL_TEXTURE_2D, 0, +#ifdef HAVE_OPENGLES2 + GL_RGBA, +#else + GL_RGBA32F, +#endif gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, GL_RGBA, GL_FLOAT, NULL); } else -#endif { -#ifndef HAVE_OPENGLES bool srgb_fbo = (chain->fbo_scale[i].flags & FBO_SCALE_FLAG_SRGB_FBO) ? true : false; if (!fp_fbo && srgb_fbo) @@ -1678,27 +1677,23 @@ static void gl2_create_fbo_texture(gl2_t *gl, && (chain->flags & GL2_CHAIN_FLAG_HAS_SRGB_FBO)) { RARCH_LOG("[GL]: FBO pass #%d is sRGB.\n", i); + gl2_load_texture_image(GL_TEXTURE_2D, 0, #ifdef HAVE_OPENGLES2 - /* EXT defines are same as core GLES3 defines, - * but GLES3 variant requires different arguments. */ - glTexImage2D(GL_TEXTURE_2D, - 0, GL_SRGB_ALPHA_EXT, - gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, - (chain->flags & GL2_CHAIN_FLAG_HAS_SRGB_FBO_GLES3) - ? GL_RGBA - : GL_SRGB_ALPHA_EXT, - GL_UNSIGNED_BYTE, NULL); + GL_SRGB_ALPHA_EXT, #else - gl2_load_texture_image(GL_TEXTURE_2D, - 0, GL_SRGB8_ALPHA8, - gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); + GL_SRGB8_ALPHA8, #endif + gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, +#ifdef HAVE_OPENGLES2 + GL_SRGB_ALPHA_EXT, +#else + GL_RGBA, +#endif + GL_UNSIGNED_BYTE, NULL); } else -#endif { -#if defined(HAVE_OPENGLES2) +#if defined(HAVE_OPENGLES) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, @@ -1724,20 +1719,29 @@ static void gl2_create_fbo_textures(gl2_t *gl, gl2_renderchain_data_t *chain) { int i; + settings_t *settings = config_get_ptr(); +#if HAVE_ODROIDGO2 + bool video_smooth = settings->bools.video_ctx_scaling ? false : settings->bools.video_smooth; +#else + bool video_smooth = settings->bools.video_smooth; +#endif + bool force_srgb_disable = settings->bools.video_force_srgb_disable; glGenTextures(chain->fbo_pass, chain->fbo_texture); for (i = 0; i < chain->fbo_pass; i++) gl2_create_fbo_texture(gl, (gl2_renderchain_data_t*)gl->renderchain_data, - i, chain->fbo_texture[i]); + i, chain->fbo_texture[i], + video_smooth, force_srgb_disable); if (gl->flags & GL2_FLAG_FBO_FEEDBACK_ENABLE) { glGenTextures(1, &gl->fbo_feedback_texture); gl2_create_fbo_texture(gl, (gl2_renderchain_data_t*)gl->renderchain_data, - gl->fbo_feedback_pass, gl->fbo_feedback_texture); + gl->fbo_feedback_pass, gl->fbo_feedback_texture, + video_smooth, force_srgb_disable); } glBindTexture(GL_TEXTURE_2D, 0); @@ -1847,9 +1851,8 @@ static void gl2_renderchain_recompute_pass_sizes( } } -static void gl2_renderchain_start_render( - gl2_t *gl, - gl2_renderchain_data_t *chain) +static void gl2_renderchain_start_render(gl2_t *gl, + gl2_renderchain_data_t *chain, bool video_scale_integer) { /* Used when rendering to an FBO. * Texture coords have to be aligned @@ -1865,7 +1868,8 @@ static void gl2_renderchain_start_render( gl2_set_viewport(gl, gl->fbo_rect[0].img_width, - gl->fbo_rect[0].img_height, true, false); + gl->fbo_rect[0].img_height, true, false, + video_scale_integer); /* Need to preserve the "flipped" state when in FBO * as well to have consistent texture coordinates. @@ -2479,11 +2483,6 @@ static void gl2_renderchain_resolve_extensions(gl2_t *gl, chain->flags |= GL2_CHAIN_FLAG_HAS_FP_FBO; else chain->flags &= ~GL2_CHAIN_FLAG_HAS_FP_FBO; - /* GLES3 has unpack_subimage and sRGB in core. */ - if (gl_check_capability(GL_CAPS_SRGB_FBO_ES3)) - chain->flags |= GL2_CHAIN_FLAG_HAS_SRGB_FBO_GLES3; - else - chain->flags &= ~GL2_CHAIN_FLAG_HAS_SRGB_FBO_GLES3; if (!force_srgb_disable) { @@ -2769,7 +2768,10 @@ static void gl2_set_viewport_wrapper(void *data, unsigned vp_width, unsigned vp_height, bool force_full, bool allow_rotate) { gl2_t *gl = (gl2_t*)data; - gl2_set_viewport(gl, vp_width, vp_height, force_full, allow_rotate); + gl2_set_viewport(gl, + vp_width, vp_height, force_full, allow_rotate, + config_get_ptr()->bools.video_scale_integer + ); } /* Shaders */ @@ -3094,7 +3096,7 @@ static void gl2_init_textures(gl2_t *gl) glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]); } -static INLINE void gl2_set_shader_viewports(gl2_t *gl) +static INLINE void gl2_set_shader_viewports(gl2_t *gl, bool video_scale_integer) { int i; unsigned width = gl->video_width; @@ -3103,7 +3105,8 @@ static INLINE void gl2_set_shader_viewports(gl2_t *gl) for (i = 0; i < 2; i++) { gl->shader->use(gl, gl->shader_data, i, true); - gl2_set_viewport(gl, width, height, false, true); + gl2_set_viewport(gl, width, height, false, true, + video_scale_integer); } } @@ -3157,7 +3160,7 @@ static void gl2_set_texture_enable(void *data, bool state, bool full_screen) gl->flags &= ~GL2_FLAG_MENU_TEXTURE_FULLSCREEN; } -static void gl2_render_osd_background(gl2_t *gl, const char *msg) +static void gl2_render_osd_background(gl2_t *gl, bool video_scale_integer, const char *msg) { video_coords_t coords; struct uniform_info uniform_param; @@ -3184,9 +3187,9 @@ static void gl2_render_osd_background(gl2_t *gl, const char *msg) width += x2; height += y2; - colors[0] = settings->uints.video_msg_bgcolor_red / 255.0f; + colors[0] = settings->uints.video_msg_bgcolor_red / 255.0f; colors[1] = settings->uints.video_msg_bgcolor_green / 255.0f; - colors[2] = settings->uints.video_msg_bgcolor_blue / 255.0f; + colors[2] = settings->uints.video_msg_bgcolor_blue / 255.0f; colors[3] = settings->floats.video_msg_bgcolor_opacity; /* triangle 1 */ @@ -3217,7 +3220,8 @@ static void gl2_render_osd_background(gl2_t *gl, const char *msg) gl2_set_viewport(gl, gl->video_width, - gl->video_height, true, false); + gl->video_height, true, false, + video_scale_integer); gl->shader->use(gl, gl->shader_data, VIDEO_SHADER_STOCK_BLEND, true); @@ -3265,7 +3269,7 @@ static void gl2_render_osd_background(gl2_t *gl, const char *msg) gl2_set_viewport(gl, gl->video_width, - gl->video_height, false, true); + gl->video_height, false, true, video_scale_integer); } static void gl2_show_mouse(void *data, bool state) @@ -3394,6 +3398,7 @@ static bool gl2_frame(void *data, const void *frame, bool widgets_active = video_info->widgets_active; #endif bool overlay_behind_menu = video_info->overlay_behind_menu; + bool video_scale_integer = config_get_ptr()->bools.video_scale_integer; if (!gl) return false; @@ -3410,7 +3415,7 @@ static bool gl2_frame(void *data, const void *frame, #ifdef IOS /* Apparently the viewport is lost each frame, thanks Apple. */ - gl2_set_viewport(gl, width, height, false, true); + gl2_set_viewport(gl, width, height, false, true, video_scale_integer); #endif /* Render to texture in first pass. */ @@ -3421,7 +3426,7 @@ static bool gl2_frame(void *data, const void *frame, frame_width, frame_height, gl->out_vp_width, gl->out_vp_height); - gl2_renderchain_start_render(gl, chain); + gl2_renderchain_start_render(gl, chain, video_scale_integer); } if (gl->flags & GL2_FLAG_SHOULD_RESIZE) @@ -3482,10 +3487,10 @@ static bool gl2_frame(void *data, const void *frame, /* Go back to what we're supposed to do, * render to FBO #0. */ - gl2_renderchain_start_render(gl, chain); + gl2_renderchain_start_render(gl, chain, video_scale_integer); } else - gl2_set_viewport(gl, width, height, false, true); + gl2_set_viewport(gl, width, height, false, true, video_scale_integer); } if (frame) @@ -3519,7 +3524,7 @@ static bool gl2_frame(void *data, const void *frame, if (!(gl->flags & GL2_FLAG_FBO_INITED)) { gl2_renderchain_bind_backbuffer(); - gl2_set_viewport(gl, width, height, false, true); + gl2_set_viewport(gl, width, height, false, true, video_scale_integer); } gl2_renderchain_restore_default_state(gl); @@ -3583,7 +3588,8 @@ static bool gl2_frame(void *data, const void *frame, if (gl->flags & GL2_FLAG_FBO_INITED) gl2_renderchain_render(gl, chain, - frame_count, &gl->tex_info, &feedback_info); + frame_count, &gl->tex_info, &feedback_info, + video_scale_integer); /* Set prev textures. */ gl2_renderchain_bind_prev_texture(gl, @@ -3623,7 +3629,7 @@ static bool gl2_frame(void *data, const void *frame, if (!string_is_empty(msg)) { if (msg_bgcolor_enable) - gl2_render_osd_background(gl, msg); + gl2_render_osd_background(gl, video_scale_integer, msg); font_driver_render_msg(gl, msg, NULL, NULL); } @@ -3892,7 +3898,6 @@ static bool gl2_resolve_extensions(gl2_t *gl, const char *context_ident, const v RARCH_WARN("[GL]: GLES implementation does not have BGRA8888 extension.\n" "[GL]: 32-bit path will require conversion.\n"); } - /* TODO/FIXME - No extensions for float FBO currently. */ #endif #ifdef GL_DEBUG @@ -4204,6 +4209,7 @@ static void *gl2_init(const video_info_t *video, unsigned shader_info_num; settings_t *settings = config_get_ptr(); bool video_gpu_record = settings->bools.video_gpu_record; + bool video_scale_integer = settings->bools.video_scale_integer; int interval = 0; unsigned mip_level = 0; unsigned mode_width = 0; @@ -4512,7 +4518,7 @@ static void *gl2_init(const video_info_t *video, #endif /* Apparently need to set viewport for passes * when we aren't using FBOs. */ - gl2_set_shader_viewports(gl); + gl2_set_shader_viewports(gl, video_scale_integer); mip_level = 1; if (gl->shader->mipmap_input(gl->shader_data, mip_level)) @@ -4548,9 +4554,9 @@ static void *gl2_init(const video_info_t *video, /* Empty buffer that we use to clear out * the texture with on res change. */ - gl->empty_buf = calloc(sizeof(uint32_t), gl->tex_w * gl->tex_h); + gl->empty_buf = calloc(gl->tex_w * gl->tex_h, sizeof(uint32_t)); - gl->conv_buffer = calloc(sizeof(uint32_t), gl->tex_w * gl->tex_h); + gl->conv_buffer = calloc(gl->tex_w * gl->tex_h, sizeof(uint32_t)); if (!gl->conv_buffer) goto error; @@ -4668,20 +4674,13 @@ static bool gl2_suppress_screensaver(void *data, bool enable) return false; } -static void gl2_update_tex_filter_frame(gl2_t *gl) +static void gl2_update_tex_filter_frame(gl2_t *gl, bool video_smooth) { unsigned i, mip_level; GLenum wrap_mode; GLuint new_filt; enum gfx_wrap_type wrap_type; bool smooth = false; - settings_t *settings = config_get_ptr(); - bool video_smooth = settings->bools.video_smooth; -#ifdef HAVE_ODROIDGO2 - bool video_ctx_scaling = settings->bools.video_ctx_scaling; - if (video_ctx_scaling) - video_smooth = false; -#endif if (gl->flags & GL2_FLAG_SHARED_CONTEXT_USE) gl->ctx_driver->bind_hw_render(gl->ctx_data, false); @@ -4730,7 +4729,14 @@ static bool gl2_set_shader(void *data, unsigned textures; video_shader_ctx_init_t init_data; enum rarch_shader_type fallback; - gl2_t *gl = (gl2_t*)data; + gl2_t *gl = (gl2_t*)data; + settings_t *settings = config_get_ptr(); + bool video_scale_integer = settings->bools.video_scale_integer; +#ifdef HAVE_ODROIDGO2 + bool video_smooth = settings->bools.video_ctx_scaling ? false : settings->bools.video_smooth; +#else + bool video_smooth = settings->bools.video_smooth; +#endif if (!gl) return false; @@ -4788,7 +4794,7 @@ static bool gl2_set_shader(void *data, gl->shader = init_data.shader; gl->shader_data = init_data.shader_data; - gl2_update_tex_filter_frame(gl); + gl2_update_tex_filter_frame(gl, video_smooth); { unsigned texture_info_id = gl->shader->get_prev_textures(gl->shader_data); @@ -4823,7 +4829,7 @@ static bool gl2_set_shader(void *data, gl->tex_w, gl->tex_h); /* Apparently need to set viewport for passes when we aren't using FBOs. */ - gl2_set_shader_viewports(gl); + gl2_set_shader_viewports(gl, video_scale_integer); if (gl->flags & GL2_FLAG_SHARED_CONTEXT_USE) gl->ctx_driver->bind_hw_render(gl->ctx_data, true); diff --git a/gfx/drivers/gl3.c b/gfx/drivers/gl3.c index 4d9e849f41..5d7bef3332 100644 --- a/gfx/drivers/gl3.c +++ b/gfx/drivers/gl3.c @@ -282,12 +282,12 @@ uint32_t gl3_get_cross_compiler_target_version(void) return 100 * major + 10 * minor; } -static void gl3_bind_scratch_vbo(gl3_t *gl, const void *data, size_t size) +static void gl3_bind_scratch_vbo(gl3_t *gl, const void *data, size_t len) { if (!gl->scratch_vbos[gl->scratch_vbo_index]) glGenBuffers(1, &gl->scratch_vbos[gl->scratch_vbo_index]); glBindBuffer(GL_ARRAY_BUFFER, gl->scratch_vbos[gl->scratch_vbo_index]); - glBufferData(GL_ARRAY_BUFFER, size, data, GL_STREAM_DRAW); + glBufferData(GL_ARRAY_BUFFER, len, data, GL_STREAM_DRAW); gl->scratch_vbo_index++; if (gl->scratch_vbo_index >= GL_CORE_NUM_VBOS) gl->scratch_vbo_index = 0; @@ -2740,7 +2740,7 @@ static bool gl3_frame(void *data, const void *frame, #else gl3_filter_chain_set_frame_direction(gl->filter_chain, 1); #endif - gl3_filter_chain_set_frame_time_delta(gl->filter_chain, video_driver_get_frame_time_delta_usec()); + gl3_filter_chain_set_frame_time_delta(gl->filter_chain, (uint32_t)video_driver_get_frame_time_delta_usec()); gl3_filter_chain_set_original_fps(gl->filter_chain, video_driver_get_original_fps()); diff --git a/gfx/drivers/gl_shaders/pipeline_snow.glsl.vert.h b/gfx/drivers/gl_shaders/pipeline_snow.glsl.vert.h index 0ebbf254dd..205cb6a5cd 100644 --- a/gfx/drivers/gl_shaders/pipeline_snow.glsl.vert.h +++ b/gfx/drivers/gl_shaders/pipeline_snow.glsl.vert.h @@ -1,5 +1,6 @@ #include "shaders_common.h" +#if defined(HAVE_OPENGLES) /* Need to duplicate these to work around broken stuff on Android. * Must enforce alpha = 1.0 or 32-bit games can potentially go black. */ static const char *stock_vertex_xmb_snow = GLSL( @@ -14,3 +15,4 @@ static const char *stock_vertex_xmb_snow = GLSL( tex_coord = TexCoord; } ); +#endif diff --git a/gfx/drivers/gl_shaders/pipeline_snowflake.glsl.frag.h b/gfx/drivers/gl_shaders/pipeline_snowflake.glsl.frag.h index 64ed81a0f7..db69949c0b 100644 --- a/gfx/drivers/gl_shaders/pipeline_snowflake.glsl.frag.h +++ b/gfx/drivers/gl_shaders/pipeline_snowflake.glsl.frag.h @@ -28,17 +28,13 @@ static const char* stock_fragment_xmb_snowflake = GLSL( float dist = d.x*d.x + d.y*d.y; - if(dist < pos.z/400.0) + if (dist < pos.z/400.0) { float col = 0.0; - if(sin(a * 8.0) < 0.0) - { + if (sin(a * 8.0) < 0.0) col=1.0; - } - if(dist < pos.z/800.0) - { + if (dist < pos.z/800.0) col+=1.0; - } return col * pos.z; } diff --git a/gfx/drivers/gx2_gfx.c b/gfx/drivers/gx2_gfx.c index 2ac624afbe..14fed4f7cf 100644 --- a/gfx/drivers/gx2_gfx.c +++ b/gfx/drivers/gx2_gfx.c @@ -1661,7 +1661,7 @@ static bool wiiu_init_frame_textures(wiiu_video_t *wiiu, unsigned width, unsigne } static void gx2_update_uniform_block(wiiu_video_t *wiiu, - int pass, float *ubo, int id, + int pass, float *ubo, int chosen_id, int size, int uniformVarCount, GX2UniformVar *uniformVars, uint64_t frame_count, int32_t frame_direction, uint32_t rotation, float core_aspect, float core_aspect_rot, uint32_t frame_time_delta, uint32_t original_fps) @@ -1672,7 +1672,7 @@ static void gx2_update_uniform_block(wiiu_video_t *wiiu, int k; float *dst; const char *id = NULL; - if (uniformVars[i].block != id) + if (uniformVars[i].block != chosen_id) continue; if (!(id = strrchr(uniformVars[i].name, '.'))) continue; @@ -1958,23 +1958,18 @@ static bool gx2_frame(void *data, const void *frame, { unsigned i; #ifdef HAVE_REWIND - int32_t frame_direction = state_manager_frame_is_reversed() ? -1 : 1; + int32_t frame_direction = state_manager_frame_is_reversed() ? -1 : 1; #else - int32_t frame_direction = 1; + int32_t frame_direction = 1; #endif - - uint32_t frame_time_delta = video_driver_get_frame_time_delta_usec(); - - float original_fps = video_driver_get_original_fps(); - - uint32_t rotation = retroarch_get_rotation(); - - float core_aspect = video_driver_get_core_aspect(); - + uint32_t frame_time_delta = (uint32_t)video_driver_get_frame_time_delta_usec(); + float original_fps = video_driver_get_original_fps(); + uint32_t rotation = retroarch_get_rotation(); + float core_aspect = video_driver_get_core_aspect(); /* OriginalAspectRotated: return 1/aspect for 90 and 270 rotated content */ - float core_aspect_rot = core_aspect; + float core_aspect_rot = core_aspect; if (rotation == 1 || rotation == 3) - core_aspect_rot = 1/core_aspect; + core_aspect_rot = 1 / core_aspect; for (i = 0; i < wiiu->shader_preset->passes; i++) { @@ -1986,7 +1981,8 @@ static bool gx2_frame(void *data, const void *frame, gx2_update_uniform_block(wiiu, i, wiiu->pass[i].vs_ubos[j], j, wiiu->pass[i].gfd->vs->uniformBlocks[j].size, wiiu->pass[i].gfd->vs->uniformVarCount, wiiu->pass[i].gfd->vs->uniformVars, - frame_count, frame_direction, rotation, core_aspect, core_aspect_rot,frame_time_delta, original_fps); + frame_count, frame_direction, rotation, core_aspect, core_aspect_rot, + frame_time_delta, original_fps); GX2SetVertexUniformBlock(wiiu->pass[i].gfd->vs->uniformBlocks[j].offset, wiiu->pass[i].gfd->vs->uniformBlocks[j].size, wiiu->pass[i].vs_ubos[j]); @@ -1999,7 +1995,8 @@ static bool gx2_frame(void *data, const void *frame, gx2_update_uniform_block(wiiu, i, wiiu->pass[i].ps_ubos[j], j, wiiu->pass[i].gfd->ps->uniformBlocks[j].size, wiiu->pass[i].gfd->ps->uniformVarCount, wiiu->pass[i].gfd->ps->uniformVars, - frame_count, frame_direction, rotation, core_aspect, core_aspect_rot,frame_time_delta, original_fps); + frame_count, frame_direction, rotation, core_aspect, core_aspect_rot, + frame_time_delta, original_fps); GX2SetPixelUniformBlock(wiiu->pass[i].gfd->ps->uniformBlocks[j].offset, wiiu->pass[i].gfd->ps->uniformBlocks[j].size, wiiu->pass[i].ps_ubos[j]); } diff --git a/gfx/drivers/gx2_shaders/bokeh.frag b/gfx/drivers/gx2_shaders/bokeh.frag index 29a8d48116..5462baab42 100644 --- a/gfx/drivers/gx2_shaders/bokeh.frag +++ b/gfx/drivers/gx2_shaders/bokeh.frag @@ -11,26 +11,25 @@ layout(location = 0) out vec4 FragColor; void main(void) { + float speed = global.time * 4.0; + vec2 uv = -1.0 + 2.0 * gl_FragCoord.xy / global.OutputSize; + uv.x *= global.OutputSize.x / global.OutputSize.y; + vec3 color = vec3(0.0); - float speed = global.time * 4.0; - vec2 uv = -1.0 + 2.0 * gl_FragCoord.xy / global.OutputSize; - uv.x *= global.OutputSize.x / global.OutputSize.y; - vec3 color = vec3(0.0); - -for( int i=0; i < 6; i++ ) + for( int i=0; i < 6; i++ ) + { + float pha = sin(float(i) * 546.13 + 1.0) * 0.5 + 0.5; + float siz = pow(sin(float(i) * 651.74 + 5.0) * 0.5 + 0.5, 4.0); + float pox = sin(float(i) * 321.55 + 4.1) * global.OutputSize.x / global.OutputSize.y; + float rad = 0.1 + 0.5 * siz + sin(pha + siz) / 4.0; + vec2 pos = vec2(pox + sin(speed / 15. + pha + siz), - 1.0 - rad + (2.0 + 2.0 * rad) * fract(pha + 0.3 * (speed / 7.) * (0.2 + 0.8 * siz))); + float dis = length(uv - pos); + if (dis < rad) { - float pha = sin(float(i) * 546.13 + 1.0) * 0.5 + 0.5; - float siz = pow(sin(float(i) * 651.74 + 5.0) * 0.5 + 0.5, 4.0); - float pox = sin(float(i) * 321.55 + 4.1) * global.OutputSize.x / global.OutputSize.y; - float rad = 0.1 + 0.5 * siz + sin(pha + siz) / 4.0; - vec2 pos = vec2(pox + sin(speed / 15. + pha + siz), - 1.0 - rad + (2.0 + 2.0 * rad) * fract(pha + 0.3 * (speed / 7.) * (0.2 + 0.8 * siz))); - float dis = length(uv - pos); - if(dis < rad) - { - vec3 col = mix(vec3(0.194 * sin(speed / 6.0) + 0.3, 0.2, 0.3 * pha), vec3(1.1 * sin(speed / 9.0) + 0.3, 0.2 * pha, 0.4), 0.5 + 0.5 * sin(float(i))); - color += col.zyx * (1.0 - smoothstep(rad * 0.15, rad, dis)); - } + vec3 col = mix(vec3(0.194 * sin(speed / 6.0) + 0.3, 0.2, 0.3 * pha), vec3(1.1 * sin(speed / 9.0) + 0.3, 0.2 * pha, 0.4), 0.5 + 0.5 * sin(float(i))); + color += col.zyx * (1.0 - smoothstep(rad * 0.15, rad, dis)); } - color *= sqrt(1.5 - 0.5 * length(uv)); + } + color *= sqrt(1.5 - 0.5 * length(uv)); FragColor = vec4(color.r, color.g, color.b , 0.5); } diff --git a/gfx/drivers/gx2_shaders/snowflake.frag b/gfx/drivers/gx2_shaders/snowflake.frag index a3934e4f24..a8bf1db107 100644 --- a/gfx/drivers/gx2_shaders/snowflake.frag +++ b/gfx/drivers/gx2_shaders/snowflake.frag @@ -29,17 +29,13 @@ float snow(vec3 pos, vec2 uv, float o) float dist = d.x*d.x + d.y*d.y; - if(dist < pos.z/400.0) + if (dist < pos.z/400.0) { float col = 0.0; if(sin(a * 8.0) < 0.0) - { col=1.0; - } if(dist < pos.z/800.0) - { col+=1.0; - } return col * pos.z; } diff --git a/gfx/drivers/gx_gfx.c b/gfx/drivers/gx_gfx.c index da7fce023e..baca247fc0 100644 --- a/gfx/drivers/gx_gfx.c +++ b/gfx/drivers/gx_gfx.c @@ -74,6 +74,9 @@ } #endif +void VIDEO_SetTrapFilter(bool enable); +void VIDEO_SetGamma(int gamma); + enum { GX_RESOLUTIONS_DEFAULT = 0, @@ -742,8 +745,8 @@ static void init_vtx(gx_video_t *gx, const video_info_t *video, } } - DCFlushRange(g_tex.data, ((g_tex.width * - g_tex.height) * video->rgb32) ? 4 : 2); + DCFlushRange(g_tex.data, g_tex.width * g_tex.height * + (video->rgb32 ? 4 : 2)); gx->rgb32 = video->rgb32; gx->scale = video->input_scale; diff --git a/gfx/drivers/metal.m b/gfx/drivers/metal.m index 9916dcd322..53b4eee15b 100644 --- a/gfx/drivers/metal.m +++ b/gfx/drivers/metal.m @@ -1578,23 +1578,19 @@ typedef struct MTLALIGN(16) _engine.pass[i].frame_direction = -1; else #else - _engine.pass[i].frame_direction = 1; + _engine.pass[i].frame_direction = 1; #endif + _engine.pass[i].frame_time_delta = (uint32_t)video_driver_get_frame_time_delta_usec(); + _engine.pass[i].original_fps = video_driver_get_original_fps(); + _engine.pass[i].rotation = retroarch_get_rotation(); + _engine.pass[i].core_aspect = video_driver_get_core_aspect(); - _engine.pass[i].frame_time_delta = video_driver_get_frame_time_delta_usec(); - - _engine.pass[i].original_fps = video_driver_get_original_fps(); - - _engine.pass[i].rotation = retroarch_get_rotation(); - - _engine.pass[i].core_aspect = video_driver_get_core_aspect(); - - /* OriginalAspectRotated: return 1/aspect for 90 and 270 rotated content */ - int rot = retroarch_get_rotation(); - float core_aspect_rot = video_driver_get_core_aspect(); + /* OriginalAspectRotated: return 1 / aspect for 90 and 270 rotated content */ + int rot = retroarch_get_rotation(); + float core_aspect_rot = video_driver_get_core_aspect(); if (rot == 1 || rot == 3) - core_aspect_rot = 1/core_aspect_rot; - _engine.pass[i].core_aspect_rot = core_aspect_rot; + core_aspect_rot = 1 / core_aspect_rot; + _engine.pass[i].core_aspect_rot = core_aspect_rot; for (j = 0; j < SLANG_CBUFFER_MAX; j++) { diff --git a/gfx/drivers/omap_gfx.c b/gfx/drivers/omap_gfx.c index 517f4b410e..6c0beeba5c 100644 --- a/gfx/drivers/omap_gfx.c +++ b/gfx/drivers/omap_gfx.c @@ -133,24 +133,19 @@ static void omapfb_page_flip(omapfb_data_t *pdata) pdata->old_page->used = false; } -static int omapfb_read_sysfs(const char *fname, char *buff, size_t size) +static int omapfb_read_sysfs(const char *fname, char *s, size_t len) { int ret; FILE *f = fopen(fname, "r"); - if (!f) return -1; - - ret = fread(buff, 1, size - 1, f); + ret = fread(s, 1, len - 1, f); fclose(f); - if (ret <= 0) return -1; - - buff[ret] = 0; - for (ret--; ret >= 0 && isspace(buff[ret]); ret--) - buff[ret] = 0; - + s[ret] = 0; + for (ret--; ret >= 0 && isspace(s[ret]); ret--) + s[ret] = 0; return 0; } diff --git a/gfx/drivers/vg.c b/gfx/drivers/vg.c index 30f0c90e9d..e63ec7cf55 100644 --- a/gfx/drivers/vg.c +++ b/gfx/drivers/vg.c @@ -318,10 +318,10 @@ static void vg_free(void *data) static void vg_calculate_quad(vg_t *vg, unsigned vp_width, unsigned vp_height) { - struct video_viewport_t vp; + video_viewport_t vp; settings_t *settings = config_get_ptr(); bool video_scale_integer = settings->bools.video_scale_integer; - float device_aspect = (float)width / height; + float device_aspect = (float)vp_width / vp_height; vp.x = 0; vp.y = 0; diff --git a/gfx/drivers/vulkan.c b/gfx/drivers/vulkan.c index 203e144e01..7063b3e872 100644 --- a/gfx/drivers/vulkan.c +++ b/gfx/drivers/vulkan.c @@ -3257,19 +3257,15 @@ static void vulkan_init_hw_render(vk_t *vk) iface->get_instance_proc_addr = vulkan_symbol_wrapper_instance_proc_addr(); } -static void vulkan_init_readback(vk_t *vk, settings_t *settings) +static void vulkan_init_readback(vk_t *vk, bool video_gpu_record) { /* Only bother with this if we're doing GPU recording. - * Check recording_st->enable and not - * driver.recording_data, because recording is - * not initialized yet. + * Check rec_st->enable and not driver.recording_data, + * because recording is not initialized yet. */ - recording_state_t - *recording_st = recording_state_get_ptr(); - bool recording_enabled = recording_st->enable; - bool video_gpu_record = settings->bools.video_gpu_record; + recording_state_t *rec_st = recording_state_get_ptr(); - if (!(video_gpu_record && recording_enabled)) + if (!(video_gpu_record && rec_st->enable)) { vk->flags &= ~VK_FLAG_READBACK_STREAMED; return; @@ -3335,10 +3331,10 @@ static void *vulkan_init(const video_info_t *video, } #ifdef VULKAN_HDR_SWAPCHAIN - vk->hdr.max_output_nits = settings->floats.video_hdr_max_nits; - vk->hdr.min_output_nits = 0.001f; - vk->hdr.max_cll = 0.0f; - vk->hdr.max_fall = 0.0f; + vk->hdr.max_output_nits = settings->floats.video_hdr_max_nits; + vk->hdr.min_output_nits = 0.001f; + vk->hdr.max_cll = 0.0f; + vk->hdr.max_fall = 0.0f; #endif /* VULKAN_HDR_SWAPCHAIN */ vk->video = *video; @@ -3552,7 +3548,7 @@ static void *vulkan_init(const video_info_t *video, is the simplest solution unless reinit tracking is done */ vk->flags |= VK_FLAG_SHOULD_RESIZE; - vulkan_init_readback(vk, settings); + vulkan_init_readback(vk, settings->bools.video_gpu_record); return vk; error: @@ -3830,8 +3826,7 @@ static void vulkan_set_viewport(void *data, unsigned vp_width, { float device_aspect = (float)vp_width / vp_height; struct video_ortho ortho = {0, 1, 0, 1, -1, 1}; - settings_t *settings = config_get_ptr(); - bool video_scale_integer = settings->bools.video_scale_integer; + bool video_scale_integer = config_get_ptr()->bools.video_scale_integer; vk_t *vk = (vk_t*)data; if (vk->ctx_driver->translate_aspect) @@ -4572,7 +4567,7 @@ static bool vulkan_frame(void *data, const void *frame, 1); #endif vulkan_filter_chain_set_frame_time_delta( - (vulkan_filter_chain_t*)vk->filter_chain, video_driver_get_frame_time_delta_usec()); + (vulkan_filter_chain_t*)vk->filter_chain, (uint32_t)video_driver_get_frame_time_delta_usec()); vulkan_filter_chain_set_original_fps( (vulkan_filter_chain_t*)vk->filter_chain, video_driver_get_original_fps()); diff --git a/gfx/drivers_context/cocoa_gl_ctx.m b/gfx/drivers_context/cocoa_gl_ctx.m index 65899de61b..bbe17c3f5a 100644 --- a/gfx/drivers_context/cocoa_gl_ctx.m +++ b/gfx/drivers_context/cocoa_gl_ctx.m @@ -174,6 +174,7 @@ static void cocoa_gl_gfx_ctx_destroy(void *data) #else [EAGLContext setCurrentContext:nil]; #endif + g_hw_ctx = nil; g_ctx = nil; free(cocoa_ctx); @@ -481,12 +482,20 @@ static bool cocoa_gl_gfx_ctx_set_video_mode(void *data, #if defined(HAVE_OPENGLES3) if (cocoa_ctx->flags & COCOA_CTX_FLAG_USE_HW_CTX) + { g_hw_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; - g_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; + g_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:g_hw_ctx.sharegroup]; + } + else + g_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; #elif defined(HAVE_OPENGLES2) if (cocoa_ctx->flags & COCOA_CTX_FLAG_USE_HW_CTX) + { g_hw_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - g_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + g_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:g_hw_ctx.sharegroup]; + } + else + g_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; #endif #ifdef OSX diff --git a/gfx/drivers_context/emscriptenegl_ctx.c b/gfx/drivers_context/emscriptenegl_ctx.c index 2082aef98e..2cfbfd066c 100644 --- a/gfx/drivers_context/emscriptenegl_ctx.c +++ b/gfx/drivers_context/emscriptenegl_ctx.c @@ -21,6 +21,7 @@ #include #include +#include "../../frontend/drivers/platform_emscripten.h" #ifdef HAVE_CONFIG_H #include "../../config.h" @@ -38,92 +39,28 @@ typedef struct #ifdef HAVE_EGL egl_ctx_data_t egl; #endif - int initial_width; - int initial_height; unsigned fb_width; unsigned fb_height; } emscripten_ctx_data_t; static void gfx_ctx_emscripten_swap_interval(void *data, int interval) { - if (interval == 0) - emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0); - else - emscripten_set_main_loop_timing(EM_TIMING_RAF, interval); -} - -static void gfx_ctx_emscripten_get_canvas_size(int *width, int *height) -{ - EmscriptenFullscreenChangeEvent fullscreen_status; - bool is_fullscreen = false; - EMSCRIPTEN_RESULT r = emscripten_get_fullscreen_status(&fullscreen_status); - - if (r == EMSCRIPTEN_RESULT_SUCCESS) - { - if (fullscreen_status.isFullscreen) - { - is_fullscreen = true; - *width = fullscreen_status.screenWidth; - *height = fullscreen_status.screenHeight; - } - } - - if (!is_fullscreen) - { - r = emscripten_get_canvas_element_size("!canvas", width, height); - - if (r != EMSCRIPTEN_RESULT_SUCCESS) - { - *width = 800; - *height = 600; - RARCH_ERR("[EMSCRIPTEN/EGL]: Could not get screen dimensions: %d\n",r); - } - } + platform_emscripten_set_main_loop_interval(interval); } static void gfx_ctx_emscripten_check_window(void *data, bool *quit, bool *resize, unsigned *width, unsigned *height) { - EMSCRIPTEN_RESULT r; int input_width; int input_height; emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; - gfx_ctx_emscripten_get_canvas_size(&input_width, &input_height); + platform_emscripten_get_canvas_size(&input_width, &input_height); - if (input_width == 0 || input_height == 0) - { - input_width = emscripten->initial_width; - input_height = emscripten->initial_height; - emscripten->fb_width = emscripten->fb_height = 0; - } - - *width = (unsigned)input_width; - *height = (unsigned)input_height; - *resize = false; - - if ( (input_width != emscripten->fb_width) - || (input_height != emscripten->fb_height)) - { - r = emscripten_set_canvas_element_size("!canvas", - input_width, input_height); - - if (r != EMSCRIPTEN_RESULT_SUCCESS) - RARCH_ERR("[EMSCRIPTEN/EGL]: error resizing canvas: %d\n", r); - - /* fix Module.requestFullscreen messing with the canvas size */ - r = emscripten_set_element_css_size("!canvas", - (double)input_width, (double)input_height); - - if (r != EMSCRIPTEN_RESULT_SUCCESS) - RARCH_ERR("[EMSCRIPTEN/EGL]: error resizing canvas css: %d\n", r); - - *resize = true; - } - - emscripten->fb_width = (unsigned)input_width; - emscripten->fb_height = (unsigned)input_height; - *quit = false; + *resize = (emscripten->fb_width != input_width || emscripten->fb_height != input_height); + *width = emscripten->fb_width = (unsigned)input_width; + *height = emscripten->fb_height = (unsigned)input_height; + *quit = false; } static void gfx_ctx_emscripten_swap_buffers(void *data) @@ -148,17 +85,34 @@ static void gfx_ctx_emscripten_get_video_size(void *data, *height = emscripten->fb_height; } +static bool gfx_ctx_emscripten_get_metrics(void *data, + enum display_metric_types type, float *value) +{ + switch (type) + { + // there is no way to get the actual DPI in emscripten, so return a standard value instead. + // this is needed for menu touch/pointer swipe scrolling to work. + case DISPLAY_METRIC_DPI: + *value = 150.0f; + break; + + default: + *value = 0.0f; + return false; + } + + return true; +} + static void gfx_ctx_emscripten_destroy(void *data) { emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; if (!emscripten) return; - #ifdef HAVE_EGL egl_destroy(&emscripten->egl); #endif - free(data); } @@ -190,14 +144,6 @@ static void *gfx_ctx_emscripten_init(void *video_driver) if (!emscripten) return NULL; - /* TODO/FIXME - why is this conditional here - shouldn't these always - * be grabbed? */ - if ( (emscripten->initial_width == 0) - || (emscripten->initial_height == 0)) - emscripten_get_canvas_element_size("!canvas", - &emscripten->initial_width, - &emscripten->initial_height); - #ifdef HAVE_EGL if (g_egl_inited) { @@ -229,7 +175,6 @@ static void *gfx_ctx_emscripten_init(void *video_driver) #endif return emscripten; - error: gfx_ctx_emscripten_destroy(video_driver); return NULL; @@ -310,7 +255,7 @@ const gfx_ctx_driver_t gfx_ctx_emscripten = { NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - NULL, /* get_metrics */ + gfx_ctx_emscripten_get_metrics, gfx_ctx_emscripten_translate_aspect, NULL, /* update_title */ gfx_ctx_emscripten_check_window, diff --git a/gfx/drivers_context/emscriptenwebgl_ctx.c b/gfx/drivers_context/emscriptenwebgl_ctx.c new file mode 100644 index 0000000000..a2e659ba27 --- /dev/null +++ b/gfx/drivers_context/emscriptenwebgl_ctx.c @@ -0,0 +1,279 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2012-2015 - Michael Lelli + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include + +#include +#include +#include "../../frontend/drivers/platform_emscripten.h" + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#include "../../retroarch.h" +#include "../../verbosity.h" + +typedef struct +{ + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; + unsigned fb_width; + unsigned fb_height; +} emscripten_ctx_data_t; + +static void gfx_ctx_emscripten_webgl_swap_interval(void *data, int interval) +{ + platform_emscripten_set_main_loop_interval(interval); +} + +static void gfx_ctx_emscripten_webgl_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height) +{ + int input_width; + int input_height; + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + + platform_emscripten_get_canvas_size(&input_width, &input_height); + + *resize = (emscripten->fb_width != input_width || emscripten->fb_height != input_height); + *width = emscripten->fb_width = (unsigned)input_width; + *height = emscripten->fb_height = (unsigned)input_height; + *quit = false; +} + +/* https://github.com/emscripten-core/emscripten/issues/17816#issuecomment-1249719343 */ +static void gfx_ctx_emscripten_webgl_swap_buffers(void *data) +{ + (void)data; +} + +static void gfx_ctx_emscripten_webgl_get_video_size(void *data, + unsigned *width, unsigned *height) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + + if (!emscripten) + return; + + *width = emscripten->fb_width; + *height = emscripten->fb_height; +} + +static bool gfx_ctx_emscripten_webgl_get_metrics(void *data, + enum display_metric_types type, float *value) +{ + switch (type) + { + // there is no way to get the actual DPI in emscripten, so return a standard value instead. + // this is needed for menu touch/pointer swipe scrolling to work. + case DISPLAY_METRIC_DPI: + *value = 150.0f; + break; + + default: + *value = 0.0f; + return false; + } + + return true; +} + +static void gfx_ctx_emscripten_webgl_destroy(void *data) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + + if (!emscripten) + return; + + emscripten_webgl_destroy_context(emscripten->ctx); + + free(data); +} + +static void *gfx_ctx_emscripten_webgl_init(void *video_driver) +{ + int width, height; + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*) + calloc(1, sizeof(*emscripten)); + + EmscriptenWebGLContextAttributes attrs = {0}; + emscripten_webgl_init_context_attributes(&attrs); + attrs.alpha = false; + attrs.depth = true; + attrs.stencil = true; + attrs.antialias = false; + attrs.powerPreference = EM_WEBGL_POWER_PREFERENCE_HIGH_PERFORMANCE; +#ifdef HAVE_OPENGLES3 + attrs.majorVersion = 2; +#else + attrs.majorVersion = 1; +#endif + attrs.minorVersion = 0; + attrs.enableExtensionsByDefault = true; + attrs.explicitSwapControl = false; + attrs.renderViaOffscreenBackBuffer = false; + attrs.proxyContextToMainThread = EMSCRIPTEN_WEBGL_CONTEXT_PROXY_DISALLOW; + + if (!emscripten) + return NULL; + + emscripten->ctx = emscripten_webgl_create_context("#canvas", &attrs); + if (!emscripten->ctx) + { + RARCH_ERR("[EMSCRIPTEN/WebGL]: Failed to initialize webgl\n"); + goto error; + } + emscripten_webgl_get_drawing_buffer_size(emscripten->ctx, &width, &height); + emscripten_webgl_make_context_current(emscripten->ctx); + emscripten->fb_width = (unsigned)width; + emscripten->fb_height = (unsigned)height; + RARCH_LOG("[EMSCRIPTEN/WebGL]: Dimensions: %ux%u\n", emscripten->fb_width, emscripten->fb_height); + + return emscripten; + +error: + gfx_ctx_emscripten_webgl_destroy(video_driver); + return NULL; +} + +static bool gfx_ctx_emscripten_webgl_set_canvas_size(int width, int height) +{ +#ifdef NO_CANVAS_RESIZE + return false; +#endif + double dpr = platform_emscripten_get_dpr(); + EMSCRIPTEN_RESULT r = emscripten_set_element_css_size("#canvas", (double)width / dpr, (double)height / dpr); + RARCH_LOG("[EMSCRIPTEN/WebGL]: set canvas size to %d, %d\n", width, height); + + if (r != EMSCRIPTEN_RESULT_SUCCESS) + { + RARCH_ERR("[EMSCRIPTEN/WebGL]: error resizing canvas: %d\n", r); + return false; + } + return true; +} + +static bool gfx_ctx_emscripten_webgl_set_video_mode(void *data, + unsigned width, unsigned height, + bool fullscreen) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + if (!emscripten || !emscripten->ctx) + return false; + + if (width != 0 && height != 0) + { + if (!gfx_ctx_emscripten_webgl_set_canvas_size(width, height)) + return false; + } + emscripten->fb_width = width; + emscripten->fb_height = height; + + return true; +} + +bool gfx_ctx_emscripten_webgl_set_resize(void *data, unsigned width, unsigned height) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + if (!emscripten || !emscripten->ctx) + return false; + return gfx_ctx_emscripten_webgl_set_canvas_size(width, height); +} + +static enum gfx_ctx_api gfx_ctx_emscripten_webgl_get_api(void *data) { return GFX_CTX_OPENGL_ES_API; } + +static bool gfx_ctx_emscripten_webgl_bind_api(void *data, + enum gfx_ctx_api api, unsigned major, unsigned minor) +{ + return true; +} + +static void gfx_ctx_emscripten_webgl_input_driver(void *data, + const char *name, + input_driver_t **input, void **input_data) +{ + void *rwebinput = input_driver_init_wrap(&input_rwebinput, name); + *input = rwebinput ? &input_rwebinput : NULL; + *input_data = rwebinput; +} + +static bool gfx_ctx_emscripten_webgl_has_focus(void *data) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + return emscripten && emscripten->ctx; +} + +static bool gfx_ctx_emscripten_webgl_suppress_screensaver(void *data, bool enable) { return false; } + +static float gfx_ctx_emscripten_webgl_translate_aspect(void *data, + unsigned width, unsigned height) { return (float)width / height; } + +static void gfx_ctx_emscripten_webgl_bind_hw_render(void *data, bool enable) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + emscripten_webgl_make_context_current(emscripten->ctx); +} + +static uint32_t gfx_ctx_emscripten_webgl_get_flags(void *data) +{ + uint32_t flags = 0; + BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_GLSL); + return flags; +} + +static void gfx_ctx_emscripten_webgl_set_flags(void *data, uint32_t flags) { } + +static gfx_ctx_proc_t gfx_ctx_emscripten_webgl_get_proc_address(const char *symbol) +{ + return emscripten_webgl_get_proc_address(symbol); +} + +const gfx_ctx_driver_t gfx_ctx_emscripten_webgl = { + gfx_ctx_emscripten_webgl_init, + gfx_ctx_emscripten_webgl_destroy, + gfx_ctx_emscripten_webgl_get_api, + gfx_ctx_emscripten_webgl_bind_api, + gfx_ctx_emscripten_webgl_swap_interval, + gfx_ctx_emscripten_webgl_set_video_mode, + gfx_ctx_emscripten_webgl_get_video_size, + NULL, /* get_refresh_rate */ + NULL, /* get_video_output_size */ + NULL, /* get_video_output_prev */ + NULL, /* get_video_output_next */ + gfx_ctx_emscripten_webgl_get_metrics, + gfx_ctx_emscripten_webgl_translate_aspect, + NULL, /* update_title */ + gfx_ctx_emscripten_webgl_check_window, + gfx_ctx_emscripten_webgl_set_resize, + gfx_ctx_emscripten_webgl_has_focus, + gfx_ctx_emscripten_webgl_suppress_screensaver, + false, + gfx_ctx_emscripten_webgl_swap_buffers, + gfx_ctx_emscripten_webgl_input_driver, + gfx_ctx_emscripten_webgl_get_proc_address, + NULL, + NULL, + NULL, + "webgl_emscripten", + gfx_ctx_emscripten_webgl_get_flags, + gfx_ctx_emscripten_webgl_set_flags, + gfx_ctx_emscripten_webgl_bind_hw_render, + NULL, /* get_context_data */ + NULL /* make_current */ +}; diff --git a/gfx/drivers_context/osmesa_ctx.c b/gfx/drivers_context/osmesa_ctx.c index 77101436f2..5d5b2ab687 100644 --- a/gfx/drivers_context/osmesa_ctx.c +++ b/gfx/drivers_context/osmesa_ctx.c @@ -122,14 +122,14 @@ static void osmesa_fifo_accept(gfx_ctx_osmesa_data_t *osmesa) static void osmesa_fifo_write(gfx_ctx_osmesa_data_t *osmesa) { int i; - size_t len = osmesa->width * osmesa->pixsize; + size_t _len = osmesa->width * osmesa->pixsize; if (osmesa->client < 0) return; for (i = osmesa->height -1; i >= 0; --i) { - int res = send(osmesa->client, osmesa->screen + i * len, len, MSG_NOSIGNAL); + int res = send(osmesa->client, osmesa->screen + i * _len, _len, MSG_NOSIGNAL); if (res < 0) { diff --git a/gfx/drivers_context/w_vk_ctx.c b/gfx/drivers_context/w_vk_ctx.c index 8f2d40bf06..c7dd29434a 100644 --- a/gfx/drivers_context/w_vk_ctx.c +++ b/gfx/drivers_context/w_vk_ctx.c @@ -29,6 +29,7 @@ #include #include +#define WIN32_LEAN_AND_MEAN #include #include @@ -96,7 +97,7 @@ static void gfx_ctx_w_vk_check_window(void *data, bool *quit, if ( (win32_vk.flags & VK_DATA_FLAG_FULLSCREEN) && (g_win32_refresh_rate) && (g_win32_refresh_rate != refresh_rate) - && (abs(g_win32_refresh_rate - refresh_rate) > 0) + && (fabsf(g_win32_refresh_rate - refresh_rate) > 0.1f) && (g_win32_resize_width == *width) && (g_win32_resize_height == *height)) { @@ -271,10 +272,24 @@ static void *gfx_ctx_w_vk_get_context_data(void *data) { return &win32_vk.contex static uint32_t gfx_ctx_w_vk_get_flags(void *data) { - uint32_t flags = 0; + uint32_t flags = 0; + uint8_t present_mode_count = 16; + uint8_t i = 0; + + /* Check for FIFO_RELAXED_KHR capability */ + for (i = 0; i < present_mode_count; i++) + { + if (win32_vk.context.present_modes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR) + { + BIT32_SET(flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC); + break; + } + } + #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG); #endif + return flags; } diff --git a/gfx/drivers_context/wgl_ctx.c b/gfx/drivers_context/wgl_ctx.c index cc44947d8a..3a7c990394 100644 --- a/gfx/drivers_context/wgl_ctx.c +++ b/gfx/drivers_context/wgl_ctx.c @@ -29,6 +29,7 @@ #include #include +#define WIN32_LEAN_AND_MEAN #include #include diff --git a/gfx/drivers_context/x_vk_ctx.c b/gfx/drivers_context/x_vk_ctx.c index 38e8654a85..b1eb909458 100644 --- a/gfx/drivers_context/x_vk_ctx.c +++ b/gfx/drivers_context/x_vk_ctx.c @@ -526,8 +526,20 @@ static void *gfx_ctx_x_vk_get_context_data(void *data) static uint32_t gfx_ctx_x_vk_get_flags(void *data) { - uint32_t flags = 0; - gfx_ctx_x_vk_data_t *x = (gfx_ctx_x_vk_data_t*)data; + gfx_ctx_x_vk_data_t *x = (gfx_ctx_x_vk_data_t*)data; + uint32_t flags = 0; + uint8_t present_mode_count = 16; + uint8_t i = 0; + + /* Check for FIFO_RELAXED_KHR capability */ + for (i = 0; i < present_mode_count; i++) + { + if (x->vk.context.present_modes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR) + { + BIT32_SET(flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC); + break; + } + } #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG); diff --git a/gfx/drivers_font/d3d9x_w32_font.c b/gfx/drivers_font/d3d9x_w32_font.c index 261176e941..244247fe4e 100644 --- a/gfx/drivers_font/d3d9x_w32_font.c +++ b/gfx/drivers_font/d3d9x_w32_font.c @@ -15,6 +15,7 @@ */ #define CINTERFACE +#define WIN32_LEAN_AND_MEAN #include diff --git a/gfx/drivers_shader/glslang_util.c b/gfx/drivers_shader/glslang_util.c index 4bb3a8e496..d5281d3313 100644 --- a/gfx/drivers_shader/glslang_util.c +++ b/gfx/drivers_shader/glslang_util.c @@ -28,17 +28,17 @@ #include "glslang_util.h" #include "../../verbosity.h" -static void get_include_file(const char *line, char *s, size_t len) +static char *slang_get_include_file(const char *line) { char *end = NULL; char *start = (char*)strchr(line, '\"'); if (!start) - return; + return NULL; start++; if (!(end = (char*)strchr(start, '\"'))) - return; + return NULL; *end = '\0'; - strlcpy(s, start, len); + return start; } bool slang_texture_semantic_is_array(enum slang_texture_semantic sem) @@ -193,15 +193,8 @@ bool glslang_read_shader_file(const char *path, bool include_optional = !strncmp("#pragma include_optional ", line, STRLEN_CONST("#pragma include_optional ")); if ( !strncmp("#include ", line, STRLEN_CONST("#include ")) || include_optional ) { - - char include_file[PATH_MAX_LENGTH]; char include_path[PATH_MAX_LENGTH]; - - include_file[0] = '\0'; - include_path[0] = '\0'; - - /* Build include file path */ - get_include_file(line, include_file, sizeof(include_file)); + char *include_file = slang_get_include_file(line); if (string_is_empty(include_file)) { @@ -209,6 +202,7 @@ bool glslang_read_shader_file(const char *path, goto error; } + include_path[0] = '\0'; fill_pathname_resolve_relative( include_path, path, include_file, sizeof(include_path)); diff --git a/gfx/drivers_shader/shader_gl3.cpp b/gfx/drivers_shader/shader_gl3.cpp index 26e206493b..2f9088bd19 100644 --- a/gfx/drivers_shader/shader_gl3.cpp +++ b/gfx/drivers_shader/shader_gl3.cpp @@ -1683,11 +1683,11 @@ void Pass::build_commands( unsigned vertex_binding = locations.buffer_index_ubo_vertex; unsigned fragment_binding = locations.buffer_index_ubo_fragment; const void *data = uniforms.data(); - size_t size = reflection.ubo_size; + size_t _len = reflection.ubo_size; GLuint id = ubo_ring.buffers[ubo_ring.buffer_index]; glBindBuffer(GL_UNIFORM_BUFFER, id); - glBufferSubData(GL_UNIFORM_BUFFER, 0, size, data); + glBufferSubData(GL_UNIFORM_BUFFER, 0, _len, data); glBindBuffer(GL_UNIFORM_BUFFER, 0); if (vertex_binding != GL_INVALID_INDEX) glBindBufferBase(GL_UNIFORM_BUFFER, vertex_binding, id); diff --git a/gfx/drivers_shader/shader_glsl.c b/gfx/drivers_shader/shader_glsl.c index 7a17ade1a1..6abd90f38b 100644 --- a/gfx/drivers_shader/shader_glsl.c +++ b/gfx/drivers_shader/shader_glsl.c @@ -44,6 +44,11 @@ #include "../../deps/xxHash/xxhash.h" #endif +#if defined(VITA) +#include +#include +#endif + #define PREV_TEXTURES (GFX_MAX_TEXTURES - 1) /* Cache the VBO. */ @@ -1368,7 +1373,7 @@ static void gl_glsl_set_params(void *dat, void *shader_data) } if (uni->frame_time_delta >= 0) - glUniform1i(uni->frame_time_delta, video_driver_get_frame_time_delta_usec()); + glUniform1i(uni->frame_time_delta, (GLint)video_driver_get_frame_time_delta_usec()); if (uni->original_fps >= 0) glUniform1f(uni->original_fps, video_driver_get_original_fps()); diff --git a/gfx/drivers_shader/shader_vulkan.cpp b/gfx/drivers_shader/shader_vulkan.cpp index b1ef070d00..c09f575213 100644 --- a/gfx/drivers_shader/shader_vulkan.cpp +++ b/gfx/drivers_shader/shader_vulkan.cpp @@ -73,7 +73,7 @@ class Buffer public: Buffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props, - size_t size, VkBufferUsageFlags usage); + size_t len, VkBufferUsageFlags usage); ~Buffer(); size_t get_size() const { return size; } @@ -1532,8 +1532,8 @@ StaticTexture::~StaticTexture() Buffer::Buffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props, - size_t size, VkBufferUsageFlags usage) : - device(device), size(size) + size_t len, VkBufferUsageFlags usage) : + device(device), size(len) { VkBufferCreateInfo info; VkMemoryRequirements mem_reqs; @@ -1542,7 +1542,7 @@ Buffer::Buffer(VkDevice device, info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; info.pNext = NULL; info.flags = 0; - info.size = size; + info.size = len; info.usage = usage; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.queueFamilyIndexCount = 0; diff --git a/gfx/font_driver.h b/gfx/font_driver.h index f8066fd5cb..ab849b0d83 100644 --- a/gfx/font_driver.h +++ b/gfx/font_driver.h @@ -89,13 +89,13 @@ typedef struct void font_driver_bind_block(void *font_data, void *block); -static void INLINE font_bind(font_data_impl_t *font_data) +static INLINE void font_bind(font_data_impl_t *font_data) { font_driver_bind_block(font_data->font, &font_data->raster_block); font_data->raster_block.carr.coords.vertices = 0; } -static void INLINE font_unbind(font_data_impl_t *font_data) +static INLINE void font_unbind(font_data_impl_t *font_data) { font_driver_bind_block(font_data->font, NULL); } diff --git a/gfx/gfx_display.c b/gfx/gfx_display.c index 67063efade..63cd804bae 100644 --- a/gfx/gfx_display.c +++ b/gfx/gfx_display.c @@ -289,7 +289,9 @@ float gfx_display_get_dpi_scale( menu_scale_factor = 1.0f; else #endif +#ifdef HAVE_GFX_WIDGETS menu_scale_factor = settings->floats.menu_scale_factor; +#endif } } #endif diff --git a/gfx/gfx_display.h b/gfx/gfx_display.h index fc2bcdd243..79aac74114 100644 --- a/gfx/gfx_display.h +++ b/gfx/gfx_display.h @@ -32,7 +32,7 @@ #include "../retroarch.h" #include "../gfx/font_driver.h" -#define GFX_SHADOW_ALPHA 0.75f +#define GFX_SHADOW_ALPHA 1.00f /* Number of pixels corner-to-corner on a 1080p * display: diff --git a/gfx/gfx_thumbnail.c b/gfx/gfx_thumbnail.c index 4e1a543519..7cfc3798f7 100644 --- a/gfx/gfx_thumbnail.c +++ b/gfx/gfx_thumbnail.c @@ -35,7 +35,7 @@ #include "../tasks/tasks_internal.h" -#define DEFAULT_GFX_THUMBNAIL_STREAM_DELAY 83.333333f +#define DEFAULT_GFX_THUMBNAIL_STREAM_DELAY 16.66667f * 3 #define DEFAULT_GFX_THUMBNAIL_FADE_DURATION 166.66667f /* Utility structure, sent as userdata when pushing @@ -282,8 +282,11 @@ static bool gfx_thumbnail_get_path( * on-demand thumbnail download support * (an annoyance...) */ void gfx_thumbnail_request( - gfx_thumbnail_path_data_t *path_data, enum gfx_thumbnail_id thumbnail_id, - playlist_t *playlist, size_t idx, gfx_thumbnail_t *thumbnail, + gfx_thumbnail_path_data_t *path_data, + enum gfx_thumbnail_id thumbnail_id, + playlist_t *playlist, + size_t idx, + gfx_thumbnail_t *thumbnail, unsigned gfx_thumbnail_upscale_threshold, bool network_on_demand_thumbnails) { @@ -332,7 +335,7 @@ void gfx_thumbnail_request( { enum playlist_thumbnail_name_flags curr_flag; static char last_img_name[PATH_MAX_LENGTH] = {0}; - settings_t *settings = config_get_ptr(); + bool playlist_use_filename = config_get_ptr()->bools.playlist_use_filename; if (!playlist) goto end; /* Only trigger a thumbnail download if image @@ -364,7 +367,7 @@ void gfx_thumbnail_request( || curr_flag & PLAYLIST_THUMBNAIL_FLAG_SHORT_NAME) goto end; /* Do not try to fetch full names here, if it is not explicitly wanted */ - if ( !settings->bools.playlist_use_filename + if ( !playlist_use_filename && !playlist_thumbnail_match_with_filename(playlist) && curr_flag == PLAYLIST_THUMBNAIL_FLAG_INVALID) playlist_update_thumbnail_name_flag(playlist, idx, PLAYLIST_THUMBNAIL_FLAG_FULL_NAME); @@ -883,6 +886,16 @@ void gfx_thumbnail_get_draw_dimensions( *draw_width = *draw_width / (thumbnail_aspect / core_aspect); } + /* Final overwidth check */ + if (*draw_width > width) + { + *draw_width = (float)width; + *draw_height = (float)thumbnail->height * (*draw_width / (float)thumbnail->width); + + if (thumbnail->flags & GFX_THUMB_FLAG_CORE_ASPECT) + *draw_height = *draw_height * (thumbnail_aspect / core_aspect); + } + /* Account for scale factor * > Side note: We cannot use the gfx_display_ctx_draw_t * 'scale_factor' parameter for scaling thumbnails, diff --git a/gfx/gfx_thumbnail_path.c b/gfx/gfx_thumbnail_path.c index 0a78dc0543..76d609f724 100644 --- a/gfx/gfx_thumbnail_path.c +++ b/gfx/gfx_thumbnail_path.c @@ -39,15 +39,15 @@ * Named_Titles, Named_Boxarts, Named_Logos) for specified thumbnail * identifier (right, left) */ static const char *gfx_thumbnail_get_type( - settings_t *settings, + unsigned gfx_thumbnails, + unsigned left_thumbnails, + unsigned icon_thumbnails, gfx_thumbnail_path_data_t *path_data, enum gfx_thumbnail_id thumbnail_id) { if (path_data) { unsigned type = 0; - unsigned menu_left_thumbnails = settings->uints.menu_left_thumbnails; - unsigned gfx_thumbnails = settings->uints.gfx_thumbnails; switch (thumbnail_id) { case GFX_THUMBNAIL_RIGHT: @@ -60,10 +60,13 @@ static const char *gfx_thumbnail_get_type( if (path_data->playlist_left_mode != PLAYLIST_THUMBNAIL_MODE_DEFAULT) type = (unsigned)path_data->playlist_left_mode - 1; else - type = menu_left_thumbnails; + type = left_thumbnails; break; case GFX_THUMBNAIL_ICON: - type = 4; + if (path_data->playlist_icon_mode != PLAYLIST_THUMBNAIL_MODE_DEFAULT) + type = (unsigned)path_data->playlist_icon_mode - 1; + else + type = icon_thumbnails; break; default: goto end; @@ -139,9 +142,11 @@ void gfx_thumbnail_path_reset(gfx_thumbnail_path_data_t *path_data) path_data->content_img_short[0] = '\0'; path_data->right_path[0] = '\0'; path_data->left_path[0] = '\0'; + path_data->icon_path[0] = '\0'; path_data->playlist_right_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT; path_data->playlist_left_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT; + path_data->playlist_icon_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT; } /* Initialisation */ @@ -166,7 +171,8 @@ gfx_thumbnail_path_data_t *gfx_thumbnail_path_init(void) /* Returns true if specified thumbnail is enabled * (i.e. if 'type' is not equal to MENU_ENUM_LABEL_VALUE_OFF) */ -bool gfx_thumbnail_is_enabled(gfx_thumbnail_path_data_t *path_data, enum gfx_thumbnail_id thumbnail_id) +bool gfx_thumbnail_is_enabled(gfx_thumbnail_path_data_t *path_data, + enum gfx_thumbnail_id thumbnail_id) { if (path_data) { @@ -187,7 +193,7 @@ bool gfx_thumbnail_is_enabled(gfx_thumbnail_path_data_t *path_data, enum gfx_thu return menu_left_thumbnails != 0; case GFX_THUMBNAIL_ICON: if (path_data->playlist_icon_mode != PLAYLIST_THUMBNAIL_MODE_DEFAULT) - return path_data->playlist_left_mode != PLAYLIST_THUMBNAIL_MODE_OFF; + return path_data->playlist_icon_mode != PLAYLIST_THUMBNAIL_MODE_OFF; return menu_icon_thumbnails != 0; default: break; @@ -488,7 +494,7 @@ bool gfx_thumbnail_set_content_playlist( sizeof(path_data->content_img), path_data->content_label, false); /* Explicit zero if full name is same as standard name - saves some queries later. */ - if(string_is_equal(path_data->content_img, path_data->content_img_full)) + if (string_is_equal(path_data->content_img, path_data->content_img_full)) path_data->content_img_full[0] = '\0'; gfx_thumbnail_fill_content_img(path_data->content_img_short, @@ -559,10 +565,14 @@ bool gfx_thumbnail_update_path( enum gfx_thumbnail_id thumbnail_id) { char content_dir[DIR_MAX_LENGTH]; - settings_t *settings = config_get_ptr(); - const char *system_name = NULL; - char *thumbnail_path = NULL; - const char *dir_thumbnails = NULL; + settings_t *settings = config_get_ptr(); + const char *system_name = NULL; + char *thumbnail_path = NULL; + const char *dir_thumbnails = settings->paths.directory_thumbnails; + bool playlist_allow_non_png = settings->bools.playlist_allow_non_png; + unsigned gfx_thumbnails = settings->uints.gfx_thumbnails; + unsigned menu_left_thumbnails = settings->uints.menu_left_thumbnails; + unsigned menu_icon_thumbnails = settings->uints.menu_icon_thumbnails; /* Thumbnail extension order. The default (i.e. png) is always the first. */ #define MAX_SUPPORTED_THUMBNAIL_EXTENSIONS 5 const char* const SUPPORTED_THUMBNAIL_EXTENSIONS[] = { ".png", ".jpg", ".jpeg", ".bmp", ".tga", 0 }; @@ -588,9 +598,6 @@ bool gfx_thumbnail_update_path( content_dir[0] = '\0'; - if (settings) - dir_thumbnails = settings->paths.directory_thumbnails; - /* Sundry error checking */ if (string_is_empty(dir_thumbnails)) return false; @@ -641,10 +648,10 @@ bool gfx_thumbnail_update_path( } else { - char tmp_buf[DIR_MAX_LENGTH]; - const char *type = gfx_thumbnail_get_type(settings, - path_data, thumbnail_id); int i; + char tmp_buf[DIR_MAX_LENGTH]; + const char *type = gfx_thumbnail_get_type(gfx_thumbnails, + menu_left_thumbnails, menu_icon_thumbnails, path_data, thumbnail_id); bool thumbnail_found = false; /* > Normal content: assemble path */ @@ -664,12 +671,13 @@ bool gfx_thumbnail_update_path( /* Try alternative file extensions in turn, if wanted */ for (i = 1; - settings->bools.playlist_allow_non_png + playlist_allow_non_png && !thumbnail_found && thumbnail_path[0]!='\0' && i < MAX_SUPPORTED_THUMBNAIL_EXTENSIONS; i++ ) { - strlcpy(path_get_extension_mutable(thumbnail_path),SUPPORTED_THUMBNAIL_EXTENSIONS[i],6); + strlcpy(path_get_extension_mutable(thumbnail_path), + SUPPORTED_THUMBNAIL_EXTENSIONS[i], 6); thumbnail_found = path_is_valid(thumbnail_path); } @@ -683,11 +691,12 @@ bool gfx_thumbnail_update_path( } for (i = 1; - settings->bools.playlist_allow_non_png + playlist_allow_non_png && !thumbnail_found && i < MAX_SUPPORTED_THUMBNAIL_EXTENSIONS ; i++ ) { - strlcpy(path_get_extension_mutable(thumbnail_path),SUPPORTED_THUMBNAIL_EXTENSIONS[i],6); + strlcpy(path_get_extension_mutable(thumbnail_path), + SUPPORTED_THUMBNAIL_EXTENSIONS[i], 6); thumbnail_found = path_is_valid(thumbnail_path); } @@ -701,11 +710,12 @@ bool gfx_thumbnail_update_path( } for( i = 1 ; - settings->bools.playlist_allow_non_png + playlist_allow_non_png && !thumbnail_found && i < MAX_SUPPORTED_THUMBNAIL_EXTENSIONS ; i++ ) { - strlcpy(path_get_extension_mutable(thumbnail_path),SUPPORTED_THUMBNAIL_EXTENSIONS[i],6); + strlcpy(path_get_extension_mutable(thumbnail_path), + SUPPORTED_THUMBNAIL_EXTENSIONS[i], 6); thumbnail_found = path_is_valid(thumbnail_path); } /* This logic is valid for locally stored thumbnails. For optional downloads, @@ -720,11 +730,11 @@ bool gfx_thumbnail_update_path( /* Fetches current content directory. * Returns true if content directory is valid. */ -size_t gfx_thumbnail_get_content_dir( - gfx_thumbnail_path_data_t *path_data, char *s, size_t len) +size_t gfx_thumbnail_get_content_dir(gfx_thumbnail_path_data_t *path_data, + char *s, size_t len) { - char *last_slash; size_t _len; + char *last_slash; char tmp_buf[NAME_MAX_LENGTH]; if (!path_data || string_is_empty(path_data->content_path)) return 0; diff --git a/gfx/gfx_widgets.c b/gfx/gfx_widgets.c index f6f9e06f4d..c26e1028d0 100644 --- a/gfx/gfx_widgets.c +++ b/gfx/gfx_widgets.c @@ -16,7 +16,6 @@ */ #include -#include #ifdef HAVE_CONFIG_H #include "../config.h" @@ -43,41 +42,13 @@ #include "../tasks/task_content.h" #include "../tasks/tasks_internal.h" -#define BASE_FONT_SIZE 32.0f - +#define BASE_FONT_SIZE 32.0f #define MSG_QUEUE_FONT_SIZE 20.0f -/* Icons */ -static const char -*gfx_widgets_icons_names[MENU_WIDGETS_ICON_LAST] = { - "menu_pause.png", - "menu_frameskip.png", - "menu_rewind.png", - "resume.png", - - "menu_hourglass.png", - "menu_check.png", - "menu_add.png", - "menu_exit.png", - - "menu_info.png", - - "menu_achievements.png" -}; - static dispgfx_widget_t dispwidget_st = {0}; /* uint64_t alignment */ -static void INLINE gfx_widgets_font_free(gfx_widget_font_data_t *font_data) -{ - if (font_data->font) - font_driver_free(font_data->font); - - font_data->font = NULL; - font_data->usage_count = 0; -} - /* Widgets list */ -const static gfx_widget_t* const widgets[] = { +static const gfx_widget_t* const widgets[] = { #ifdef HAVE_NETWORKING &gfx_widget_netplay_chat, &gfx_widget_netplay_ping, @@ -241,6 +212,11 @@ void gfx_widgets_msg_queue_push( msg_widget->unfold = 1.0f; } + if (category == MESSAGE_QUEUE_CATEGORY_WARNING) + msg_widget->flags |= DISPWIDG_FLAG_CATEGORY_WARNING; + else if (category == MESSAGE_QUEUE_CATEGORY_ERROR) + msg_widget->flags |= DISPWIDG_FLAG_CATEGORY_ERROR; + if (task) { len = strlen(task->title); @@ -1123,12 +1099,13 @@ static int gfx_widgets_draw_indicator( } else { + char txt[NAME_MAX_LENGTH]; unsigned height = p_dispwidget->simple_widget_height; - const char *txt = msg_hash_to_str(msg); + size_t _len = strlcpy(txt, msg_hash_to_str(msg), sizeof(txt)); width = font_driver_get_message_width( p_dispwidget->gfx_widget_fonts.regular.font, - txt, strlen(txt), 1.0f) + txt, _len, 1.0f) + p_dispwidget->simple_widget_padding * 2; gfx_display_draw_quad( @@ -1389,24 +1366,30 @@ static void gfx_widgets_draw_regular_msg( unsigned video_width, unsigned video_height) { - static float msg_queue_info[16] = COLOR_HEX_TO_FLOAT(0x0C99D6, 1.0f); - static float msg_queue_bar[16] = COLOR_HEX_TO_FLOAT(0xCCCCCC, 1.0f); + static float msg_queue_info_blue[16] = COLOR_HEX_TO_FLOAT(0x0C99D6, 1.0f); + static float msg_queue_info_yellow[16] = COLOR_HEX_TO_FLOAT(0xD6C10C, 1.0f); + static float msg_queue_info_red[16] = COLOR_HEX_TO_FLOAT(0xD6160C, 1.0f); + static float msg_queue_bar[16] = COLOR_HEX_TO_FLOAT(0xCCCCCC, 1.0f); + float* msg_queue_info; unsigned rect_width; unsigned rect_margin; unsigned text_color; - static float last_alpha = 0.0f; msg->flags &= ~DISPWIDG_FLAG_UNFOLDING; msg->flags |= DISPWIDG_FLAG_UNFOLDED; - if (last_alpha != msg->alpha) - { - /* Icon */ - gfx_display_set_alpha(msg_queue_info, msg->alpha); - gfx_display_set_alpha(p_dispwidget->pure_white, msg->alpha); - gfx_display_set_alpha(p_dispwidget->msg_queue_bg, msg->alpha); - last_alpha = msg->alpha; - } + /* Tint icon yellow for warnings and red for errors, otherwise use blue */ + if (msg->flags & DISPWIDG_FLAG_CATEGORY_WARNING) + msg_queue_info = msg_queue_info_yellow; + else if (msg->flags & DISPWIDG_FLAG_CATEGORY_ERROR) + msg_queue_info = msg_queue_info_red; + else + msg_queue_info = msg_queue_info_blue; + + /* Icon */ + gfx_display_set_alpha(msg_queue_info, msg->alpha); + gfx_display_set_alpha(p_dispwidget->pure_white, msg->alpha); + gfx_display_set_alpha(p_dispwidget->msg_queue_bg, msg->alpha); if ( !(msg->flags & DISPWIDG_FLAG_UNFOLDED) || (msg->flags & DISPWIDG_FLAG_UNFOLDING)) @@ -1489,6 +1472,10 @@ static void gfx_widgets_draw_regular_msg( if (p_dispwidget->flags & DISPGFX_WIDGET_FLAG_MSG_QUEUE_HAS_ICONS) { + /* For warnings and errors, flip the 'i' upside down so it becomes '!' */ + bool invert_y = (msg->flags & ( DISPWIDG_FLAG_CATEGORY_WARNING + | DISPWIDG_FLAG_CATEGORY_ERROR)) != 0; + if (dispctx && dispctx->blend_begin) dispctx->blend_begin(userdata); @@ -1504,7 +1491,7 @@ static void gfx_widgets_draw_regular_msg( + (p_dispwidget->simple_widget_padding / 4.0f), video_height - msg->offset_y - p_dispwidget->msg_queue_icon_offset_y, 0.0f, /* rad */ - 1.0f, /* cos(rad) = cos(0) = 1.0f */ + (invert_y ? -1.0f : 1.0f), /* cosine */ 0.0f, /* sine(rad) = sine(0) = 0.0f */ msg_queue_info); @@ -1513,19 +1500,6 @@ static void gfx_widgets_draw_regular_msg( } } -static void INLINE gfx_widgets_font_bind(gfx_widget_font_data_t *font_data) -{ - font_driver_bind_block(font_data->font, &font_data->raster_block); - font_data->raster_block.carr.coords.vertices = 0; - font_data->usage_count = 0; -} - -static void INLINE gfx_widgets_font_unbind(gfx_widget_font_data_t *font_data) -{ - font_driver_bind_block(font_data->font, NULL); -} - - void gfx_widgets_frame(void *data) { size_t i; @@ -1567,9 +1541,19 @@ void gfx_widgets_frame(void *data) video_st->data, video_width, video_height, true, false); /* Font setup */ - gfx_widgets_font_bind(&p_dispwidget->gfx_widget_fonts.regular); - gfx_widgets_font_bind(&p_dispwidget->gfx_widget_fonts.bold); - gfx_widgets_font_bind(&p_dispwidget->gfx_widget_fonts.msg_queue); + font_driver_bind_block(p_dispwidget->gfx_widget_fonts.regular.font, + &p_dispwidget->gfx_widget_fonts.regular.raster_block); + font_driver_bind_block(p_dispwidget->gfx_widget_fonts.bold.font, + &p_dispwidget->gfx_widget_fonts.bold.raster_block); + font_driver_bind_block(p_dispwidget->gfx_widget_fonts.msg_queue.font, + &p_dispwidget->gfx_widget_fonts.msg_queue.raster_block); + + p_dispwidget->gfx_widget_fonts.regular.raster_block.carr.coords.vertices = 0; + p_dispwidget->gfx_widget_fonts.regular.usage_count = 0; + p_dispwidget->gfx_widget_fonts.bold.raster_block.carr.coords.vertices = 0; + p_dispwidget->gfx_widget_fonts.bold.usage_count = 0; + p_dispwidget->gfx_widget_fonts.msg_queue.raster_block.carr.coords.vertices = 0; + p_dispwidget->gfx_widget_fonts.msg_queue.usage_count = 0; #ifdef HAVE_TRANSLATE /* AI Service overlay */ @@ -1668,7 +1652,7 @@ void gfx_widgets_frame(void *data) } #endif - /* Status Text (fps, framecount, memory, core status message) */ + /* Status Text (FPS, framecount, memory, core status message) */ if ( fps_show || framecount_show || memory_show @@ -1834,9 +1818,9 @@ void gfx_widgets_frame(void *data) &p_dispwidget->gfx_widget_fonts.msg_queue); /* Unbind fonts */ - gfx_widgets_font_unbind(&p_dispwidget->gfx_widget_fonts.regular); - gfx_widgets_font_unbind(&p_dispwidget->gfx_widget_fonts.bold); - gfx_widgets_font_unbind(&p_dispwidget->gfx_widget_fonts.msg_queue); + font_driver_bind_block(p_dispwidget->gfx_widget_fonts.regular.font, NULL); + font_driver_bind_block(p_dispwidget->gfx_widget_fonts.bold.font, NULL); + font_driver_bind_block(p_dispwidget->gfx_widget_fonts.msg_queue.font, NULL); if (video_st->current_video && video_st->current_video->set_viewport) video_st->current_video->set_viewport( @@ -1937,6 +1921,23 @@ static void gfx_widgets_context_reset( unsigned width, unsigned height, bool fullscreen, const char *dir_assets, char *font_path) { + /* Icons */ + static const char + *gfx_widgets_icons_names[MENU_WIDGETS_ICON_LAST] = { + "menu_pause.png", + "menu_frameskip.png", + "menu_rewind.png", + "resume.png", + + "menu_hourglass.png", + "menu_check.png", + "menu_add.png", + "menu_exit.png", + + "menu_info.png", + + "menu_achievements.png" + }; size_t i; /* Load textures */ @@ -2110,6 +2111,15 @@ error: return false; } +static void gfx_widgets_font_free(gfx_widget_font_data_t *font_data) +{ + if (font_data->font) + font_driver_free(font_data->font); + + font_data->font = NULL; + font_data->usage_count = 0; +} + static void gfx_widgets_context_destroy(dispgfx_widget_t *p_dispwidget) { size_t i; @@ -2134,7 +2144,6 @@ static void gfx_widgets_context_destroy(dispgfx_widget_t *p_dispwidget) gfx_widgets_font_free(&p_dispwidget->gfx_widget_fonts.msg_queue); } - void gfx_widgets_deinit(bool widgets_persisting) { dispgfx_widget_t *p_dispwidget = &dispwidget_st; diff --git a/gfx/gfx_widgets.h b/gfx/gfx_widgets.h index 7b0a02ebde..99c6bfbefc 100644 --- a/gfx/gfx_widgets.h +++ b/gfx/gfx_widgets.h @@ -116,7 +116,9 @@ enum disp_widget_flags_enum DISPWIDG_FLAG_UNFOLDING = (1 << 7), /* Color style */ DISPWIDG_FLAG_POSITIVE = (1 << 8), - DISPWIDG_FLAG_NEGATIVE = (1 << 9) + DISPWIDG_FLAG_NEGATIVE = (1 << 9), + DISPWIDG_FLAG_CATEGORY_WARNING = (1 << 10), + DISPWIDG_FLAG_CATEGORY_ERROR = (1 << 11) }; /* There can only be one message animation at a time to diff --git a/gfx/video_crt_switch.c b/gfx/video_crt_switch.c index 352538ac41..c1f72f70b6 100644 --- a/gfx/video_crt_switch.c +++ b/gfx/video_crt_switch.c @@ -23,7 +23,6 @@ #include #include -#include "../retroarch.h" #include #include "video_crt_switch.h" #include "video_display_server.h" @@ -78,15 +77,15 @@ static void crt_store_temp_changes(videocrt_switch_t *p_switch) static void crt_aspect_ratio_switch( videocrt_switch_t *p_switch, unsigned width, unsigned height, - float srm_width, float srm_height) + float srm_width, float srm_height, + unsigned video_aspect_ratio_idx) { - settings_t *settings = config_get_ptr(); float fly_aspect = (float)width / (float)height; p_switch->fly_aspect = fly_aspect; video_driver_state_t *video_st = video_state_get_ptr(); /* We only force aspect ratio for the core provided setting */ - if (settings->uints.video_aspect_ratio_idx != ASPECT_RATIO_CORE) + if (video_aspect_ratio_idx != ASPECT_RATIO_CORE) { RARCH_LOG("[CRT]: Aspect ratio forced by user: %f\n", video_st->aspect_ratio); return; @@ -145,7 +144,9 @@ static void crt_switch_set_aspect( scaled_width = roundf(patched_width * srm_xscale); scaled_height = roundf(patched_height * srm_yscale); - crt_aspect_ratio_switch(p_switch, scaled_width, scaled_height, srm_width, srm_height); + crt_aspect_ratio_switch(p_switch, scaled_width, scaled_height, + srm_width, srm_height, + config_get_ptr()->uints.video_aspect_ratio_idx); } #if !defined(HAVE_VIDEOCORE) @@ -384,9 +385,9 @@ void crt_switch_res_core( int crt_switch_center_adjust, int crt_switch_porch_adjust, int monitor_index, bool dynamic, - int super_width, bool hires_menu) + int super_width, bool hires_menu, + unsigned video_aspect_ratio_idx) { - settings_t *settings = config_get_ptr(); if (height <= 4) { hz = 60; @@ -444,8 +445,8 @@ void crt_switch_res_core( crt_store_temp_changes(p_switch); } - if ( (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CORE) - && video_driver_get_aspect_ratio() != p_switch->fly_aspect) + if ( (video_aspect_ratio_idx == ASPECT_RATIO_CORE) + && video_driver_get_aspect_ratio() != p_switch->fly_aspect) { video_driver_state_t *video_st = video_state_get_ptr(); float fly_aspect = (float)p_switch->fly_aspect; @@ -558,7 +559,8 @@ static void crt_rpi_switch(videocrt_switch_t *p_switch, width = w; - crt_aspect_ratio_switch(p_switch, width,height,width,height); + crt_aspect_ratio_switch(p_switch, width, height, width, height, + config_get_ptr()->uints.video_aspect_ratio_idx); /* following code is the mode line generator */ hfp = ((width * 0.044f) + (width / 112)); diff --git a/gfx/video_crt_switch.h b/gfx/video_crt_switch.h index 860443be39..1b354d80f8 100644 --- a/gfx/video_crt_switch.h +++ b/gfx/video_crt_switch.h @@ -84,7 +84,8 @@ void crt_switch_res_core( int monitor_index, bool dynamic, int super_width, - bool hires_menu); + bool hires_menu, + unsigned video_aspect_ratio_idx); void crt_destroy_modes(videocrt_switch_t *p_switch); diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 339341a7e7..436b018526 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -162,8 +162,11 @@ static const gfx_ctx_driver_t *gfx_ctx_gl_drivers[] = { #ifdef HAVE_OSMESA &gfx_ctx_osmesa, #endif -#ifdef EMSCRIPTEN +#if (defined(EMSCRIPTEN) && defined(HAVE_EGL)) &gfx_ctx_emscripten, +#endif +#ifdef EMSCRIPTEN + &gfx_ctx_emscripten_webgl, #endif &gfx_ctx_null, NULL @@ -198,18 +201,15 @@ struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { { 4.0f / 3.0f , "" } /* full - initialized in video_driver_init_internal */ }; -static INLINE bool realloc_checked(void **ptr, size_t size) +static INLINE bool realloc_checked(void **ptr, size_t len) { void *nptr = NULL; - if (*ptr) - nptr = realloc(*ptr, size); + nptr = realloc(*ptr, len); else - nptr = malloc(size); - + nptr = malloc(len); if (nptr) *ptr = nptr; - return *ptr == nptr; } @@ -1006,7 +1006,7 @@ video_pixel_scaler_t *video_driver_pixel_converter_init( if (!scaler_ctx_gen_filter(scalr_ctx)) goto error; - if (!(scalr_out = calloc(sizeof(uint16_t), size * size))) + if (!(scalr_out = calloc(size * size, sizeof(uint16_t)))) goto error; scalr->scaler_out = scalr_out; @@ -1927,7 +1927,7 @@ void video_driver_unset_stub_frame(void) } /* Get time diff between frames in usec (microseconds) */ -uint32_t video_driver_get_frame_time_delta_usec(void) +retro_time_t video_driver_get_frame_time_delta_usec(void) { static retro_time_t last_time; retro_time_t now_time = cpu_features_get_time_usec(); @@ -2512,11 +2512,15 @@ void video_viewport_get_scaled_integer(struct video_viewport *vp, if (overscale_h_diff <= underscale_h_diff) max_scale_h = overscale_h; + /* Limit width overscale */ + if (max_scale_w * content_width >= width + ((int)content_width / 2)) + max_scale_w = underscale_w; + /* Allow overscale when it is close enough */ if (scale_h_diff > 0 && scale_h_diff < 64) max_scale_h = overscale_h; /* Overscale will be too much even if it is closer */ - else if ((scale_h_diff < -155 && scale_h_diff > (int)-content_height / 2) + else if ((scale_h_diff < -140 && scale_h_diff >= (int)-content_height / 2) || (scale_h_diff < -30 && scale_h_diff > -50) || (scale_h_diff > 20)) max_scale_h = underscale_h; @@ -2617,7 +2621,7 @@ void video_viewport_get_scaled_integer(struct video_viewport *vp, || axis == VIDEO_SCALE_INTEGER_AXIS_XHALF) { if ( max_scale_h == (height / content_height) - && content_height / 300 + && content_height / ((rotation % 2) ? 288 : 300) && content_height * max_scale_h < height * 0.90f ) { @@ -3641,7 +3645,7 @@ void video_driver_frame(const void *data, unsigned width, static retro_time_t curr_time; static retro_time_t fps_time; static float last_fps, frame_time; - static uint16_t frame_time_accumulator; + static int32_t frame_time_accumulator; /* Mark the start of nonblock state for * ignoring initial previous frame time */ static int8_t nonblock_active; @@ -3725,7 +3729,7 @@ void video_driver_frame(const void *data, unsigned width, || (last_frame_duped && !!data)) ) { - uint16_t frame_time_accumulator_prev = frame_time_accumulator; + int32_t frame_time_accumulator_prev = frame_time_accumulator; uint16_t frame_time_delta = new_time - last_time; uint16_t frame_time_target = video_info.frame_time_target; @@ -3793,11 +3797,17 @@ void video_driver_frame(const void *data, unsigned width, video_st->frame_time_samples[write_index] = frame_time; fps_time = new_time; - /* Consider frame dropped when frame time exceeds 1.75x target */ + /* Try to count dropped frames */ if ( video_st->frame_count > 4 - && !menu_is_alive - && frame_time > 1000000.0f / video_info.refresh_rate * 1.75f) - video_st->frame_drop_count++; + && !menu_is_alive) + { + float frame_time_av_info = 1000000.0f / video_st->av_info.timing.fps; + + if ( (frame_time > frame_time_av_info * 1.75f) + || (runloop_st->core_run_time > frame_time_av_info * 1.5f) + ) + video_st->frame_drop_count++; + } if (video_info.fps_show) { @@ -4132,55 +4142,57 @@ void video_driver_frame(const void *data, unsigned width, " Viewport: %u x %u\n" " - Scale: %u x %u\n" " - Scale X/Y: %2.2f / %2.2f\n" - " Refresh: %5.2f hz\n" - " Frame Rate: %5.2f fps\n" - " Frame Time: %5.2f ms\n" - " - Deviation: %5.2f %%\n" + " Refresh: %6.2f hz\n" + " Frame Rate:%7.2f fps\n" + " Frame Time: %6.2f ms\n" + " - Deviation:%6.2f %%\n" " Frames: %8" PRIu64"\n" " - Dropped: %5u\n" "AUDIO: %s\n" - " Saturation: %5.2f %%\n" - " Deviation: %5.2f %%\n" - " Underrun: %5.2f %%\n" - " Blocking: %5.2f %%\n" + " Saturation: %6.2f %%\n" + " Deviation: %6.2f %%\n" + " Underrun: %6.2f %%\n" + " Blocking: %6.2f %%\n" " Samples: %8d\n" , - video_st->frame_cache_width, - video_st->frame_cache_height, - av_info->geometry.base_width, - av_info->geometry.base_height, - av_info->geometry.max_width, - av_info->geometry.max_height, - av_info->geometry.aspect_ratio, - av_info->timing.fps, - av_info->timing.sample_rate, - video_st->current_video->ident, - video_info.width, - video_info.height, - video_info.scale_width, - video_info.scale_height, - (float)video_info.scale_width / ((rotation % 2) ? (float)video_st->frame_cache_height : (float)video_st->frame_cache_width), - (float)video_info.scale_height / ((rotation % 2) ? (float)video_st->frame_cache_width : (float)video_st->frame_cache_height), - video_info.refresh_rate, - last_fps, - frame_time / 1000.0f, - 100.0f * stddev, - video_st->frame_count, - video_st->frame_drop_count, - audio_state_get_ptr()->current_audio->ident, - audio_stats.average_buffer_saturation, - audio_stats.std_deviation_percentage, - audio_stats.close_to_underrun, - audio_stats.close_to_blocking, - audio_stats.samples + video_st->frame_cache_width, + video_st->frame_cache_height, + av_info->geometry.base_width, + av_info->geometry.base_height, + av_info->geometry.max_width, + av_info->geometry.max_height, + av_info->geometry.aspect_ratio, + av_info->timing.fps, + av_info->timing.sample_rate, + video_st->current_video->ident, + video_info.width, + video_info.height, + video_info.scale_width, + video_info.scale_height, + (float)video_info.scale_width / ((rotation % 2) + ? (float)video_st->frame_cache_height : (float)video_st->frame_cache_width), + (float)video_info.scale_height / ((rotation % 2) + ? (float)video_st->frame_cache_width : (float)video_st->frame_cache_height), + video_info.refresh_rate, + last_fps, + frame_time / 1000.0f, + 100.0f * stddev, + video_st->frame_count, + video_st->frame_drop_count, + audio_state_get_ptr()->current_audio->ident, + audio_stats.average_buffer_saturation, + audio_stats.std_deviation_percentage, + audio_stats.close_to_underrun, + audio_stats.close_to_blocking, + audio_stats.samples ); - /* TODO/FIXME - localize */ - if ( (video_st->frame_delay_target > 0) - || (video_info.runahead && !video_info.runahead_second_instance)) - __len += strlcpy(video_info.stat_text + __len, "LATENCY\n", - sizeof(video_info.stat_text) - __len); + if ( (video_st->frame_delay_target > 0) + || (video_info.runahead) + || (video_info.preemptive_frames)) + __len += strlcpy(video_info.stat_text + __len, "LATENCY\n", + sizeof(video_info.stat_text) - __len); /* TODO/FIXME - localize */ if (video_st->frame_delay_target > 0) @@ -4301,7 +4313,9 @@ void video_driver_frame(const void *data, unsigned width, video_info.monitor_index, dynamic_super_width, video_info.crt_switch_resolution_super, - video_info.crt_switch_hires_menu); + video_info.crt_switch_hires_menu, + config_get_ptr()->uints.video_aspect_ratio_idx + ); } else if (!video_info.crt_switch_resolution) #endif @@ -4673,7 +4687,9 @@ void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_delay_au uint8_t count_pos = 0; uint8_t count_min = 0; uint8_t count_med = 0; +#if FRAME_DELAY_AUTO_DEBUG uint8_t count_max = 0; +#endif int8_t mode = 0; /* Calculate average frame time */ @@ -4702,8 +4718,10 @@ void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_delay_au count_min++; if (frame_time_i > frame_time_limit_med) count_med++; +#if FRAME_DELAY_AUTO_DEBUG if (frame_time_i > frame_time_limit_max) count_max++; +#endif } frame_time_avg += frame_time_i; diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 7dfc555d5e..a5cb80d986 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -915,7 +915,7 @@ void video_driver_unset_stub_frame(void); float video_driver_get_core_aspect(void); -uint32_t video_driver_get_frame_time_delta_usec(void); +retro_time_t video_driver_get_frame_time_delta_usec(void); float video_driver_get_original_fps(void); @@ -1384,6 +1384,7 @@ extern const gfx_ctx_driver_t gfx_ctx_cgl; extern const gfx_ctx_driver_t gfx_ctx_cocoagl; extern const gfx_ctx_driver_t gfx_ctx_cocoavk; extern const gfx_ctx_driver_t gfx_ctx_emscripten; +extern const gfx_ctx_driver_t gfx_ctx_emscripten_webgl; extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev; extern const gfx_ctx_driver_t gfx_ctx_khr_display; extern const gfx_ctx_driver_t gfx_ctx_gdi; diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index 84f84bc750..c66d19f249 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -83,26 +83,7 @@ enum wildcard_type struct wildcard_token { enum wildcard_type token_id; - char token_name[64]; - size_t token_size; -}; - -static struct wildcard_token wildcard_tokens[SHADER_NUM_WILDCARDS] = { - {RARCH_WILDCARD_CONTENT_DIR, "$CONTENT-DIR$", STRLEN_CONST("$CONTENT-DIR$")}, - {RARCH_WILDCARD_CORE, "$CORE$", STRLEN_CONST("$CORE$")}, - {RARCH_WILDCARD_GAME, "$GAME$", STRLEN_CONST("$GAME$")}, - {RARCH_WILDCARD_VIDEO_DRIVER, "$VID-DRV$", STRLEN_CONST("$VID-DRV$")}, - {RARCH_WILDCARD_VIDEO_DRIVER_PRESET_EXT, "$VID-DRV-PRESET-EXT$", STRLEN_CONST("$VID-DRV-PRESET-EXT$")}, - {RARCH_WILDCARD_VIDEO_DRIVER_SHADER_EXT, "$VID-DRV-SHADER-EXT$", STRLEN_CONST("$VID-DRV-SHADER-EXT$")}, - {RARCH_WILDCARD_CORE_REQUESTED_ROTATION, "$CORE-REQ-ROT$", STRLEN_CONST("$CORE-REQ-ROT$")}, - {RARCH_WILDCARD_VIDEO_ALLOW_CORE_ROTATION, "$VID-ALLOW-CORE-ROT$", STRLEN_CONST("$VID-ALLOW-CORE-ROT$")}, - {RARCH_WILDCARD_VIDEO_USER_ROTATION, "$VID-USER-ROT$", STRLEN_CONST("$VID-USER-ROT$")}, - {RARCH_WILDCARD_VIDEO_FINAL_ROTATION, "$VID-FINAL-ROT$", STRLEN_CONST("$VID-FINAL-ROT$")}, - {RARCH_WILDCARD_SCREEN_ORIENTATION, "$SCREEN-ORIENT$", STRLEN_CONST("$SCREEN-ORIENT$")}, - {RARCH_WILDCARD_VIEWPORT_ASPECT_ORIENTATION, "$VIEW-ASPECT-ORIENT$", STRLEN_CONST("$VIEW-ASPECT-ORIENT$")}, - {RARCH_WILDCARD_CORE_ASPECT_ORIENTATION, "$CORE-ASPECT-ORIENT$", STRLEN_CONST("$CORE-ASPECT-ORIENT$")}, - {RARCH_WILDCARD_PRESET_DIR, "$PRESET-DIR$", STRLEN_CONST("$PRESET-DIR$")}, - {RARCH_WILDCARD_PRESET, "$PRESET$", STRLEN_CONST("$PRESET$")}, + char token_name[24]; }; /* TODO/FIXME - global state - perhaps move outside this file */ @@ -110,7 +91,7 @@ static path_change_data_t *file_change_data = NULL; /** * fill_pathname_expanded_and_absolute: - * @param out_path + * @param s * String to write into. * @param in_refpath * Used to get the base path if in_path is relative. @@ -123,29 +104,18 @@ static path_change_data_t *file_change_data = NULL; * If the path was relative it will take this path and get the * absolute path using in_refpath as the path to extract a base path. * - * out_path is filled with the absolute path + * s is filled with the absolute path **/ -static void fill_pathname_expanded_and_absolute( - char *out_path, size_t out_size, - const char *in_refpath, - const char *in_path) +static void fill_pathname_expanded_and_absolute(char *s, size_t len, + const char *in_refpath, const char *in_path) { - char expanded_path[PATH_MAX_LENGTH]; - - expanded_path[0] = '\0'; - /* Expand paths which start with :\ to an absolute path */ - fill_pathname_expand_special(expanded_path, - in_path, sizeof(expanded_path)); - + fill_pathname_expand_special(s, in_path, len); /* Resolve the reference path relative to the config */ - if (path_is_absolute(expanded_path)) - strlcpy(out_path, expanded_path, out_size); - else - fill_pathname_resolve_relative(out_path, in_refpath, - in_path, out_size); - - pathname_conform_slashes_to_os(out_path); + if (!path_is_absolute(s)) + fill_pathname_resolve_relative(s, in_refpath, + in_path, len); + pathname_conform_slashes_to_os(s); } /** @@ -230,16 +200,32 @@ static void fill_pathname_expanded_and_absolute( * after replacing the wildcards does not exist on disk, * the path returned will be uneffected. **/ -static void video_shader_replace_wildcards(char *inout_absolute_path, - const unsigned in_absolute_path_length, char *in_preset_path) +static void video_shader_replace_wildcards(char *s, size_t len, char *in_preset_path) { int i = 0; char replaced_path[PATH_MAX_LENGTH]; + static struct wildcard_token wildcard_tokens[SHADER_NUM_WILDCARDS] = { + {RARCH_WILDCARD_CONTENT_DIR, "$CONTENT-DIR$"}, + {RARCH_WILDCARD_CORE, "$CORE$"}, + {RARCH_WILDCARD_GAME, "$GAME$"}, + {RARCH_WILDCARD_VIDEO_DRIVER, "$VID-DRV$"}, + {RARCH_WILDCARD_VIDEO_DRIVER_PRESET_EXT, "$VID-DRV-PRESET-EXT$"}, + {RARCH_WILDCARD_VIDEO_DRIVER_SHADER_EXT, "$VID-DRV-SHADER-EXT$"}, + {RARCH_WILDCARD_CORE_REQUESTED_ROTATION, "$CORE-REQ-ROT$"}, + {RARCH_WILDCARD_VIDEO_ALLOW_CORE_ROTATION, "$VID-ALLOW-CORE-ROT$"}, + {RARCH_WILDCARD_VIDEO_USER_ROTATION, "$VID-USER-ROT$"}, + {RARCH_WILDCARD_VIDEO_FINAL_ROTATION, "$VID-FINAL-ROT$"}, + {RARCH_WILDCARD_SCREEN_ORIENTATION, "$SCREEN-ORIENT$"}, + {RARCH_WILDCARD_VIEWPORT_ASPECT_ORIENTATION, "$VIEW-ASPECT-ORIENT$"}, + {RARCH_WILDCARD_CORE_ASPECT_ORIENTATION, "$CORE-ASPECT-ORIENT$"}, + {RARCH_WILDCARD_PRESET_DIR, "$PRESET-DIR$"}, + {RARCH_WILDCARD_PRESET, "$PRESET$"}, + }; - if (!strstr(inout_absolute_path, RARCH_WILDCARD_DELIMITER)) + if (!strstr(s, RARCH_WILDCARD_DELIMITER)) return; - strlcpy(replaced_path, inout_absolute_path, sizeof(replaced_path)); + strlcpy(replaced_path, s, sizeof(replaced_path)); /* Step through the wildcards while we can still find the * delimiter in the replaced path @@ -249,7 +235,7 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, /* If the wildcard text is in the path then process it */ if (strstr(replaced_path, wildcard_tokens[i].token_name)) { - size_t replace_len = 0; + size_t _len = 0; char replace_text[PATH_MAX_LENGTH]; switch (wildcard_tokens[i].token_id) @@ -270,13 +256,13 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, path_remove_extension(content_dir_name); if (string_is_not_equal_fast(content_dir_name, "", sizeof(""))) - replace_len = strlcpy(replace_text, content_dir_name, sizeof(replace_text)); + _len = strlcpy(replace_text, content_dir_name, sizeof(replace_text)); else replace_text[0] = '\0'; } break; case RARCH_WILDCARD_CORE: - strlcpy(replace_text, runloop_state_get_ptr()->system.info.library_name, sizeof(replace_text)); + _len = strlcpy(replace_text, runloop_state_get_ptr()->system.info.library_name, sizeof(replace_text)); break; case RARCH_WILDCARD_GAME: { @@ -284,82 +270,60 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, if (path_basename) path_basename = path_basename_nocompression(path_basename); if (path_basename) - replace_len = strlcpy(replace_text, path_basename, sizeof(replace_text)); + _len = strlcpy(replace_text, path_basename, sizeof(replace_text)); else replace_text[0] = '\0'; } break; case RARCH_WILDCARD_VIDEO_DRIVER: - strlcpy(replace_text, config_get_ptr()->arrays.video_driver, sizeof(replace_text)); + _len = strlcpy(replace_text, config_get_ptr()->arrays.video_driver, sizeof(replace_text)); break; case RARCH_WILDCARD_CORE_REQUESTED_ROTATION: - { - char rotation_replace_strings[4][64] = { - "CORE-REQ-ROT-0", - "CORE-REQ-ROT-90", - "CORE-REQ-ROT-180", - "CORE-REQ-ROT-270" - }; - replace_len = strlcpy(replace_text, - rotation_replace_strings[retroarch_get_core_requested_rotation()], - sizeof(replace_text)); - } + _len = strlcpy(replace_text, "CORE-REQ-ROT-", sizeof(replace_text)); + _len += snprintf( + replace_text + _len, + sizeof(replace_text) - _len, + "%d", + retroarch_get_core_requested_rotation() * 90); break; case RARCH_WILDCARD_VIDEO_ALLOW_CORE_ROTATION: + _len = strlcpy(replace_text, "VID-ALLOW-CORE-ROT-O", + sizeof(replace_text)); if (config_get_ptr()->bools.video_allow_rotate) - replace_len = strlcpy(replace_text, "VID-ALLOW-CORE-ROT-ON", - sizeof(replace_text)); + _len += strlcpy(replace_text + _len, "N", sizeof(replace_text) - _len); else - replace_len = strlcpy(replace_text, "VID-ALLOW-CORE-ROT-OFF", - sizeof(replace_text)); + _len += strlcpy(replace_text + _len, "FF", sizeof(replace_text) - _len); break; case RARCH_WILDCARD_VIDEO_USER_ROTATION: - { - char rotation_replace_strings[4][64] = { - "VID-USER-ROT-0", - "VID-USER-ROT-90", - "VID-USER-ROT-180", - "VID-USER-ROT-270" - }; - settings_t *settings = config_get_ptr(); - replace_len = strlcpy(replace_text, - rotation_replace_strings[settings->uints.video_rotation], - sizeof(replace_text)); - } + _len = strlcpy(replace_text, "VID-USER-ROT-", sizeof(replace_text)); + _len += snprintf( + replace_text + _len, + sizeof(replace_text) - _len, + "%d", + config_get_ptr()->uints.video_rotation * 90); break; case RARCH_WILDCARD_VIDEO_FINAL_ROTATION: - { - char rotation_replace_strings[4][64] = { - "VID-FINAL-ROT-0", - "VID-FINAL-ROT-90", - "VID-FINAL-ROT-180", - "VID-FINAL-ROT-270" - }; - replace_len = strlcpy(replace_text, - rotation_replace_strings[retroarch_get_rotation()], - sizeof(replace_text)); - } + _len = strlcpy(replace_text, "VID-FINAL-ROT-", sizeof(replace_text)); + _len += snprintf( + replace_text + _len, + sizeof(replace_text) - _len, + "%d", + retroarch_get_rotation() * 90); break; case RARCH_WILDCARD_SCREEN_ORIENTATION: - { - char rotation_replace_strings[4][64] = { - "SCREEN-ORIENT-0", - "SCREEN-ORIENT-90", - "SCREEN-ORIENT-180", - "SCREEN-ORIENT-270" - }; - replace_len = strlcpy(replace_text, - rotation_replace_strings[config_get_ptr()->uints.screen_orientation], - sizeof(replace_text)); - } + _len = strlcpy(replace_text, "SCREEN-ORIENT-", sizeof(replace_text)); + _len += snprintf( + replace_text + _len, + sizeof(replace_text) - _len, + "%d", + config_get_ptr()->uints.screen_orientation * 90); break; case RARCH_WILDCARD_CORE_ASPECT_ORIENTATION: { const int requested_rotation = retroarch_get_core_requested_rotation(); - replace_len = strlcpy(replace_text, + _len = strlcpy(replace_text, (video_driver_get_core_aspect() < 1 || requested_rotation == 1 || requested_rotation == 3) - ? "CORE-ASPECT-ORIENT-VERT" - : "CORE-ASPECT-ORIENT-HORZ", + ? "CORE-ASPECT-ORIENT-VERT" : "CORE-ASPECT-ORIENT-HORZ", sizeof(replace_text)); } break; @@ -368,7 +332,7 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, unsigned viewport_width = 0; unsigned viewport_height = 0; video_driver_get_size(&viewport_width, &viewport_height); - replace_len = strlcpy(replace_text, + _len = strlcpy(replace_text, ((float)viewport_width / viewport_height < 1) ? "VIEW-ASPECT-ORIENT-VERT" : "VIEW-ASPECT-ORIENT-HORZ", @@ -378,13 +342,17 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, case RARCH_WILDCARD_PRESET_DIR: { char preset_dir_name[DIR_MAX_LENGTH]; - fill_pathname_parent_dir_name(preset_dir_name, in_preset_path, sizeof(preset_dir_name)); + fill_pathname_parent_dir_name(preset_dir_name, + in_preset_path, sizeof(preset_dir_name)); if (string_is_not_equal_fast(preset_dir_name, "", sizeof(""))) - strlcpy(preset_dir_name, path_basename_nocompression(preset_dir_name), sizeof(preset_dir_name)); + strlcpy(preset_dir_name, + path_basename_nocompression(preset_dir_name), + sizeof(preset_dir_name)); if (string_is_not_equal_fast(preset_dir_name, "", sizeof(""))) path_remove_extension(preset_dir_name); if (string_is_not_equal_fast(preset_dir_name, "", sizeof(""))) - replace_len = strlcpy(replace_text, preset_dir_name, sizeof(replace_text)); + _len = strlcpy(replace_text, + preset_dir_name, sizeof(replace_text)); else replace_text[0] = '\0'; } @@ -392,11 +360,14 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, case RARCH_WILDCARD_PRESET: { char preset_name[NAME_MAX_LENGTH]; - strlcpy(preset_name, path_basename_nocompression(in_preset_path), sizeof(preset_name)); + strlcpy(preset_name, + path_basename_nocompression(in_preset_path), + sizeof(preset_name)); if (string_is_not_equal_fast(preset_name, "", sizeof(""))) path_remove_extension(preset_name); if (string_is_not_equal_fast(preset_name, "", sizeof(""))) - replace_len = strlcpy(replace_text, preset_name, sizeof(replace_text)); + _len = strlcpy(replace_text, + preset_name, sizeof(replace_text)); else replace_text[0] = '\0'; } @@ -408,11 +379,11 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, video_context_driver_get_flags(&flags); if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_CG)) - replace_len = strlcpy(replace_text, "cg", sizeof(replace_text)); + _len = strlcpy(replace_text, "cg", sizeof(replace_text)); else if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_GLSL)) - replace_len = strlcpy(replace_text, "glsl", sizeof(replace_text)); + _len = strlcpy(replace_text, "glsl", sizeof(replace_text)); else if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_SLANG)) - replace_len = strlcpy(replace_text, "slang", sizeof(replace_text)); + _len = strlcpy(replace_text, "slang", sizeof(replace_text)); else replace_text[0] = '\0'; } @@ -424,11 +395,11 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, video_context_driver_get_flags(&flags); if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_CG)) - replace_len = strlcpy(replace_text, "cgp", sizeof(replace_text)); + _len = strlcpy(replace_text, "cgp", sizeof(replace_text)); else if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_GLSL)) - replace_len = strlcpy(replace_text, "glslp", sizeof(replace_text)); + _len = strlcpy(replace_text, "glslp", sizeof(replace_text)); else if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_SLANG)) - replace_len = strlcpy(replace_text, "slangp", sizeof(replace_text)); + _len = strlcpy(replace_text, "slangp", sizeof(replace_text)); else replace_text[0] = '\0'; } @@ -441,19 +412,17 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, char *replace_output = string_replace_substring(replaced_path, sizeof(replaced_path), wildcard_tokens[i].token_name, - wildcard_tokens[i].token_size, + strlen(wildcard_tokens[i].token_name), replace_text, - replace_len); - + _len); strlcpy(replaced_path, replace_output, sizeof(replaced_path)); - free(replace_output); } } } if (path_is_valid(replaced_path)) - strlcpy(inout_absolute_path, replaced_path, in_absolute_path_length); + strlcpy(s, replaced_path, len); else { /* If a file does not exist at the location of the replaced path @@ -461,7 +430,7 @@ static void video_shader_replace_wildcards(char *inout_absolute_path, RARCH_DBG("\n[Shaders]: Filepath after wildcard replacement can't be found:\n"); RARCH_DBG(" \"%s\" \n", replaced_path); RARCH_DBG(" Falling back to original Filepath\n"); - RARCH_DBG(" \"%s\" \n\n", inout_absolute_path); + RARCH_DBG(" \"%s\" \n\n", s); } } @@ -493,13 +462,11 @@ static void video_shader_gather_reference_path_list( while (ref_tmp) { char* reference_preset_path = (char*)malloc(PATH_MAX_LENGTH); - /* Get the absolute path and replace wildcards in the path */ fill_pathname_expanded_and_absolute(reference_preset_path, PATH_MAX_LENGTH, conf->path, ref_tmp->path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ video_shader_replace_wildcards(reference_preset_path, PATH_MAX_LENGTH, conf->path); - video_shader_gather_reference_path_list(in_path_linked_list, reference_preset_path, reference_depth + 1); - free(reference_preset_path); ref_tmp = ref_tmp->next; } @@ -612,6 +579,7 @@ static bool video_shader_parse_pass(config_file_t *conf, /* Get the absolute path and replace wildcards in the path */ fill_pathname_expanded_and_absolute(pass->source.path, PATH_MAX_LENGTH, conf->path, tmp_path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ video_shader_replace_wildcards(pass->source.path, PATH_MAX_LENGTH, conf->path); @@ -845,8 +813,11 @@ static bool video_shader_parse_textures(config_file_t *conf, config_get_path(conf, id, texture_path, sizeof(texture_path)); /* Get the absolute path and replace wildcards in the path */ - fill_pathname_expanded_and_absolute(shader->lut[shader->luts].path, PATH_MAX_LENGTH, conf->path, texture_path); - video_shader_replace_wildcards(shader->lut[shader->luts].path, PATH_MAX_LENGTH, conf->path); + fill_pathname_expanded_and_absolute(shader->lut[shader->luts].path, + PATH_MAX_LENGTH, conf->path, texture_path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ + video_shader_replace_wildcards(shader->lut[shader->luts].path, + PATH_MAX_LENGTH, conf->path); strlcpy(shader->lut[shader->luts].id, id, sizeof(shader->lut[shader->luts].id)); @@ -1189,6 +1160,18 @@ static bool video_shader_write_root_preset(const struct video_shader *shader, config_set_path(conf, key, tmp_rel); + _len = strlcpy(key, "alias", sizeof(key)); + strlcpy(key + _len, formatted_num, sizeof(key) - _len); + config_set_string(conf, key, pass->alias); + + _len = strlcpy(key, "wrap_mode", sizeof(key)); + strlcpy(key + _len, formatted_num, sizeof(key) - _len); + config_set_string(conf, key, video_shader_wrap_mode_to_str(pass->wrap)); + + _len = strlcpy(key, "mipmap_input", sizeof(key)); + strlcpy(key + _len, formatted_num, sizeof(key) - _len); + config_set_string(conf, key, pass->mipmap ? "true" : "false"); + if (pass->filter != RARCH_FILTER_UNSPEC) { _len = strlcpy(key, "filter_linear", sizeof(key)); @@ -1199,10 +1182,6 @@ static bool video_shader_write_root_preset(const struct video_shader *shader, : "false"); } - _len = strlcpy(key, "wrap_mode", sizeof(key)); - strlcpy(key + _len, formatted_num, sizeof(key) - _len); - config_set_string(conf, key, video_shader_wrap_mode_to_str(pass->wrap)); - if (pass->frame_count_mod) { _len = strlcpy(key, "frame_count_mod", sizeof(key)); @@ -1210,14 +1189,6 @@ static bool video_shader_write_root_preset(const struct video_shader *shader, config_set_int(conf, key, pass->frame_count_mod); } - _len = strlcpy(key, "mipmap_input", sizeof(key)); - strlcpy(key + _len, formatted_num, sizeof(key) - _len); - config_set_string(conf, key, pass->mipmap ? "true" : "false"); - - _len = strlcpy(key, "alias", sizeof(key)); - strlcpy(key + _len, formatted_num, sizeof(key) - _len); - config_set_string(conf, key, pass->alias); - video_shader_write_fbo(conf, formatted_num, &pass->fbo); } @@ -1245,16 +1216,24 @@ static bool video_shader_write_root_preset(const struct video_shader *shader, /* Step through the textures in the shader */ for (i = 0; i < shader->luts; i++) { + size_t _len; + char k[128]; fill_pathname_abbreviated_or_relative(tmp_rel, tmp_base, shader->lut[i].path, PATH_MAX_LENGTH); pathname_make_slashes_portable(tmp_rel); config_set_string(conf, shader->lut[i].id, tmp_rel); + _len = strlcpy(k, shader->lut[i].id, sizeof(k)); + + /* Mipmap On or Off */ + strlcpy(k + _len, "_mipmap", sizeof(k) - _len); + config_set_string(conf, k, shader->lut[i].mipmap + ? "true" + : "false"); + /* Linear filter ON or OFF */ if (shader->lut[i].filter != RARCH_FILTER_UNSPEC) { - char k[128]; - size_t _len = strlcpy(k, shader->lut[i].id, sizeof(k)); strlcpy(k + _len, "_linear", sizeof(k) - _len); config_set_string(conf, k, (shader->lut[i].filter == RARCH_FILTER_LINEAR) @@ -1263,23 +1242,9 @@ static bool video_shader_write_root_preset(const struct video_shader *shader, } /* Wrap Mode */ - { - char k[128]; - size_t _len = strlcpy(k, shader->lut[i].id, sizeof(k)); - strlcpy(k + _len, "_wrap_mode", sizeof(k) - _len); - config_set_string(conf, k, - video_shader_wrap_mode_to_str(shader->lut[i].wrap)); - } - - /* Mipmap On or Off */ - { - char k[128]; - size_t _len = strlcpy(k, shader->lut[i].id, sizeof(k)); - strlcpy(k + _len, "_mipmap", sizeof(k) - _len); - config_set_string(conf, k, shader->lut[i].mipmap - ? "true" - : "false"); - } + strlcpy(k + _len, "_wrap_mode", sizeof(k) - _len); + config_set_string(conf, k, + video_shader_wrap_mode_to_str(shader->lut[i].wrap)); } } @@ -1322,8 +1287,11 @@ static config_file_t *video_shader_get_root_preset_config(const char *path) } /* Get the absolute path and replace wildcards in the path */ - fill_pathname_expanded_and_absolute(nested_reference_path, PATH_MAX_LENGTH, conf->path, conf->references->path); - video_shader_replace_wildcards(nested_reference_path, PATH_MAX_LENGTH, conf->path); + fill_pathname_expanded_and_absolute(nested_reference_path, + PATH_MAX_LENGTH, conf->path, conf->references->path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ + video_shader_replace_wildcards(nested_reference_path, + PATH_MAX_LENGTH, conf->path); /* Create a new config from the referenced path */ config_file_free(conf); @@ -1408,11 +1376,15 @@ static bool video_shader_check_reference_chain_for_save( } /* Get the absolute path and replace wildcards in the path */ - fill_pathname_expanded_and_absolute(nested_ref_path, PATH_MAX_LENGTH, conf->path, conf->references->path); - video_shader_replace_wildcards(nested_ref_path, PATH_MAX_LENGTH, conf->path); + fill_pathname_expanded_and_absolute(nested_ref_path, + PATH_MAX_LENGTH, conf->path, conf->references->path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ + video_shader_replace_wildcards(nested_ref_path, + PATH_MAX_LENGTH, conf->path); - /* If one of the reference paths is the same as the file we want to save then this reference chain would be - * self-referential / cyclical and we can't save this as a simple preset*/ + /* If one of the reference paths is the same as the file we want to save, + * then this reference chain would be self-referential / cyclical and + * we can't save this as a simple preset */ if (string_is_equal(nested_ref_path, path_to_save_conformed)) { RARCH_WARN("[Shaders]: Saving preset:\n" @@ -1441,7 +1413,7 @@ static bool video_shader_check_reference_chain_for_save( break; } - ref_depth += 1; + ref_depth++; } free(path_to_save_conformed); @@ -1550,6 +1522,7 @@ static bool video_shader_write_referenced_preset( /* Get the absolute path and replace wildcards in the path */ fill_pathname_expanded_and_absolute(abs_tmp_ref_path, PATH_MAX_LENGTH, ref_conf->path, ref_conf->references->path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ video_shader_replace_wildcards(abs_tmp_ref_path, PATH_MAX_LENGTH, ref_conf->path); pathname_conform_slashes_to_os(abs_tmp_ref_path); @@ -1592,6 +1565,7 @@ static bool video_shader_write_referenced_preset( /* Get the absolute path and replace wildcards in the path */ fill_pathname_expanded_and_absolute(path_to_ref, PATH_MAX_LENGTH, ref_conf->path, ref_conf->references->path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ video_shader_replace_wildcards(path_to_ref, PATH_MAX_LENGTH, ref_conf->path); @@ -1615,6 +1589,7 @@ static bool video_shader_write_referenced_preset( /* Get the absolute path and replace wildcards in the path */ fill_pathname_expanded_and_absolute(path_to_ref, PATH_MAX_LENGTH, ref_conf->path, ref_conf->references->path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ video_shader_replace_wildcards(path_to_ref, PATH_MAX_LENGTH, ref_conf->path); } @@ -1915,7 +1890,7 @@ end: **/ static bool video_shader_load_root_config_into_shader( config_file_t *conf, - settings_t *settings, + bool video_shader_watch_files, struct video_shader *shader) { size_t i; @@ -1946,7 +1921,7 @@ static bool video_shader_load_root_config_into_shader( strlcpy(shader->loaded_preset_path, conf->path, sizeof(shader->loaded_preset_path)); - if (settings->bools.video_shader_watch_files) + if (video_shader_watch_files) { union string_list_elem_attr attr; int flags = @@ -2083,22 +2058,22 @@ static bool video_shader_override_values(config_file_t *override_conf, if (config_get_entry(override_conf, shader->lut[i].id)) { char *tex_path = (char*)malloc(PATH_MAX_LENGTH); - /* Texture path from the config */ - config_get_path(override_conf, shader->lut[i].id, tex_path, PATH_MAX_LENGTH); - + config_get_path(override_conf, shader->lut[i].id, tex_path, + PATH_MAX_LENGTH); /* Get the absolute path and replace wildcards in the path */ - fill_pathname_expanded_and_absolute(override_tex_path, PATH_MAX_LENGTH, override_conf->path, tex_path); - video_shader_replace_wildcards(override_tex_path, PATH_MAX_LENGTH, override_conf->path); - - strlcpy(shader->lut[i].path, override_tex_path, sizeof(shader->lut[i].path)); - + fill_pathname_expanded_and_absolute(override_tex_path, + PATH_MAX_LENGTH, override_conf->path, tex_path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ + video_shader_replace_wildcards(override_tex_path, + PATH_MAX_LENGTH, override_conf->path); + strlcpy(shader->lut[i].path, override_tex_path, + sizeof(shader->lut[i].path)); #ifdef DEBUG RARCH_DBG("[Shaders]: Texture: \"%s\" = %s.\n", shader->lut[i].id, shader->lut[i].path); #endif - free(tex_path); return_val = true; } @@ -2280,7 +2255,8 @@ bool video_shader_load_preset_into_shader(const char *path, if (string_is_equal(root_conf->path, path)) { /* Load the config from the shader chain from the first reference into the shader */ - video_shader_load_root_config_into_shader(root_conf, config_get_ptr(), shader); + video_shader_load_root_config_into_shader(root_conf, + config_get_ptr()->bools.video_shader_watch_files, shader); goto end; } @@ -2302,10 +2278,10 @@ bool video_shader_load_preset_into_shader(const char *path, { config_file_t *tmp_conf = NULL; char *path_to_ref = (char*)malloc(PATH_MAX_LENGTH); - /* Get the absolute path and replace wildcards in the path */ fill_pathname_expanded_and_absolute(path_to_ref, PATH_MAX_LENGTH, conf->path, path_list_tmp->path); + /* TODO/FIXME - dehardcode PATH_MAX_LENGTH */ video_shader_replace_wildcards(path_to_ref, PATH_MAX_LENGTH, conf->path); if ((tmp_conf = video_shader_get_root_preset_config(path_to_ref))) @@ -2313,8 +2289,7 @@ bool video_shader_load_preset_into_shader(const char *path, /* Check if the config is a valid shader chain config If the config has a shaders entry then it is considered a shader chain config, vs a config which may only have - parameter values and texture overrides - */ + parameter values and texture overrides */ if (config_get_entry(tmp_conf, "shaders")) { RARCH_WARN("\n[Shaders]: Additional #reference entries pointing at shader chain presets are not supported: \"%s\".\n", path_to_ref); @@ -2334,7 +2309,8 @@ bool video_shader_load_preset_into_shader(const char *path, } /* Load the config from the shader chain from the first reference into the shader */ - video_shader_load_root_config_into_shader(root_conf, config_get_ptr(), shader); + video_shader_load_root_config_into_shader(root_conf, + config_get_ptr()->bools.video_shader_watch_files, shader); /* Set Path for originally loaded preset because it is different than the root preset path */ strlcpy(shader->loaded_preset_path, path, sizeof(shader->loaded_preset_path)); @@ -2347,10 +2323,8 @@ bool video_shader_load_preset_into_shader(const char *path, override_paths_list = path_linked_list_new(); video_shader_gather_reference_path_list(override_paths_list, conf->path, 0); - /* - * Step through the references and apply overrides for each one - * Start on the second item since the first is empty - */ + /* Step through the references and apply overrides for each one + * Start on the second item since the first is empty */ path_list_tmp = (struct path_linked_list*)override_paths_list; while (path_list_tmp) { @@ -2559,14 +2533,13 @@ static bool video_shader_dir_init_shader_internal( static void video_shader_dir_init_shader( void *menu_driver_data_, - settings_t *settings, + const char *directory_video_shader, + const char *directory_menu_config, + bool show_hidden_files, + bool shader_remember_last_dir, + bool video_shader_remember_last_dir, struct rarch_dir_shader_list *dir_list) { - bool show_hidden_files = settings->bools.show_hidden_files; - bool shader_remember_last_dir = settings->bools.video_shader_remember_last_dir; - const char *directory_video_shader = settings->paths.directory_video_shader; - const char *directory_menu_config = settings->paths.directory_menu_config; - bool video_shader_remember_last_dir = settings->bools.video_shader_remember_last_dir; const char *last_shader_preset_dir = NULL; const char *last_shader_preset_file_name = NULL; video_driver_state_t *video_st = video_state_get_ptr(); @@ -2671,7 +2644,18 @@ void video_shader_dir_check_shader( && (last_shader_preset_type != RARCH_SHADER_NONE) && !string_is_equal(dir_list->directory, last_shader_preset_dir))) { - video_shader_dir_init_shader(menu_ptr, settings, dir_list); + const char *directory_video_shader = settings->paths.directory_video_shader; + const char *directory_menu_config = settings->paths.directory_menu_config; + bool show_hidden_files = settings->bools.show_hidden_files; + bool shader_remember_last_dir = settings->bools.video_shader_remember_last_dir; + bool video_shader_remember_last_dir = settings->bools.video_shader_remember_last_dir; + video_shader_dir_init_shader(menu_ptr, + directory_video_shader, + directory_menu_config, + show_hidden_files, + shader_remember_last_dir, + video_shader_remember_last_dir, + dir_list); dir_list_initialised = true; } @@ -2855,12 +2839,13 @@ static bool video_shader_load_shader_preset_internal( * * Returns: false if there was an error or no action was performed. */ -static bool video_shader_load_auto_shader_preset(settings_t *settings, const char *core_name, +static bool video_shader_load_auto_shader_preset( + const char *video_shader_directory, + const char *menu_config_directory, + const char *core_name, char *s, size_t len) { size_t i; - const char *video_shader_directory = settings->paths.directory_video_shader; - const char *menu_config_directory = settings->paths.directory_menu_config; const char *rarch_path_basename = path_get(RARCH_PATH_BASENAME); bool has_content = !string_is_empty(rarch_path_basename); @@ -2945,7 +2930,6 @@ success: } bool video_shader_combine_preset_and_apply( - settings_t *settings, enum rarch_shader_type type, struct video_shader *menu_shader, const char *preset_path, @@ -3139,7 +3123,8 @@ const char *video_shader_get_current_shader_preset(void) if (auto_shaders_enable) /* sets runtime_shader_preset_path */ { if (video_shader_load_auto_shader_preset( - settings, + settings->paths.directory_video_shader, + settings->paths.directory_menu_config, runloop_st->system.info.library_name, runloop_st->runtime_shader_preset_path, sizeof(runloop_st->runtime_shader_preset_path))) diff --git a/gfx/video_shader_parse.h b/gfx/video_shader_parse.h index 002734c62e..3a35463647 100644 --- a/gfx/video_shader_parse.h +++ b/gfx/video_shader_parse.h @@ -275,7 +275,6 @@ void video_shader_dir_check_shader( bool pressed_prev); bool video_shader_combine_preset_and_apply( - settings_t *settings, enum rarch_shader_type type, struct video_shader *menu_shader, const char *preset_path, diff --git a/gfx/video_thread_wrapper.c b/gfx/video_thread_wrapper.c index e4b191ab07..e3d574ed2e 100644 --- a/gfx/video_thread_wrapper.c +++ b/gfx/video_thread_wrapper.c @@ -23,6 +23,11 @@ #include #include +#ifdef _3DS +#include <3ds/types.h> +#include <3ds/allocator/linear.h> /* linearMemAlign() */ +#endif + #include "video_driver.h" #include "video_thread_wrapper.h" #include "font_driver.h" diff --git a/gfx/widgets/gfx_widget_achievement_popup.c b/gfx/widgets/gfx_widget_achievement_popup.c index ba583a8ab0..0de8cbe29c 100644 --- a/gfx/widgets/gfx_widget_achievement_popup.c +++ b/gfx/widgets/gfx_widget_achievement_popup.c @@ -155,18 +155,14 @@ static void gfx_widget_achievement_popup_frame(void* data, void* userdata) gfx_display_ctx_driver_t* dispctx = p_disp->dispctx; dispgfx_widget_t* p_dispwidget = (dispgfx_widget_t*)userdata; - unsigned text_unfold_offset = 0; - bool is_folding = false; - unsigned screen_padding_x = 0; - unsigned screen_padding_y = 0; - int screen_pos_x = 0; - int screen_pos_y = 0; - + unsigned screen_padding_x = 0; + unsigned screen_padding_y = 0; + int screen_pos_x = 0; + int screen_pos_y = 0; /* Slight additional offset for title/subtitle while unfolding */ - text_unfold_offset = ((1.0f - state->unfold) * state->width) * 0.5; - + unsigned text_unfold_offset = ((1.0f - state->unfold) * state->width) * 0.5; /* Whether gfx scissoring should occur, partially hiding popup */ - is_folding = fabs(state->unfold - 1.0f) > 0.01; + bool is_folding = fabs(state->unfold - 1.0f) > 0.01; /* Calculate padding in screen space */ if (state->padding_auto) @@ -200,11 +196,11 @@ static void gfx_widget_achievement_popup_frame(void* data, void* userdata) switch (state->anchor_v) { case ANCHOR_TOP: - screen_pos_y = -(state->height); + screen_pos_y = -(state->height); screen_pos_y += (screen_padding_y + state->height) * state->slide_v; break; case ANCHOR_BOTTOM: - screen_pos_y = video_height; + screen_pos_y = video_height; screen_pos_y -= (screen_padding_y + state->height) * state->slide_v; break; } @@ -217,7 +213,7 @@ static void gfx_widget_achievement_popup_frame(void* data, void* userdata) state->queue[state->queue_read_index].badge_name) { const retro_time_t next_try = state->queue[state->queue_read_index].badge_retry; - const retro_time_t now = cpu_features_get_time_usec(); + const retro_time_t now = cpu_features_get_time_usec(); if (next_try == 0 || now > next_try) { /* try again in 250ms */ diff --git a/griffin/griffin.c b/griffin/griffin.c index 570746d4d4..82e74922f4 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -811,6 +811,13 @@ CAMERA #ifdef HAVE_V4L2 #include "../camera/drivers/video4linux2.c" #endif +#ifdef HAVE_PIPEWIRE +#include "../camera/drivers/pipewire.c" +#endif + +#ifdef HAVE_FFMPEG +#include "../camera/drivers/ffmpeg.c" +#endif #ifdef HAVE_VIDEOPROCESSOR #include "../cores/libretro-video-processor/video_processor_v4l2.c" @@ -861,7 +868,7 @@ AUDIO #include "../audio/drivers/gx_audio.c" #elif defined(__wiiu__) #include "../audio/drivers/wiiu_audio.c" -#elif defined(EMSCRIPTEN) +#elif defined(HAVE_RWEBAUDIO) #include "../audio/drivers/rwebaudio.c" #elif defined(PSP) || defined(VITA) || defined(ORBIS) #include "../audio/drivers/psp_audio.c" @@ -958,6 +965,10 @@ MIDI #include "../midi/drivers/winmm_midi.c" #endif +#ifdef HAVE_COREMIDI +#include "../midi/drivers/coremidi.c" +#endif + /*============================================================ DRIVERS ============================================================ */ @@ -1682,3 +1693,10 @@ CLOUD SYNC #include "../network/cloud_sync_driver.c" #include "../network/cloud_sync/webdav.c" #endif + +/*============================================================ +GAME AI +============================================================ */ +#if defined(HAVE_GAME_AI) +#include "../ai/game_ai.c" +#endif diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index 51557f1b94..c22442a7ba 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -120,3 +120,4 @@ FONTS #include "../deps/discord-rpc/src/connection_unix.cpp" #endif #endif + diff --git a/griffin/griffin_objc.m b/griffin/griffin_objc.m index 68c6ac6e47..c670919e65 100644 --- a/griffin/griffin_objc.m +++ b/griffin/griffin_objc.m @@ -61,6 +61,14 @@ #include "../audio/drivers/coreaudio3.m" #endif +#ifdef HAVE_CORELOCATION +#include "../location/drivers/corelocation.m" +#endif + +#ifdef HAVE_AVF +#include "../camera/drivers/avfoundation.m" +#endif + #if defined(HAVE_DISCORD) #include "../deps/discord-rpc/src/discord_register_osx.m" #endif diff --git a/input/common/linux_common.c b/input/common/linux_common.c index c3705bd5da..4e52b7630f 100644 --- a/input/common/linux_common.c +++ b/input/common/linux_common.c @@ -201,6 +201,10 @@ linux_illuminance_sensor_t *linux_open_illuminance_sensor(unsigned rate) if (!sensor) goto error; + device = retro_opendir(IIO_DEVICES_DIR); + if (!device) + goto error; + sensor->millilux = 0; sensor->poll_rate = rate ? rate : DEFAULT_POLL_RATE; sensor->thread = NULL; /* We'll spawn a thread later, once we find a sensor */ @@ -243,7 +247,7 @@ linux_illuminance_sensor_t *linux_open_illuminance_sensor(unsigned rate) } error: - RARCH_ERR("Failed to find an illuminance sensor\n"); + RARCH_ERR("Failed to find an illuminance sensor in " IIO_DEVICES_DIR "\n"); retro_closedir(device); free(sensor); @@ -262,7 +266,7 @@ void linux_close_illuminance_sensor(linux_illuminance_sensor_t *sensor) if (sensor->thread) { - pthread_t thread = sthread_get_thread_id(sensor->thread); + pthread_t thread = (pthread_t)sthread_get_thread_id(sensor->thread); sensor->done = true; if (pthread_cancel(thread) != 0) @@ -310,6 +314,7 @@ static double linux_read_illuminance_sensor(const linux_illuminance_sensor_t *se char buffer[256]; double illuminance = 0.0; RFILE *in_illuminance_input = NULL; + int err = 0; if (!sensor || sensor->path[0] == '\0') return -1.0; @@ -328,11 +333,15 @@ static double linux_read_illuminance_sensor(const linux_illuminance_sensor_t *se goto done; } + /* Clear any existing error so we'll know if strtod fails */ + errno = 0; + /* TODO: This may be locale-sensitive */ illuminance = strtod(buffer, NULL); - if (errno != 0) + err = errno; + if (err != 0) { - RARCH_ERR("Failed to parse input \"%s\" into a floating-point value\n", buffer); + RARCH_ERR("Failed to parse input \"%s\" into a floating-point value: %s\n", buffer, strerror(err)); illuminance = -1.0; goto done; } diff --git a/input/common/wayland_common.c b/input/common/wayland_common.c index 9f5d273735..f17d2fe2ca 100644 --- a/input/common/wayland_common.c +++ b/input/common/wayland_common.c @@ -996,8 +996,7 @@ static void wl_data_device_handle_drop(void *data, FILE *stream; int pipefd[2]; void *buffer; - size_t length; - size_t len = 0; + size_t __len, _len = 0; ssize_t read = 0; char *line = NULL; char file_list[512][512] = { 0 }; @@ -1012,7 +1011,7 @@ static void wl_data_device_handle_drop(void *data, pipe(pipefd); - buffer = wayland_data_offer_receive(wl->input.dpy, offer_data->offer, &length, FILE_MIME, false); + buffer = wayland_data_offer_receive(wl->input.dpy, offer_data->offer, &__len, FILE_MIME, false); close(pipefd[1]); close(pipefd[0]); @@ -1023,14 +1022,14 @@ static void wl_data_device_handle_drop(void *data, wl_data_offer_destroy(offer_data->offer); free(offer_data); - if (!(stream = fmemopen(buffer, length, "r"))) + if (!(stream = fmemopen(buffer, __len, "r"))) { RARCH_WARN("[Wayland]: Failed to open DnD buffer\n"); return; } RARCH_WARN("[Wayland]: Files opp:\n"); - while ((read = getline(&line, &len, stream)) != -1) + while ((read = getline(&line, &_len, stream)) != -1) { line[strcspn(line, "\r\n")] = 0; RARCH_DBG("[Wayland]: > \"%s\"\n", line); diff --git a/input/common/wayland_common.h b/input/common/wayland_common.h index 8ccae5f2fd..125af85307 100644 --- a/input/common/wayland_common.h +++ b/input/common/wayland_common.h @@ -235,7 +235,7 @@ typedef struct gfx_ctx_wayland_data #ifdef HAVE_XKBCOMMON /* FIXME: Move this into a header? */ -int init_xkb(int fd, size_t size); +int init_xkb(int fd, size_t len); int handle_xkb(int code, int value); void handle_xkb_state_mask(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); diff --git a/input/connect/connect_retrode.c b/input/connect/connect_retrode.c index b4322e66d4..01aa8e2f3c 100644 --- a/input/connect/connect_retrode.c +++ b/input/connect/connect_retrode.c @@ -164,20 +164,20 @@ static void retrode_update_button_state(retrode_pad_data_t *pad) pad->buttons |= (pressed_keys & (1 << i)) ? (1 << button_mapping[i]) : 0; } -static void hidpad_retrode_pad_packet_handler(retrode_pad_data_t *pad, uint8_t *packet, size_t size) +static void hidpad_retrode_pad_packet_handler(retrode_pad_data_t *pad, uint8_t *packet, size_t len) { - memcpy(pad->data, packet, size); + memcpy(pad->data, packet, len); retrode_update_button_state(pad); } -static void hidpad_retrode_packet_handler(void *device_data, uint8_t *packet, uint16_t size) +static void hidpad_retrode_packet_handler(void *device_data, uint8_t *packet, uint16_t len) { retrode_device_data_t *device = (retrode_device_data_t *)device_data; if (!device) return; - memcpy(device->data, packet, size); + memcpy(device->data, packet, len); /* * packet[0] contains Retrode port number @@ -187,7 +187,7 @@ static void hidpad_retrode_packet_handler(void *device_data, uint8_t *packet, ui * 4 = right Genesis/MD */ - hidpad_retrode_pad_packet_handler(&device->pad_data[packet[0] - 1], &device->data[0], size); + hidpad_retrode_pad_packet_handler(&device->pad_data[packet[0] - 1], &device->data[0], len); } static void hidpad_retrode_set_rumble(void *data, diff --git a/input/connect/connect_wiiugca.c b/input/connect/connect_wiiugca.c index c06ecfb37b..8e3422ec4a 100644 --- a/input/connect/connect_wiiugca.c +++ b/input/connect/connect_wiiugca.c @@ -191,17 +191,16 @@ static void update_analog_state(gca_pad_data_t *pad) } } -static void hidpad_wiiugca_pad_packet_handler(gca_pad_data_t *pad, uint8_t *packet, size_t size) +static void hidpad_wiiugca_pad_packet_handler(gca_pad_data_t *pad, uint8_t *packet, size_t len) { - if (size > 9) + if (len > 9) return; - - memcpy(pad->data, packet, size); + memcpy(pad->data, packet, len); update_button_state(pad); update_analog_state(pad); } -static void hidpad_wiiugca_packet_handler(void *device_data, uint8_t *packet, uint16_t size) +static void hidpad_wiiugca_packet_handler(void *device_data, uint8_t *packet, uint16_t len) { uint32_t i; gca_device_data_t *device = (gca_device_data_t *)device_data; @@ -209,7 +208,7 @@ static void hidpad_wiiugca_packet_handler(void *device_data, uint8_t *packet, ui if (!device) return; - memcpy(device->data, packet, size); + memcpy(device->data, packet, len); for (i = 1; i < 37; i += 9) { diff --git a/input/drivers/android_input.c b/input/drivers/android_input.c index eaa286afc7..ff86055a92 100644 --- a/input/drivers/android_input.c +++ b/input/drivers/android_input.c @@ -81,7 +81,7 @@ enum { #endif /* Use this to enable/disable using the touch screen as mouse */ -#define ENABLE_TOUCH_SCREEN_MOUSE 1 +#define ENABLE_TOUCH_SCREEN_MOUSE 0 #define AKEYCODE_ASSIST 219 @@ -102,9 +102,6 @@ uint8_t *android_keyboard_state_get(unsigned port) return android_key_state[port]; } -/* TODO/FIXME - - * fix game focus toggle */ - typedef struct { float x; @@ -1610,8 +1607,7 @@ static void android_input_poll_user(android_input_t *android) } } -/* Handle all events. If our activity is in pause state, - * block until we're unpaused. +/* Handle all events. */ static void android_input_poll(void *data) { @@ -1621,11 +1617,7 @@ static void android_input_poll(void *data) settings_t *settings = config_get_ptr(); while ((ident = - ALooper_pollAll((input_config_binds[0][RARCH_PAUSE_TOGGLE].valid - && input_key_pressed(RARCH_PAUSE_TOGGLE, - ANDROID_KEYBOARD_PORT_INPUT_PRESSED(input_config_binds[0], - RARCH_PAUSE_TOGGLE))) - ? -1 : settings->uints.input_block_timeout, + ALooper_pollAll(settings->uints.input_block_timeout, NULL, NULL, NULL)) >= 0) { switch (ident) @@ -1726,7 +1718,9 @@ static int16_t android_input_state( if (binds[port][id].valid) { if ( (binds[port][id].key && binds[port][id].key < RETROK_LAST) - && ANDROID_KEYBOARD_PORT_INPUT_PRESSED(binds[port], id)) + && ANDROID_KEYBOARD_PORT_INPUT_PRESSED(binds[port], id) + && (id == RARCH_GAME_FOCUS_TOGGLE || !keyboard_mapping_blocked) + ) return 1; } } diff --git a/input/drivers/cocoa_input.m b/input/drivers/cocoa_input.m index 5249a31d87..b9fe733367 100644 --- a/input/drivers/cocoa_input.m +++ b/input/drivers/cocoa_input.m @@ -78,6 +78,11 @@ static UISelectionFeedbackGenerator *feedbackGenerator; static bool apple_key_state[MAX_KEYS]; +void apple_input_keyboard_reset(void) +{ + memset(apple_key_state, 0, sizeof(apple_key_state)); +} + /* Send keyboard inputs directly using RETROK_* codes * Used by the iOS custom keyboard implementation */ void apple_direct_input_keyboard_event(bool down, @@ -396,6 +401,12 @@ static void cocoa_input_poll(void *data) if (!apple) return; + apple->mouse_rel_x = apple->window_pos_x - apple->mouse_x_last; + apple->mouse_x_last = apple->window_pos_x; + + apple->mouse_rel_y = apple->window_pos_y - apple->mouse_y_last; + apple->mouse_y_last = apple->window_pos_y; + for (i = 0; i < apple->touch_count || i == 0; i++) { struct video_viewport vp; @@ -568,75 +579,40 @@ static int16_t cocoa_input_state( return (id && id < RETROK_LAST) && apple_key_state[rarch_keysym_lut[(enum retro_key)id]]; case RETRO_DEVICE_MOUSE: case RARCH_DEVICE_MOUSE_SCREEN: + switch (id) { - int16_t val = 0; - switch (id) + case RETRO_DEVICE_ID_MOUSE_X: + if (device == RARCH_DEVICE_MOUSE_SCREEN) { - case RETRO_DEVICE_ID_MOUSE_X: - if (device == RARCH_DEVICE_MOUSE_SCREEN) - { #ifdef IOS - return apple->window_pos_x; + return apple->window_pos_x; #else - return apple->window_pos_x * cocoa_screen_get_backing_scale_factor(); + return apple->window_pos_x * cocoa_screen_get_backing_scale_factor(); #endif - } -#ifdef IOS -#ifdef HAVE_IOS_TOUCHMOUSE - if (apple->window_pos_x > 0 || apple->mouse_grabbed) - { - val = apple->window_pos_x - apple->mouse_x_last; - apple->mouse_x_last = apple->window_pos_x; - } - else - val = apple->mouse_rel_x; -#else - val = apple->mouse_rel_x; -#endif -#else - val = apple->window_pos_x - apple->mouse_x_last; - apple->mouse_x_last = apple->window_pos_x; -#endif - return val; - case RETRO_DEVICE_ID_MOUSE_Y: - if (device == RARCH_DEVICE_MOUSE_SCREEN) - { -#ifdef IOS - return apple->window_pos_y; -#else - return apple->window_pos_y * cocoa_screen_get_backing_scale_factor(); -#endif - } -#ifdef IOS -#ifdef HAVE_IOS_TOUCHMOUSE - if (apple->window_pos_y > 0 || apple->mouse_grabbed) - { - val = apple->window_pos_y - apple->mouse_y_last; - apple->mouse_y_last = apple->window_pos_y; - } - else - val = apple->mouse_rel_y; -#else - val = apple->mouse_rel_y; -#endif -#else - val = apple->window_pos_y - apple->mouse_y_last; - apple->mouse_y_last = apple->window_pos_y; -#endif - return val; - case RETRO_DEVICE_ID_MOUSE_LEFT: - return apple->mouse_buttons & 1; - case RETRO_DEVICE_ID_MOUSE_RIGHT: - return apple->mouse_buttons & 2; - case RETRO_DEVICE_ID_MOUSE_WHEELUP: - return apple->mouse_wu; - case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: - return apple->mouse_wd; - case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: - return apple->mouse_wl; - case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN: - return apple->mouse_wr; } + return apple->mouse_rel_x; + case RETRO_DEVICE_ID_MOUSE_Y: + if (device == RARCH_DEVICE_MOUSE_SCREEN) + { +#ifdef IOS + return apple->window_pos_y; +#else + return apple->window_pos_y * cocoa_screen_get_backing_scale_factor(); +#endif + } + return apple->mouse_rel_y; + case RETRO_DEVICE_ID_MOUSE_LEFT: + return apple->mouse_buttons & 1; + case RETRO_DEVICE_ID_MOUSE_RIGHT: + return apple->mouse_buttons & 2; + case RETRO_DEVICE_ID_MOUSE_WHEELUP: + return apple->mouse_wu; + case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: + return apple->mouse_wd; + case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: + return apple->mouse_wl; + case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN: + return apple->mouse_wr; } break; case RETRO_DEVICE_POINTER: @@ -695,13 +671,13 @@ static int16_t cocoa_input_state( case RETRO_DEVICE_ID_LIGHTGUN_PAUSE: { unsigned new_id = input_driver_lightgun_id_convert(id); - const uint64_t bind_joykey = input_config_binds[port][new_id].joykey; - const uint64_t bind_joyaxis = input_config_binds[port][new_id].joyaxis; - const uint64_t autobind_joykey = input_autoconf_binds[port][new_id].joykey; - const uint64_t autobind_joyaxis= input_autoconf_binds[port][new_id].joyaxis; + const uint32_t bind_joykey = input_config_binds[port][new_id].joykey; + const uint32_t bind_joyaxis = input_config_binds[port][new_id].joyaxis; + const uint32_t autobind_joykey = input_autoconf_binds[port][new_id].joykey; + const uint32_t autobind_joyaxis= input_autoconf_binds[port][new_id].joyaxis; uint16_t joyport = joypad_info->joy_idx; float axis_threshold = joypad_info->axis_threshold; - const uint64_t joykey = (bind_joykey != NO_BTN) ? bind_joykey : autobind_joykey; + const uint32_t joykey = (bind_joykey != NO_BTN) ? bind_joykey : autobind_joykey; const uint32_t joyaxis = (bind_joyaxis != AXIS_NONE) ? bind_joyaxis : autobind_joyaxis; if (binds[port][new_id].valid) @@ -737,14 +713,12 @@ static int16_t cocoa_input_state( static void cocoa_input_free(void *data) { - unsigned i; cocoa_input_data_t *apple = (cocoa_input_data_t*)data; if (!apple || !data) return; - for (i = 0; i < MAX_KEYS; i++) - apple_key_state[i] = 0; + memset(apple_key_state, 0, sizeof(apple_key_state)); free(apple); } @@ -778,6 +752,10 @@ static bool cocoa_input_set_sensor_state(void *data, unsigned port, continue; if (!controller.motion) break; + if (action == RETRO_SENSOR_ACCELEROMETER_ENABLE && !controller.motion.hasGravityAndUserAcceleration) + break; + if (action == RETRO_SENSOR_GYROSCOPE_ENABLE && !controller.motion.hasAttitudeAndRotationRate) + break; if (controller.motion.sensorsRequireManualActivation) { /* This is a bug, we assume if you turn on/off either @@ -823,7 +801,7 @@ static bool cocoa_input_set_sensor_state(void *data, unsigned port, static float cocoa_input_get_sensor_input(void *data, unsigned port, unsigned id) { #ifdef HAVE_MFI - if (@available(iOS 14.0, *)) + if (@available(iOS 14.0, macOS 11.0, tvOS 14.0, *)) { for (GCController *controller in [GCController controllers]) { @@ -834,11 +812,11 @@ static float cocoa_input_get_sensor_input(void *data, unsigned port, unsigned id switch (id) { case RETRO_SENSOR_ACCELEROMETER_X: - return controller.motion.userAcceleration.x; + return controller.motion.acceleration.x; case RETRO_SENSOR_ACCELEROMETER_Y: - return controller.motion.userAcceleration.y; + return controller.motion.acceleration.y; case RETRO_SENSOR_ACCELEROMETER_Z: - return controller.motion.userAcceleration.z; + return controller.motion.acceleration.z; case RETRO_SENSOR_GYROSCOPE_X: return controller.motion.rotationRate.x; case RETRO_SENSOR_GYROSCOPE_Y: @@ -856,11 +834,11 @@ static float cocoa_input_get_sensor_input(void *data, unsigned port, unsigned id switch (id) { case RETRO_SENSOR_ACCELEROMETER_X: - return motionManager.deviceMotion.userAcceleration.x; + return motionManager.deviceMotion.gravity.x + motionManager.deviceMotion.userAcceleration.x; case RETRO_SENSOR_ACCELEROMETER_Y: - return motionManager.deviceMotion.userAcceleration.y; + return motionManager.deviceMotion.gravity.y + motionManager.deviceMotion.userAcceleration.y; case RETRO_SENSOR_ACCELEROMETER_Z: - return motionManager.deviceMotion.userAcceleration.z; + return motionManager.deviceMotion.gravity.z + motionManager.deviceMotion.userAcceleration.z; case RETRO_SENSOR_GYROSCOPE_X: return motionManager.deviceMotion.rotationRate.x; case RETRO_SENSOR_GYROSCOPE_Y: diff --git a/input/drivers/dinput.c b/input/drivers/dinput.c index 10c8dc6f1e..9db7de4f49 100644 --- a/input/drivers/dinput.c +++ b/input/drivers/dinput.c @@ -18,6 +18,8 @@ #pragma comment(lib, "dinput8") #endif +#define WIN32_LEAN_AND_MEAN + #undef DIRECTINPUT_VERSION #define DIRECTINPUT_VERSION 0x0800 @@ -172,10 +174,10 @@ static void *dinput_init(const char *joypad_driver) if (di->keyboard) { - settings_t *settings = config_get_ptr(); - DWORD flags = DISCL_NONEXCLUSIVE | DISCL_FOREGROUND; - if (settings->bools.input_nowinkey_enable) - flags |= DISCL_NOWINKEY; + bool input_nowinkey_enable = config_get_ptr()->bools.input_nowinkey_enable; + DWORD flags = DISCL_NONEXCLUSIVE | DISCL_FOREGROUND; + if (input_nowinkey_enable) + flags |= DISCL_NOWINKEY; IDirectInputDevice8_SetDataFormat(di->keyboard, &c_dfDIKeyboard); IDirectInputDevice8_SetCooperativeLevel(di->keyboard, diff --git a/input/drivers/linuxraw_input.c b/input/drivers/linuxraw_input.c index 1788c1f283..e500327fa5 100644 --- a/input/drivers/linuxraw_input.c +++ b/input/drivers/linuxraw_input.c @@ -98,7 +98,7 @@ static int16_t linuxraw_input_state( if (binds[port][i].valid) { if ( (binds[port][i].key && binds[port][i].key < RETROK_LAST) - && linuxraw->state[rarch_keysym_lut[(enum retro_key)binds[port][i].key]]) + && linuxraw->state[rarch_keysym_lut[(enum retro_key)binds[port][i].key] & 0X7F]) ret |= (1 << i); } } @@ -112,7 +112,7 @@ static int16_t linuxraw_input_state( if (binds[port][id].valid) { if ( (binds[port][id].key && binds[port][id].key < RETROK_LAST) - && linuxraw->state[rarch_keysym_lut[(enum retro_key)binds[port][id].key]] + && linuxraw->state[rarch_keysym_lut[(enum retro_key)binds[port][id].key] & 0X7F] && (id == RARCH_GAME_FOCUS_TOGGLE || !keyboard_mapping_blocked) ) return 1; @@ -120,7 +120,7 @@ static int16_t linuxraw_input_state( } break; case RETRO_DEVICE_ANALOG: - if (binds[port]) + if (binds) { int id_minus_key = 0; int id_plus_key = 0; @@ -139,20 +139,27 @@ static int16_t linuxraw_input_state( if (id_plus_valid && id_plus_key && id_plus_key < RETROK_LAST) { - unsigned sym = rarch_keysym_lut[(enum retro_key)id_plus_key]; - if (linuxraw->state[sym] & 0x80) + unsigned sym = rarch_keysym_lut[(enum retro_key)id_plus_key] & 0X7F; + if (linuxraw->state[sym]) ret = 0x7fff; } if (id_minus_valid && id_minus_key && id_minus_key < RETROK_LAST) { - unsigned sym = rarch_keysym_lut[(enum retro_key)id_minus_key]; - if (linuxraw->state[sym] & 0x80) + unsigned sym = rarch_keysym_lut[(enum retro_key)id_minus_key] & 0X7F; + if (linuxraw->state[sym]) ret += -0x7fff; } return ret; } break; + case RETRO_DEVICE_KEYBOARD: + if (id && id < RETROK_LAST) + { + unsigned sym = rarch_keysym_lut[(enum retro_key)id] & 0X7F; + return linuxraw->state[sym]; + } + break; } return 0; @@ -242,14 +249,30 @@ static void linuxraw_input_poll(void *data) if (!c) read(STDIN_FILENO, &t, 2); else + { + unsigned keyboardcode = input_keymaps_translate_keysym_to_rk(c); + uint16_t mod = 0; + + if (linuxraw->state[KEY_LEFTCTRL] || linuxraw->state[KEY_RIGHTCTRL]) + mod |= RETROKMOD_CTRL; + if (linuxraw->state[KEY_LEFTALT] || linuxraw->state[KEY_RIGHTALT]) + mod |= RETROKMOD_ALT; + if (linuxraw->state[KEY_LEFTSHIFT] || linuxraw->state[KEY_RIGHTSHIFT]) + mod |= RETROKMOD_SHIFT; + if (linuxraw->state[KEY_LEFTMETA] || linuxraw->state[KEY_RIGHTMETA]) + mod |= RETROKMOD_META; + linuxraw->state[c] = pressed; + input_keyboard_event(pressed, keyboardcode, keyboardcode, mod, RETRO_DEVICE_KEYBOARD); + } } } static uint64_t linuxraw_get_capabilities(void *data) { return (1 << RETRO_DEVICE_JOYPAD) - | (1 << RETRO_DEVICE_ANALOG); + | (1 << RETRO_DEVICE_ANALOG) + | (1 << RETRO_DEVICE_KEYBOARD); } input_driver_t input_linuxraw = { diff --git a/input/drivers/rwebinput_input.c b/input/drivers/rwebinput_input.c index 34b0cfbbec..55982a056f 100644 --- a/input/drivers/rwebinput_input.c +++ b/input/drivers/rwebinput_input.c @@ -23,14 +23,19 @@ #include #include +#include #include +#include "../../frontend/drivers/platform_emscripten.h" +#include "../input_driver.h" +#include "../input_types.h" #include "../input_keymaps.h" #include "../../tasks/tasks_internal.h" #include "../../configuration.h" #include "../../retroarch.h" #include "../../verbosity.h" +#include "../../command.h" /* https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button */ #define RWEBINPUT_MOUSE_BTNL 0 @@ -39,6 +44,8 @@ #define RWEBINPUT_MOUSE_BTN4 3 #define RWEBINPUT_MOUSE_BTN5 4 +#define MAX_TOUCH 32 + typedef struct rwebinput_key_to_code_map_entry { const char *key; @@ -58,26 +65,36 @@ typedef struct rwebinput_keyboard_event_queue size_t max_size; } rwebinput_keyboard_event_queue_t; +typedef struct rwebinput_pointer_states +{ + int x; + int y; + int id; +} rwebinput_pointer_state_t; + typedef struct rwebinput_mouse_states { double pending_scroll_x; double pending_scroll_y; double scroll_x; double scroll_y; - signed x; - signed y; - signed pending_delta_x; - signed pending_delta_y; - signed delta_x; - signed delta_y; + int x; + int y; + int pending_delta_x; + int pending_delta_y; + int delta_x; + int delta_y; uint8_t buttons; } rwebinput_mouse_state_t; typedef struct rwebinput_input { - rwebinput_mouse_state_t mouse; /* double alignment */ - rwebinput_keyboard_event_queue_t keyboard; /* ptr alignment */ + rwebinput_mouse_state_t mouse; /* double alignment */ + rwebinput_keyboard_event_queue_t keyboard; /* ptr alignment */ + rwebinput_pointer_state_t pointer[MAX_TOUCH]; /* int alignment */ + unsigned pointer_count; bool keys[RETROK_LAST]; + bool pointerlock_active; } rwebinput_input_t; /* KeyboardEvent.keyCode has been deprecated for a while and doesn't have @@ -255,11 +272,39 @@ static EM_BOOL rwebinput_mouse_cb(int event_type, uint8_t mask = 1 << mouse_event->button; - rwebinput->mouse.x = mouse_event->targetX; - rwebinput->mouse.y = mouse_event->targetY; + // note: movementX/movementY are pre-scaled in chromium (but not firefox) + // see https://github.com/w3c/pointerlock/issues/42 + rwebinput->mouse.pending_delta_x += mouse_event->movementX; rwebinput->mouse.pending_delta_y += mouse_event->movementY; + if (rwebinput->pointerlock_active) + { + unsigned video_width, video_height; + video_driver_get_size(&video_width, &video_height); + + rwebinput->mouse.x += mouse_event->movementX; + rwebinput->mouse.y += mouse_event->movementY; + + /* Clamp X */ + if (rwebinput->mouse.x < 0) + rwebinput->mouse.x = 0; + if (rwebinput->mouse.x >= video_width) + rwebinput->mouse.x = (int)(video_width - 1); + + /* Clamp Y */ + if (rwebinput->mouse.y < 0) + rwebinput->mouse.y = 0; + if (rwebinput->mouse.y >= video_height) + rwebinput->mouse.y = (int)(video_height - 1); + } + else + { + double dpr = platform_emscripten_get_dpr(); + rwebinput->mouse.x = (int)(mouse_event->targetX * dpr); + rwebinput->mouse.y = (int)(mouse_event->targetY * dpr); + } + if (event_type == EMSCRIPTEN_EVENT_MOUSEDOWN) rwebinput->mouse.buttons |= mask; else if (event_type == EMSCRIPTEN_EVENT_MOUSEUP) @@ -273,8 +318,90 @@ static EM_BOOL rwebinput_wheel_cb(int event_type, { rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data; - rwebinput->mouse.pending_scroll_x += wheel_event->deltaX; - rwebinput->mouse.pending_scroll_y += wheel_event->deltaY; + double dpr = platform_emscripten_get_dpr(); + rwebinput->mouse.pending_scroll_x += wheel_event->deltaX * dpr; + rwebinput->mouse.pending_scroll_y += wheel_event->deltaY * dpr; + + return EM_TRUE; +} + +static EM_BOOL rwebinput_touch_cb(int event_type, + const EmscriptenTouchEvent *touch_event, void *user_data) +{ + rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data; + + unsigned touches_max = MIN(touch_event->numTouches, MAX_TOUCH); + unsigned touches_released = 0; + + switch (event_type) + { + case EMSCRIPTEN_EVENT_TOUCHSTART: + case EMSCRIPTEN_EVENT_TOUCHMOVE: + for (unsigned touch = 0; touch < touches_max; touch++) + { + if (!(touch_event->touches[touch].isChanged) && rwebinput->pointer[touch].id == touch_event->touches[touch].identifier) + continue; + + double dpr = platform_emscripten_get_dpr(); + rwebinput->pointer[touch].x = (int)(touch_event->touches[touch].targetX * dpr); + rwebinput->pointer[touch].y = (int)(touch_event->touches[touch].targetY * dpr); + rwebinput->pointer[touch].id = touch_event->touches[touch].identifier; + } + break; + case EMSCRIPTEN_EVENT_TOUCHEND: + case EMSCRIPTEN_EVENT_TOUCHCANCEL: + // note: touches_max/numTouches is out of date here - it uses the old value from before the release + // note 2: I'm unsure if multiple touches can trigger the same touchend anyway... + if (touches_max > 1) + { + for (unsigned touch_up = 0; touch_up < touches_max; touch_up++) + { + if (touch_event->touches[touch_up].isChanged) + { + memmove(rwebinput->pointer + touch_up - touches_released, + rwebinput->pointer + touch_up - touches_released + 1, + (touches_max - touch_up - 1) * sizeof(rwebinput_pointer_state_t)); + touches_released++; + } + } + } + else + touches_released = 1; + + if (touches_max > touches_released) + touches_max -= touches_released; + else + touches_max = 0; + break; + } + + rwebinput->pointer_count = touches_max; + + return EM_TRUE; +} + +static EM_BOOL rwebinput_pointerlockchange_cb(int event_type, + const EmscriptenPointerlockChangeEvent *pointerlock_change_event, void *user_data) +{ + rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data; + + rwebinput->pointerlock_active = pointerlock_change_event->isActive; + + if (!pointerlock_change_event->isActive) + { + input_driver_state_t *input_st = input_state_get_ptr(); + + if (input_st->game_focus_state.enabled) + { + enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_OFF; + command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd); + } + + if (input_st->flags & INP_FLAG_GRAB_MOUSE_STATE) + { + command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); + } + } return EM_TRUE; } @@ -290,8 +417,9 @@ static void *rwebinput_input_init(const char *joypad_driver) rwebinput_generate_lut(); - r = emscripten_set_keydown_callback( - "!canvas", rwebinput, false, + input_keymaps_init_keyboard_lut(rarch_key_map_rwebinput); + + r = emscripten_set_keydown_callback("#canvas", rwebinput, false, rwebinput_keyboard_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -299,8 +427,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create keydown callback: %d\n", r); } - r = emscripten_set_keyup_callback( - "!canvas", rwebinput, false, + r = emscripten_set_keyup_callback("#canvas", rwebinput, false, rwebinput_keyboard_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -308,8 +435,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create keyup callback: %d\n", r); } - r = emscripten_set_keypress_callback( - "!canvas", rwebinput, false, + r = emscripten_set_keypress_callback("#canvas", rwebinput, false, rwebinput_keyboard_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -317,7 +443,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create keypress callback: %d\n", r); } - r = emscripten_set_mousedown_callback("!canvas", rwebinput, false, + r = emscripten_set_mousedown_callback("#canvas", rwebinput, false, rwebinput_mouse_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -325,7 +451,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create mousedown callback: %d\n", r); } - r = emscripten_set_mouseup_callback("!canvas", rwebinput, false, + r = emscripten_set_mouseup_callback("#canvas", rwebinput, false, rwebinput_mouse_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -333,7 +459,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create mouseup callback: %d\n", r); } - r = emscripten_set_mousemove_callback("!canvas", rwebinput, false, + r = emscripten_set_mousemove_callback("#canvas", rwebinput, false, rwebinput_mouse_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -341,8 +467,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create mousemove callback: %d\n", r); } - r = emscripten_set_wheel_callback( - "!canvas", rwebinput, false, + r = emscripten_set_wheel_callback("#canvas", rwebinput, false, rwebinput_wheel_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -350,7 +475,46 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create wheel callback: %d\n", r); } - input_keymaps_init_keyboard_lut(rarch_key_map_rwebinput); + r = emscripten_set_touchstart_callback("#canvas", rwebinput, false, + rwebinput_touch_cb); + if (r != EMSCRIPTEN_RESULT_SUCCESS) + { + RARCH_ERR( + "[EMSCRIPTEN/INPUT] failed to create touchstart callback: %d\n", r); + } + + r = emscripten_set_touchend_callback("#canvas", rwebinput, false, + rwebinput_touch_cb); + if (r != EMSCRIPTEN_RESULT_SUCCESS) + { + RARCH_ERR( + "[EMSCRIPTEN/INPUT] failed to create touchend callback: %d\n", r); + } + + r = emscripten_set_touchmove_callback("#canvas", rwebinput, false, + rwebinput_touch_cb); + if (r != EMSCRIPTEN_RESULT_SUCCESS) + { + RARCH_ERR( + "[EMSCRIPTEN/INPUT] failed to create touchmove callback: %d\n", r); + } + + r = emscripten_set_touchcancel_callback("#canvas", rwebinput, false, + rwebinput_touch_cb); + if (r != EMSCRIPTEN_RESULT_SUCCESS) + { + RARCH_ERR( + "[EMSCRIPTEN/INPUT] failed to create touchcancel callback: %d\n", r); + } + + r = emscripten_set_pointerlockchange_callback( + EMSCRIPTEN_EVENT_TARGET_DOCUMENT, rwebinput, false, + rwebinput_pointerlockchange_cb); + if (r != EMSCRIPTEN_RESULT_SUCCESS) + { + RARCH_ERR( + "[EMSCRIPTEN/INPUT] failed to create pointerlockchange callback: %d\n", r); + } return rwebinput; } @@ -505,24 +669,41 @@ static int16_t rwebinput_input_state( return rwebinput_mouse_state(&rwebinput->mouse, id, device == RARCH_DEVICE_MOUSE_SCREEN); case RETRO_DEVICE_POINTER: case RARCH_DEVICE_POINTER_SCREEN: - if (idx == 0) { struct video_viewport vp = {0}; rwebinput_mouse_state_t *mouse = &rwebinput->mouse; - bool screen = device == - RARCH_DEVICE_POINTER_SCREEN; + bool pointer_down = false; + unsigned pointer_count = rwebinput->pointer_count; + int x = 0; + int y = 0; int16_t res_x = 0; int16_t res_y = 0; int16_t res_screen_x = 0; int16_t res_screen_y = 0; + if (pointer_count && idx < pointer_count) + { + x = rwebinput->pointer[idx].x; + y = rwebinput->pointer[idx].y; + pointer_down = true; + } + else if (idx == 0) + { + x = mouse->x; + y = mouse->y; + pointer_down = !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTNL)); + pointer_count = 1; + } + else + return 0; + if (!(video_driver_translate_coord_viewport_confined_wrap( - &vp, mouse->x, mouse->y, + &vp, x, y, &res_x, &res_y, &res_screen_x, &res_screen_y))) return 0; - if (screen) + if (device == RARCH_DEVICE_POINTER_SCREEN) { res_x = res_screen_x; res_y = res_screen_y; @@ -535,7 +716,9 @@ static int16_t rwebinput_input_state( case RETRO_DEVICE_ID_POINTER_Y: return res_y; case RETRO_DEVICE_ID_POINTER_PRESSED: - return !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTNL)); + return (pointer_down && !input_driver_pointer_is_offscreen(res_x, res_y)); + case RETRO_DEVICE_ID_POINTER_COUNT: + return pointer_count; case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN: return input_driver_pointer_is_offscreen(res_x, res_y); default: @@ -548,14 +731,18 @@ static int16_t rwebinput_input_state( return 0; } +static void rwebinput_remove_event_listeners(void *data) +{ + /* *currently* not automatically proxied in the case of PROXY_TO_PTHREAD */ + emscripten_html5_remove_all_event_listeners(); +} + static void rwebinput_input_free(void *data) { rwebinput_input_t *rwebinput = (rwebinput_input_t*)data; - emscripten_html5_remove_all_event_listeners(); - + platform_emscripten_run_on_browser_thread_sync(rwebinput_remove_event_listeners, NULL); free(rwebinput->keyboard.events); - free(data); } @@ -633,7 +820,7 @@ static void rwebinput_input_poll(void *data) static void rwebinput_grab_mouse(void *data, bool state) { if (state) - emscripten_request_pointerlock("!canvas", EM_TRUE); + emscripten_request_pointerlock("#canvas", EM_TRUE); else emscripten_exit_pointerlock(); } diff --git a/input/drivers/sdl_input.c b/input/drivers/sdl_input.c index f98f3c12b5..a65a94855b 100644 --- a/input/drivers/sdl_input.c +++ b/input/drivers/sdl_input.c @@ -338,7 +338,7 @@ static void sdl_input_free(void *data) #endif sdl_input_t *sdl = (sdl_input_t*)data; - if (!data) + if (!sdl) return; /* Flush out all pending events. */ diff --git a/input/drivers/test_input.c b/input/drivers/test_input.c index 7a0ae52b44..bc66f86155 100644 --- a/input/drivers/test_input.c +++ b/input/drivers/test_input.c @@ -125,7 +125,7 @@ static bool KTifJSONObjectEndHandler(void* context) return true; } -static bool KTifJSONObjectMemberHandler(void* context, const char *pValue, size_t length) +static bool KTifJSONObjectMemberHandler(void* context, const char *pValue, size_t len) { KTifJSONContext *pCtx = (KTifJSONContext*)context; @@ -133,7 +133,7 @@ static bool KTifJSONObjectMemberHandler(void* context, const char *pValue, size_ if (pCtx->current_entry_str_val) return false; - if (length) + if (len) { if (string_is_equal(pValue, "frame")) pCtx->current_entry_uint_val = &pCtx->frame; @@ -149,11 +149,11 @@ static bool KTifJSONObjectMemberHandler(void* context, const char *pValue, size_ return true; } -static bool KTifJSONNumberHandler(void* context, const char *pValue, size_t length) +static bool KTifJSONNumberHandler(void* context, const char *pValue, size_t len) { KTifJSONContext *pCtx = (KTifJSONContext*)context; - if (pCtx->current_entry_uint_val && length && !string_is_empty(pValue)) + if (pCtx->current_entry_uint_val && len && !string_is_empty(pValue)) *pCtx->current_entry_uint_val = string_to_unsigned(pValue); /* ignore unknown members */ @@ -162,11 +162,11 @@ static bool KTifJSONNumberHandler(void* context, const char *pValue, size_t leng return true; } -static bool KTifJSONStringHandler(void* context, const char *pValue, size_t length) +static bool KTifJSONStringHandler(void* context, const char *pValue, size_t len) { KTifJSONContext *pCtx = (KTifJSONContext*)context; - if (pCtx->current_entry_str_val && length && !string_is_empty(pValue)) + if (pCtx->current_entry_str_val && len && !string_is_empty(pValue)) { if (*pCtx->current_entry_str_val) free(*pCtx->current_entry_str_val); @@ -412,9 +412,9 @@ static void test_input_poll(void *data) { if (!input_test_steps[i].handled && curr_frame > input_test_steps[i].frame) { - if( input_test_steps[i].action == INPUT_TEST_COMMAND_PRESS_KEY) + if (input_test_steps[i].action == INPUT_TEST_COMMAND_PRESS_KEY) { - if(input_test_steps[i].param_num < RETROK_LAST) + if (input_test_steps[i].param_num < RETROK_LAST) { test_key_state[DEFAULT_MAX_PADS][input_test_steps[i].param_num] = 1; input_keyboard_event(true, input_test_steps[i].param_num, 0, 0, RETRO_DEVICE_KEYBOARD); @@ -424,9 +424,9 @@ static void test_input_poll(void *data) "[Test input driver]: Pressing keyboard button %d at frame %d\n", input_test_steps[i].param_num, curr_frame); } - else if( input_test_steps[i].action == INPUT_TEST_COMMAND_RELEASE_KEY) + else if (input_test_steps[i].action == INPUT_TEST_COMMAND_RELEASE_KEY) { - if(input_test_steps[i].param_num < RETROK_LAST) + if (input_test_steps[i].param_num < RETROK_LAST) { test_key_state[DEFAULT_MAX_PADS][input_test_steps[i].param_num] = 0; input_keyboard_event(false, input_test_steps[i].param_num, 0, 0, RETRO_DEVICE_KEYBOARD); @@ -436,9 +436,9 @@ static void test_input_poll(void *data) "[Test input driver]: Releasing keyboard button %d at frame %d\n", input_test_steps[i].param_num, curr_frame); } - else if(input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_ACC_X || - input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_ACC_Y || - input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_ACC_Z) + else if ( input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_ACC_X + || input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_ACC_Y + || input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_ACC_Z) { float setval = test_input_unsigned_to_float_acc(input_test_steps[i].param_num); switch (input_test_steps[i].action) @@ -458,9 +458,9 @@ static void test_input_poll(void *data) "[Test input driver]: Setting accelerometer axis %d to %f at frame %d\n", input_test_steps[i].action - INPUT_TEST_COMMAND_SET_SENSOR_ACC_X, setval, curr_frame); } - else if(input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_GYR_X || - input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_GYR_Y || - input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_GYR_Z) + else if ( input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_GYR_X + || input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_GYR_Y + || input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_GYR_Z) { float setval = test_input_unsigned_to_float_gyro(input_test_steps[i].param_num); switch (input_test_steps[i].action) @@ -480,7 +480,7 @@ static void test_input_poll(void *data) "[Test input driver]: Setting gyroscope axis %d to %f at frame %d\n", input_test_steps[i].action - INPUT_TEST_COMMAND_SET_SENSOR_GYR_X, setval, curr_frame); } - else if(input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_LUX) + else if (input_test_steps[i].action == INPUT_TEST_COMMAND_SET_SENSOR_LUX) { float setval = test_input_unsigned_to_float_lux(input_test_steps[i].param_num); test_input_values.lux_sensor_state = setval; @@ -510,23 +510,23 @@ static bool test_input_set_sensor_state(void *data, unsigned port, static float test_input_get_sensor_input(void *data, unsigned port, unsigned id) { - switch (id) - { - case RETRO_SENSOR_ACCELEROMETER_X: - return test_input_values.accelerometer_state.x; - case RETRO_SENSOR_ACCELEROMETER_Y: - return test_input_values.accelerometer_state.y; - case RETRO_SENSOR_ACCELEROMETER_Z: - return test_input_values.accelerometer_state.z; - case RETRO_SENSOR_GYROSCOPE_X: - return test_input_values.gyroscope_state.x; - case RETRO_SENSOR_GYROSCOPE_Y: - return test_input_values.gyroscope_state.y; - case RETRO_SENSOR_GYROSCOPE_Z: - return test_input_values.gyroscope_state.z; - case RETRO_SENSOR_ILLUMINANCE: - return test_input_values.lux_sensor_state; - } + switch (id) + { + case RETRO_SENSOR_ACCELEROMETER_X: + return test_input_values.accelerometer_state.x; + case RETRO_SENSOR_ACCELEROMETER_Y: + return test_input_values.accelerometer_state.y; + case RETRO_SENSOR_ACCELEROMETER_Z: + return test_input_values.accelerometer_state.z; + case RETRO_SENSOR_GYROSCOPE_X: + return test_input_values.gyroscope_state.x; + case RETRO_SENSOR_GYROSCOPE_Y: + return test_input_values.gyroscope_state.y; + case RETRO_SENSOR_GYROSCOPE_Z: + return test_input_values.gyroscope_state.z; + case RETRO_SENSOR_ILLUMINANCE: + return test_input_values.lux_sensor_state; + } return 0.0f; } diff --git a/input/drivers/udev_input.c b/input/drivers/udev_input.c index 01834f133e..ef5cbf0f12 100644 --- a/input/drivers/udev_input.c +++ b/input/drivers/udev_input.c @@ -574,7 +574,7 @@ typedef struct udev_input } udev_input_t; #ifdef UDEV_XKB_HANDLING -int init_xkb(int fd, size_t size); +int init_xkb(int fd, size_t len); void free_xkb(void); int handle_xkb(int code, int value); #endif @@ -781,7 +781,7 @@ static int16_t udev_mouse_get_y(const udev_input_mouse_t *mouse) return y + (y < 0 ? -0.5 : 0.5); } -static bool udev_mouse_get_pointer(const udev_input_mouse_t *mouse, +static bool udev_mouse_get_pointer(const udev_input_mouse_t *mouse, bool screen, bool confined, int16_t *ret_x, int16_t *ret_y) { struct video_viewport vp = {0}; @@ -800,8 +800,8 @@ static bool udev_mouse_get_pointer(const udev_input_mouse_t *mouse, { /* mouse coordinates are relative to the full screen; convert them * to be relative to the viewport */ - scaled_x = mouse->x_abs - mouse->x_min; - scaled_y = mouse->y_abs - mouse->y_min; + scaled_x = vp.full_width * (mouse->x_abs - mouse->x_min) / (mouse->x_max - mouse->x_min + 1); + scaled_y = vp.full_height * (mouse->y_abs - mouse->y_min) / (mouse->y_max - mouse->y_min + 1); } else /* mouse coords are viewport relative */ { @@ -823,7 +823,7 @@ static bool udev_mouse_get_pointer(const udev_input_mouse_t *mouse, { return false; } - + if (screen) { *ret_x = res_screen_x; @@ -1209,14 +1209,14 @@ static const char *udev_mt_code_to_str(uint32_t code) * * @param label Label to prefix the message with. * @param request_data Input data structure to dump. - * @param count Number of elements in the values array. + * @param len Number of elements in the values array. */ -static void udev_dump_mt_request_data(const char *label, const uint8_t *request_data, size_t count) +static void udev_dump_mt_request_data(const char *label, const uint8_t *request_data, size_t len) { uint32_t *mt_req_code = (uint32_t*) request_data; int32_t *mt_req_values = ((int32_t*) request_data) + 1; RARCH_DBG("[udev] %s: Req { %s, [ ", label, udev_mt_code_to_str(*mt_req_code)); - for (; mt_req_values < (((int32_t*) mt_req_code) + count + 1); ++mt_req_values) + for (; mt_req_values < (((int32_t*) mt_req_code) + len + 1); ++mt_req_values) { RARCH_DBG("%d, ", *mt_req_values); } @@ -3787,7 +3787,7 @@ static int16_t udev_input_state( } break; case RETRO_DEVICE_ANALOG: - if (binds[port]) + if (binds) { int id_minus_key = 0; int id_plus_key = 0; @@ -4126,7 +4126,28 @@ static void *udev_input_init(const char *joypad_driver) /* If using KMS and we forgot this, * we could lock ourselves out completely. */ if (!udev->num_devices) + { + settings_t *settings = config_get_ptr(); RARCH_WARN("[udev]: Couldn't open any keyboard, mouse or touchpad. Are permissions set correctly for /dev/input/event* and /run/udev/?\n"); + /* Start screen is not used nowadays, but it still gets true value only + * on first startup without config file, so it should be good to catch + * initial boots without udev devices available. */ +#if defined(__linux__) && !defined(ANDROID) + if (settings->bools.menu_show_start_screen) + { + /* Force fallback to linuxraw. Driver reselection would happen even + * without overwriting input_driver setting, but that would not be saved + * as input driver auto-changes are not stored (due to interlock with + * video context driver), and on next boot user would be stuck with a + * possibly nonworking configuration. + */ + strlcpy(settings->arrays.input_driver, "linuxraw", + sizeof(settings->arrays.input_driver)); + RARCH_WARN("[udev]: First boot and without input devices, forcing fallback to linuxraw.\n"); + goto error; + } +#endif + } input_keymaps_init_keyboard_lut(rarch_key_map_linux); diff --git a/input/drivers/wayland_input.c b/input/drivers/wayland_input.c index f1c86ef455..fdea597066 100644 --- a/input/drivers/wayland_input.c +++ b/input/drivers/wayland_input.c @@ -214,7 +214,7 @@ static int16_t input_wl_state( } break; case RETRO_DEVICE_ANALOG: - if (binds[port]) + if (binds) { int id_minus_key = 0; int id_plus_key = 0; diff --git a/input/drivers/winraw_input.c b/input/drivers/winraw_input.c index e04b9d80b2..0dae1e9346 100644 --- a/input/drivers/winraw_input.c +++ b/input/drivers/winraw_input.c @@ -13,6 +13,7 @@ * If not, see . */ +#define WIN32_LEAN_AND_MEAN #include #ifdef CXX_BUILD @@ -128,14 +129,14 @@ static void winraw_log_mice_info(winraw_mouse_t *mice, unsigned mouse_cnt) char name[256]; UINT name_size = sizeof(name); - name[0] = '\0'; + name[0] = '\0'; for (i = 0; i < mouse_cnt; ++i) { UINT r = GetRawInputDeviceInfoA(mice[i].hnd, RIDI_DEVICENAME, name, &name_size); if (r == (UINT)-1 || r == 0) - name[0] = '\0'; + name[0] = '\0'; if (name[0]) { @@ -146,7 +147,7 @@ static void winraw_log_mice_info(winraw_mouse_t *mice, unsigned mouse_cnt) if (hhid != INVALID_HANDLE_VALUE) { wchar_t prod_buf[128]; - prod_buf[0] = '\0'; + prod_buf[0] = '\0'; if (HidD_GetProductString(hhid, prod_buf, sizeof(prod_buf))) wcstombs(name, prod_buf, sizeof(name)); } @@ -158,7 +159,7 @@ static void winraw_log_mice_info(winraw_mouse_t *mice, unsigned mouse_cnt) input_config_set_mouse_display_name(i, name); - RARCH_LOG("[WinRaw]: Mouse #%u: \"%s\".\n", i, name); + RARCH_LOG("[WinRaw]: Mouse #%u: \"%s\".\n", i + 1, name); } } @@ -203,19 +204,23 @@ static bool winraw_init_devices(winraw_mouse_t **mice, unsigned *mouse_cnt) } } + *mouse_cnt = mouse_cnt_r; + /* count is already checked, so this is safe */ for (i = mouse_cnt_r = 0; i < dev_cnt; ++i) { if (devs[i].dwType == RIM_TYPEMOUSE) - mice_r[mouse_cnt_r++].hnd = devs[i].hDevice; + { + mouse_cnt_r++; + mice_r[*mouse_cnt - mouse_cnt_r].hnd = devs[i].hDevice; + } } + *mice = mice_r; + winraw_log_mice_info(mice_r, mouse_cnt_r); free(devs); - *mice = mice_r; - *mouse_cnt = mouse_cnt_r; - return true; error: @@ -554,7 +559,7 @@ static LRESULT CALLBACK winraw_callback( static void *winraw_init(const char *joypad_driver) { RAWINPUTDEVICE rid; - settings_t *settings = config_get_ptr(); + bool input_nowinkey_enable = config_get_ptr()->bools.input_nowinkey_enable; winraw_input_t *wr = (winraw_input_t *) calloc(1, sizeof(winraw_input_t)); @@ -581,7 +586,7 @@ static void *winraw_init(const char *joypad_driver) rid.hwndTarget = wr->window; rid.usUsagePage = 0x01; /* Generic desktop */ rid.usUsage = 0x06; /* Keyboard */ - if (settings->bools.input_nowinkey_enable) + if (input_nowinkey_enable) rid.dwFlags |= RIDEV_NOHOTKEYS; /* Disable win keys while focused */ if (!RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE))) @@ -613,7 +618,7 @@ error: rid.hwndTarget = NULL; rid.usUsagePage = 0x01; /* Generic desktop */ rid.usUsage = 0x06; /* Keyboard */ - if (settings->bools.input_nowinkey_enable) + if (input_nowinkey_enable) rid.dwFlags |= RIDEV_NOHOTKEYS; /* Disable win keys while focused */ RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE)); @@ -988,8 +993,8 @@ bool winraw_handle_message(UINT msg, static void winraw_free(void *data) { RAWINPUTDEVICE rid; - settings_t *settings = config_get_ptr(); - winraw_input_t *wr = (winraw_input_t*)data; + winraw_input_t *wr = (winraw_input_t*)data; + bool input_nowinkey_enable = config_get_ptr()->bools.input_nowinkey_enable; rid.dwFlags = RIDEV_REMOVE; rid.hwndTarget = NULL; @@ -1002,7 +1007,7 @@ static void winraw_free(void *data) rid.hwndTarget = NULL; rid.usUsagePage = 0x01; /* Generic desktop */ rid.usUsage = 0x06; /* Keyboard */ - if (settings->bools.input_nowinkey_enable) + if (input_nowinkey_enable) rid.dwFlags |= RIDEV_NOHOTKEYS; /* Disable win keys while focused */ RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE)); diff --git a/input/drivers/x11_input.c b/input/drivers/x11_input.c index 23a7e4d8de..992d3f54fd 100644 --- a/input/drivers/x11_input.c +++ b/input/drivers/x11_input.c @@ -24,28 +24,46 @@ #include #include +#ifdef HAVE_XI2 +#include +#define MAX_MOUSE_IDX MAX_INPUT_DEVICES +#else +#define MAX_MOUSE_IDX 1 +#endif + #include "../input_keymaps.h" +#include "../input_defines.h" #include "../common/input_x11_common.h" #include "../common/linux_common.h" #include "../../configuration.h" #include "../../retroarch.h" +#include "../../verbosity.h" typedef struct x11_input { Display *display; Window win; - int mouse_x; - int mouse_y; - int mouse_delta_x; - int mouse_delta_y; +#ifdef HAVE_XI2 + int mouse_dev_list[MAX_MOUSE_IDX]; +#endif + int mouse_x[MAX_MOUSE_IDX]; + int mouse_y[MAX_MOUSE_IDX]; + int mouse_delta_x[MAX_MOUSE_IDX]; + int mouse_delta_y[MAX_MOUSE_IDX]; bool mouse_grabbed; char state[32]; - bool mouse_l; - bool mouse_r; - bool mouse_m; + bool mouse_l[MAX_MOUSE_IDX]; + bool mouse_r[MAX_MOUSE_IDX]; + bool mouse_m[MAX_MOUSE_IDX]; +#ifdef HAVE_XI2 + bool mouse_4[MAX_MOUSE_IDX]; + bool mouse_5[MAX_MOUSE_IDX]; + XIDeviceInfo *di; +#endif + #ifdef __linux__ /* X11 is mostly used on Linux, but not exclusively. */ linux_illuminance_sensor_t *illuminance_sensor; @@ -58,6 +76,12 @@ extern bool g_x11_entered; static void *x_input_init(const char *joypad_driver) { x11_input_t *x11; +#ifdef HAVE_XI2 + XIDeviceInfo *dev; + XIButtonClassInfo *classinfo; + int i, j = 0; + int cnt; +#endif /* Currently active window is not an X11 window. Cannot use this driver. */ if (video_driver_display_type_get() != RARCH_DISPLAY_X11) @@ -71,6 +95,23 @@ static void *x_input_init(const char *joypad_driver) input_keymaps_init_keyboard_lut(rarch_key_map_x11); +#ifdef HAVE_XI2 + x11->di = XIQueryDevice(x11->display, XIAllDevices, &cnt); + for (i = 0; i < cnt; i++) + { + x11->mouse_dev_list[i] = -1; + dev = &(x11->di[i]); + RARCH_DBG("[X11]: Device detected, %d \"%s\" attached to %d\n", i, dev->name, dev->attachment); + if (dev->use == XIMasterPointer) + { + RARCH_LOG("[X11]: Master pointer, %d \"%s\"\n",dev->deviceid,dev->name); + input_config_set_mouse_display_name(j, dev->name); + x11->mouse_dev_list[j++] = dev->deviceid; + } + } +#else + RARCH_DBG("[X11]: XInput2 support not compiled in, using only 1 mouse.\n"); +#endif return x11; } @@ -83,16 +124,27 @@ static bool x_keyboard_pressed(x11_input_t *x11, unsigned key) static bool x_mouse_button_pressed( x11_input_t *x11, unsigned port, unsigned key) { + unsigned mouse_port = port; +#ifndef HAVE_XI2 + mouse_port = 0; +#endif + switch (key) { case RETRO_DEVICE_ID_MOUSE_LEFT: - return x11->mouse_l; + return x11->mouse_l[mouse_port]; case RETRO_DEVICE_ID_MOUSE_RIGHT: - return x11->mouse_r; + return x11->mouse_r[mouse_port]; case RETRO_DEVICE_ID_MOUSE_MIDDLE: - return x11->mouse_m; + return x11->mouse_m[mouse_port]; case RETRO_DEVICE_ID_MOUSE_BUTTON_4: +#ifdef HAVE_XI2 + return x11->mouse_4[mouse_port]; +#endif case RETRO_DEVICE_ID_MOUSE_BUTTON_5: +#ifdef HAVE_XI2 + return x11->mouse_5[mouse_port]; +#endif case RETRO_DEVICE_ID_MOUSE_WHEELUP: case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: @@ -118,6 +170,11 @@ static int16_t x_input_state( if (port < MAX_USERS) { + unsigned mouse_port = port; + +#ifndef HAVE_XI2 + mouse_port = 0; +#endif x11_input_t *x11 = (x11_input_t*)data; settings_t *settings = config_get_ptr(); @@ -175,7 +232,7 @@ static int16_t x_input_state( } break; case RETRO_DEVICE_ANALOG: - if (binds[port]) + if (binds) { int id_minus_key = 0; int id_plus_key = 0; @@ -218,25 +275,22 @@ static int16_t x_input_state( { case RETRO_DEVICE_ID_MOUSE_X: if (device == RARCH_DEVICE_MOUSE_SCREEN) - return x11->mouse_x; - return x11->mouse_delta_x; + return x11->mouse_x[mouse_port]; + return x11->mouse_delta_x[mouse_port]; case RETRO_DEVICE_ID_MOUSE_Y: if (device == RARCH_DEVICE_MOUSE_SCREEN) - return x11->mouse_y; - return x11->mouse_delta_y; + return x11->mouse_y[mouse_port]; + return x11->mouse_delta_y[mouse_port]; case RETRO_DEVICE_ID_MOUSE_LEFT: - return x11->mouse_l; case RETRO_DEVICE_ID_MOUSE_RIGHT: - return x11->mouse_r; case RETRO_DEVICE_ID_MOUSE_WHEELUP: case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN: case RETRO_DEVICE_ID_MOUSE_BUTTON_4: case RETRO_DEVICE_ID_MOUSE_BUTTON_5: - return x_mouse_state_wheel(id); case RETRO_DEVICE_ID_MOUSE_MIDDLE: - return x11->mouse_m; + return x_mouse_button_pressed(x11, mouse_port, id); } break; case RETRO_DEVICE_POINTER: @@ -253,7 +307,7 @@ static int16_t x_input_state( int16_t res_screen_y = 0; if (video_driver_translate_coord_viewport_confined_wrap( - &vp, x11->mouse_x, x11->mouse_y, + &vp, x11->mouse_x[mouse_port], x11->mouse_y[mouse_port], &res_x, &res_y, &res_screen_x, &res_screen_y)) { if (screen) @@ -270,11 +324,14 @@ static int16_t x_input_state( return res_y; case RETRO_DEVICE_ID_POINTER_PRESSED: if (idx == 0) - return (x11->mouse_l | x11->mouse_r | x11->mouse_m); + return (x11->mouse_l[mouse_port] + | x11->mouse_r[mouse_port] + | x11->mouse_m[mouse_port]); else if (idx == 1) - return (x11->mouse_r | x11->mouse_m); + return (x11->mouse_r[mouse_port] + | x11->mouse_m[mouse_port]); else if (idx == 2) - return x11->mouse_m; + return x11->mouse_m[mouse_port]; case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN: return input_driver_pointer_is_offscreen(res_x, res_y); } @@ -296,7 +353,7 @@ static int16_t x_input_state( int16_t res_screen_y = 0; if (video_driver_translate_coord_viewport_wrap(&vp, - x11->mouse_x, x11->mouse_y, + x11->mouse_x[mouse_port], x11->mouse_y[mouse_port], &res_x, &res_y, &res_screen_x, &res_screen_y)) { switch ( id ) @@ -360,9 +417,9 @@ static int16_t x_input_state( break; /*deprecated*/ case RETRO_DEVICE_ID_LIGHTGUN_X: - return x11->mouse_delta_x; + return x11->mouse_delta_x[mouse_port]; case RETRO_DEVICE_ID_LIGHTGUN_Y: - return x11->mouse_delta_y; + return x11->mouse_delta_y[mouse_port]; } break; } @@ -377,6 +434,9 @@ static void x_input_free(void *data) if (x11) { +#ifdef HAVE_XI2 + XIFreeDeviceInfo(x11->di); +#endif #ifdef __linux__ linux_close_illuminance_sensor(x11->illuminance_sensor); #endif @@ -448,22 +508,39 @@ static void x_input_poll(void *data) Window child_win; x11_input_t *x11 = (x11_input_t*)data; bool video_has_focus = video_driver_has_focus(); +#ifdef HAVE_XI2 + double root_x = 0; + double root_y = 0; + double win_x = 0; + double win_y = 0; + XIButtonState buttons_return; + XIModifierState modifiers_return; + XIGroupState group_return; + settings_t *settings = config_get_ptr(); + unsigned mouse_dev_idx; +#else int root_x = 0; int root_y = 0; int win_x = 0; int win_y = 0; unsigned mask = 0; +#endif + unsigned mouse_port; /* If window loses focus, 'reset' keyboard * and ignore mouse input */ if (!video_has_focus) { - memset(x11->state, 0, sizeof(x11->state)); - x11->mouse_delta_x = 0; - x11->mouse_delta_y = 0; - x11->mouse_l = 0; - x11->mouse_m = 0; - x11->mouse_r = 0; + memset(x11->state, 0, sizeof(x11->state)); + memset(x11->mouse_delta_x, 0, sizeof(x11->mouse_delta_x)); + memset(x11->mouse_delta_y, 0, sizeof(x11->mouse_delta_y)); + memset(x11->mouse_l, 0, sizeof(x11->mouse_l)); + memset(x11->mouse_m, 0, sizeof(x11->mouse_m)); + memset(x11->mouse_r, 0, sizeof(x11->mouse_r)); +#ifdef HAVE_XI2 + memset(x11->mouse_4, 0, sizeof(x11->mouse_4)); + memset(x11->mouse_5, 0, sizeof(x11->mouse_5)); +#endif return; } @@ -474,117 +551,149 @@ static void x_input_poll(void *data) * window, ignore mouse input */ if (!g_x11_entered) { - x11->mouse_delta_x = 0; - x11->mouse_delta_y = 0; - x11->mouse_l = 0; - x11->mouse_m = 0; - x11->mouse_r = 0; + memset(x11->mouse_delta_x, 0, sizeof(x11->mouse_delta_x)); + memset(x11->mouse_delta_y, 0, sizeof(x11->mouse_delta_y)); + memset(x11->mouse_l, 0, sizeof(x11->mouse_l)); + memset(x11->mouse_m, 0, sizeof(x11->mouse_m)); + memset(x11->mouse_r, 0, sizeof(x11->mouse_r)); +#ifdef HAVE_XI2 + memset(x11->mouse_4, 0, sizeof(x11->mouse_4)); + memset(x11->mouse_5, 0, sizeof(x11->mouse_5)); +#endif return; } - /* Process mouse */ - if (!XQueryPointer(x11->display, - x11->win, - &root_win, &child_win, - &root_x, &root_y, - &win_x, &win_y, - &mask)) - return; - - /* > Mouse buttons */ - x11->mouse_l = mask & Button1Mask; - x11->mouse_m = mask & Button2Mask; - x11->mouse_r = mask & Button3Mask; - /* Buttons 4 and 5 are not returned here, so they are handled elsewhere. */ - - /* > Mouse pointer */ - if (!x11->mouse_grabbed) + for(mouse_port = 0; mouse_port < MAX_MOUSE_IDX; mouse_port++) { - /* Mouse is not grabbed - this corresponds - * to 'conventional' pointer input, using - * absolute screen coordinates */ - int mouse_last_x = x11->mouse_x; - int mouse_last_y = x11->mouse_y; - - x11->mouse_x = win_x; - x11->mouse_y = win_y; - - x11->mouse_delta_x = x11->mouse_x - mouse_last_x; - x11->mouse_delta_y = x11->mouse_y - mouse_last_y; - } - else - { - /* Mouse is grabbed - all pointer movement - * must be considered 'relative' */ - XWindowAttributes win_attr; - int centre_x, centre_y; - int warp_x = win_x; - int warp_y = win_y; - bool do_warp = false; - - /* Get dimensions/centre coordinates of - * application window */ - if (!XGetWindowAttributes(x11->display, x11->win, &win_attr)) - { - x11->mouse_delta_x = 0; - x11->mouse_delta_y = 0; +#ifdef HAVE_XI2 + mouse_dev_idx = settings->uints.input_mouse_index[mouse_port]; + if (mouse_dev_idx >= MAX_INPUT_DEVICES || x11->mouse_dev_list[mouse_dev_idx] < 0) return; - } - centre_x = win_attr.width >> 1; - centre_y = win_attr.height >> 1; + /* Process mouse */ + if (!XIQueryPointer( x11->display, + x11->mouse_dev_list[mouse_dev_idx], + x11->win, + &root_win, &child_win, + &root_x, &root_y, + &win_x, &win_y, + &buttons_return, + &modifiers_return, + &group_return)) + return; +#else + if (!XQueryPointer(x11->display, + x11->win, + &root_win, &child_win, + &root_x, &root_y, + &win_x, &win_y, + &mask)) + return; +#endif - /* Get relative movement delta since last - * poll event */ - x11->mouse_delta_x = win_x - centre_x; - x11->mouse_delta_y = win_y - centre_y; +#ifdef HAVE_XI2 + /* > Mouse buttons - fixed map (1,2,3,8,9) */ + x11->mouse_l[mouse_port] = buttons_return.mask_len > 0 ? buttons_return.mask[0] & 1<<1 : 0; + x11->mouse_m[mouse_port] = buttons_return.mask_len > 0 ? buttons_return.mask[0] & 1<<2 : 0; + x11->mouse_r[mouse_port] = buttons_return.mask_len > 0 ? buttons_return.mask[0] & 1<<3 : 0; + x11->mouse_4[mouse_port] = buttons_return.mask_len > 1 ? buttons_return.mask[1] & 1<<0 : 0; + x11->mouse_5[mouse_port] = buttons_return.mask_len > 1 ? buttons_return.mask[1] & 1<<1 : 0; +#else + x11->mouse_l[mouse_port] = mask & Button1Mask; + x11->mouse_m[mouse_port] = mask & Button2Mask; + x11->mouse_r[mouse_port] = mask & Button3Mask; + /* Buttons 4 and 5 are not returned here, so they are handled elsewhere. */ +#endif - /* Get effective 'absolute' pointer location - * (last position + delta, bounded by current - * application window dimensions) */ - x11->mouse_x += x11->mouse_delta_x; - x11->mouse_y += x11->mouse_delta_y; - - /* Clamp X */ - if (x11->mouse_x < 0) - x11->mouse_x = 0; - if (x11->mouse_x >= win_attr.width) - x11->mouse_x = (win_attr.width - 1); - - /* Clamp Y */ - if (x11->mouse_y < 0) - x11->mouse_y = 0; - if (x11->mouse_y >= win_attr.height) - x11->mouse_y = (win_attr.height - 1); - - /* Hack/workaround: - * - X11 gives absolute pointer coordinates - * - Once the pointer reaches a screen edge - * it cannot go any further - * - To achieve 'relative' motion, we therefore - * have to reset the hardware cursor to the - * centre of the screen after polling each - * movement delta, such that it is always - * free to move in all directions during the - * time interval until the next poll event */ - if (win_x != centre_x) + /* > Mouse pointer */ + if (!x11->mouse_grabbed) { - warp_x = centre_x; - do_warp = true; - } + /* Mouse is not grabbed - this corresponds + * to 'conventional' pointer input, using + * absolute screen coordinates */ + int mouse_last_x = x11->mouse_x[mouse_port]; + int mouse_last_y = x11->mouse_y[mouse_port]; - if (win_y != centre_y) - { - warp_y = centre_y; - do_warp = true; - } + x11->mouse_x[mouse_port] = win_x; + x11->mouse_y[mouse_port] = win_y; - if (do_warp) + x11->mouse_delta_x[mouse_port] = x11->mouse_x[mouse_port] - mouse_last_x; + x11->mouse_delta_y[mouse_port] = x11->mouse_y[mouse_port] - mouse_last_y; + } + else { - XWarpPointer(x11->display, None, - x11->win, 0, 0, 0, 0, - warp_x, warp_y); - XSync(x11->display, False); + /* Mouse is grabbed - all pointer movement + * must be considered 'relative' */ + XWindowAttributes win_attr; + int centre_x, centre_y; + int warp_x = win_x; + int warp_y = win_y; + bool do_warp = false; + + /* Get dimensions/centre coordinates of + * application window */ + if (!XGetWindowAttributes(x11->display, x11->win, &win_attr)) + { + x11->mouse_delta_x[mouse_port] = 0; + x11->mouse_delta_y[mouse_port] = 0; + return; + } + + centre_x = win_attr.width >> 1; + centre_y = win_attr.height >> 1; + + /* Get relative movement delta since last + * poll event */ + x11->mouse_delta_x[mouse_port] = win_x - centre_x; + x11->mouse_delta_y[mouse_port] = win_y - centre_y; + + /* Get effective 'absolute' pointer location + * (last position + delta, bounded by current + * application window dimensions) */ + x11->mouse_x[mouse_port] += x11->mouse_delta_x[mouse_port]; + x11->mouse_y[mouse_port] += x11->mouse_delta_y[mouse_port]; + + /* Clamp X */ + if (x11->mouse_x[mouse_port] < 0) + x11->mouse_x[mouse_port] = 0; + if (x11->mouse_x[mouse_port] >= win_attr.width) + x11->mouse_x[mouse_port] = (win_attr.width - 1); + + /* Clamp Y */ + if (x11->mouse_y[mouse_port] < 0) + x11->mouse_y[mouse_port] = 0; + if (x11->mouse_y[mouse_port] >= win_attr.height) + x11->mouse_y[mouse_port] = (win_attr.height - 1); + + /* Hack/workaround: + * - X11 gives absolute pointer coordinates + * - Once the pointer reaches a screen edge + * it cannot go any further + * - To achieve 'relative' motion, we therefore + * have to reset the hardware cursor to the + * centre of the screen after polling each + * movement delta, such that it is always + * free to move in all directions during the + * time interval until the next poll event */ + if (win_x != centre_x) + { + warp_x = centre_x; + do_warp = true; + } + + if (win_y != centre_y) + { + warp_y = centre_y; + do_warp = true; + } + + if (do_warp) + { + XWarpPointer(x11->display, None, + x11->win, 0, 0, 0, 0, + warp_x, warp_y); + XSync(x11->display, False); + } } } } diff --git a/input/drivers_hid/btstack_hid.c b/input/drivers_hid/btstack_hid.c index e5ea40e8f7..865de315f9 100644 --- a/input/drivers_hid/btstack_hid.c +++ b/input/drivers_hid/btstack_hid.c @@ -766,12 +766,11 @@ static void btpad_increment_position(uint32_t *ptr) } static void btpad_connection_send_control(void *data, - uint8_t* data_buf, size_t size) + uint8_t *s, size_t len) { struct btstack_hid_adapter *connection = (struct btstack_hid_adapter*)data; - if (connection) - bt_send_l2cap_ptr(connection->channels[0], data_buf, size); + bt_send_l2cap_ptr(connection->channels[0], s, len); } static void btpad_queue_process_cmd(struct btpad_queue_command *cmd) diff --git a/input/drivers_hid/iohidmanager_hid.c b/input/drivers_hid/iohidmanager_hid.c index 3de1c01d80..58fb876177 100644 --- a/input/drivers_hid/iohidmanager_hid.c +++ b/input/drivers_hid/iohidmanager_hid.c @@ -269,14 +269,14 @@ static bool iohidmanager_hid_joypad_rumble(void *data, unsigned pad, } static void iohidmanager_hid_device_send_control(void *data, - uint8_t* data_buf, size_t size) + uint8_t *s, size_t len) { struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*)data; if (adapter) IOHIDDeviceSetReport(adapter->handle, - kIOHIDReportTypeOutput, 0x01, data_buf + 1, size - 1); + kIOHIDReportTypeOutput, 0x01, s + 1, len - 1); } static void iohidmanager_hid_device_report(void *data, @@ -490,7 +490,7 @@ static void iohidmanager_hid_device_remove(IOHIDDeviceRef device, iohidmanager_h { int i, slot; struct iohidmanager_hid_adapter *adapter = NULL; - + /*loop though the controller ports and find the device with a matching IOHINDeviceRef*/ for (i=0; iptr, matcher); IOHIDManagerRegisterDeviceMatchingCallback(hid->ptr,iohidmanager_hid_device_matched, 0); IOHIDManagerRegisterDeviceRemovalCallback(hid->ptr,iohidmanager_hid_device_removed, 0); - + CFRelease(matcher); return 0; @@ -1088,27 +1087,29 @@ static void iohidmanager_hid_free(const void *data) static void iohidmanager_hid_poll(void *data) { } -static int32_t iohidmanager_set_report(void *handle, uint8_t report_type, uint8_t report_id, uint8_t *data_buf, size_t size) +static int32_t iohidmanager_set_report(void *handle, uint8_t report_type, uint8_t report_id, uint8_t *s, size_t len) { struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*)handle; if (adapter) return IOHIDDeviceSetReport(adapter->handle, translate_hid_report_type(report_type), report_id, - data_buf + 1, size - 1); + s + 1, len - 1); return -1; } static int32_t iohidmanager_get_report(void *handle, uint8_t report_type, uint8_t report_id, - uint8_t *data_buf, size_t size) + uint8_t *s, size_t len) { struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*)handle; if (adapter) { - CFIndex length = size; - return IOHIDDeviceGetReport(adapter->handle, translate_hid_report_type(report_type), report_id, data_buf, &length); + CFIndex length = len; + return IOHIDDeviceGetReport(adapter->handle, + translate_hid_report_type(report_type), + report_id, s, &length); } return -1; diff --git a/input/drivers_hid/libusb_hid.c b/input/drivers_hid/libusb_hid.c index 2df8fe142d..46d336e72f 100644 --- a/input/drivers_hid/libusb_hid.c +++ b/input/drivers_hid/libusb_hid.c @@ -89,26 +89,26 @@ static void adapter_thread(void *data) while (!adapter->quitting) { - size_t send_command_size; int tmp; + size_t _len; int report_number; int size = 0; slock_lock(adapter->send_control_lock); if (FIFO_READ_AVAIL(adapter->send_control_buffer) - >= sizeof(send_command_size)) + >= sizeof(_len)) { fifo_read(adapter->send_control_buffer, - &send_command_size, sizeof(send_command_size)); + &_len, sizeof(_len)); if (FIFO_READ_AVAIL(adapter->send_control_buffer) - >= sizeof(send_command_size)) + >= sizeof(_len)) { fifo_read(adapter->send_control_buffer, - send_command_buf, send_command_size); + send_command_buf, _len); libusb_interrupt_transfer(adapter->handle, adapter->endpoint_out, send_command_buf, - send_command_size, &tmp, 1000); + _len, &tmp, 1000); } } slock_unlock(adapter->send_control_lock); @@ -124,7 +124,7 @@ static void adapter_thread(void *data) } static void libusb_hid_device_send_control(void *data, - uint8_t* data_buf, size_t size) + uint8_t *s, size_t len) { struct libusb_adapter *adapter = (struct libusb_adapter*)data; @@ -133,10 +133,10 @@ static void libusb_hid_device_send_control(void *data, slock_lock(adapter->send_control_lock); - if (FIFO_WRITE_AVAIL(adapter->send_control_buffer) >= size + sizeof(size)) + if (FIFO_WRITE_AVAIL(adapter->send_control_buffer) >= len + sizeof(len)) { - fifo_write(adapter->send_control_buffer, &size, sizeof(size)); - fifo_write(adapter->send_control_buffer, data_buf, size); + fifo_write(adapter->send_control_buffer, &len, sizeof(len)); + fifo_write(adapter->send_control_buffer, s, len); } else { diff --git a/input/drivers_hid/wiiu_hid.c b/input/drivers_hid/wiiu_hid.c index 285bcb9e0a..0acf8fa0ab 100644 --- a/input/drivers_hid/wiiu_hid.c +++ b/input/drivers_hid/wiiu_hid.c @@ -147,8 +147,7 @@ static int16_t wiiu_hid_joypad_axis(void *data, unsigned slot, uint32_t joyaxis) return 0; } -static int16_t wiiu_hid_joypad_state( - void *data, +static int16_t wiiu_hid_joypad_state(void *data, rarch_joypad_info_t *joypad_info, const void *binds_data, unsigned port) @@ -170,11 +169,11 @@ static int16_t wiiu_hid_joypad_state( const uint32_t joyaxis = (binds[i].joyaxis != AXIS_NONE) ? binds[i].joyaxis : joypad_info->auto_binds[i].joyaxis; if ( - (uint16_t)joykey != NO_BTN + (uint16_t)joykey != NO_BTN && pad->iface->button && pad->iface->button(pad->connection, (uint16_t)joykey)) ret |= ( 1 << i); else if (joyaxis != AXIS_NONE && pad->iface->get_axis && - ((float)abs(pad->iface->get_axis(pad->connection, joyaxis)) + ((float)abs(pad->iface->get_axis(pad->connection, joyaxis)) / 0x8000) > joypad_info->axis_threshold) ret |= (1 << i); } @@ -194,12 +193,11 @@ static bool wiiu_hid_joypad_rumble(void *data, unsigned slot, return false; } -static void *wiiu_hid_alloc_zeroed(size_t alignment, size_t size) +static void *wiiu_hid_alloc_zeroed(size_t alignment, size_t len) { - void *result = memalign(alignment, size); + void *result = memalign(alignment, len); if (result) - memset(result, 0, size); - + memset(result, 0, len); return result; } @@ -663,7 +661,7 @@ static uint8_t wiiu_hid_try_init_driver(wiiu_adapter_t *adapter) adapter->device_name); adapter->pad_driver = entry->iface; - + if (entry->iface->multi_pad) return wiiu_hid_try_init_driver_multi(adapter, entry); @@ -749,7 +747,7 @@ static void wiiu_hid_poll(void *data) synchronized_process_adapters(hid); } -static void wiiu_hid_send_control(void *data, uint8_t *buf, size_t size) +static void wiiu_hid_send_control(void *data, uint8_t *s, size_t len) { wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; int32_t result; @@ -761,7 +759,7 @@ static void wiiu_hid_send_control(void *data, uint8_t *buf, size_t size) } memset(adapter->tx_buffer, 0, adapter->tx_size); - memcpy(adapter->tx_buffer, buf, size); + memcpy(adapter->tx_buffer, s, len); /* From testing, HIDWrite returns an error that looks like it's two * int16_t's bitmasked together. For example, one error I saw when trying @@ -776,12 +774,12 @@ static void wiiu_hid_send_control(void *data, uint8_t *buf, size_t size) } } -static void _fixup_report_buffer(uint8_t **buffer, uint8_t report_id, size_t *length) +static void _fixup_report_buffer(uint8_t **s, uint8_t report_id, size_t *len) { - if ((*buffer)[0] == report_id) + if ((*s)[0] == report_id) { - *buffer = (*buffer)+ 1; - *length = *length - 1; + *s = (*s)+ 1; + *len = *len - 1; } } @@ -805,7 +803,8 @@ static int32_t wiiu_hid_set_report(void *data, uint8_t report_type, NULL, NULL); } -static int32_t wiiu_hid_get_report(void *handle, uint8_t report_type, uint8_t report_id, uint8_t *report_data, size_t report_length) +static int32_t wiiu_hid_get_report(void *handle, uint8_t report_type, uint8_t report_id, + uint8_t *report_data, size_t report_length) { wiiu_adapter_t *adapter = (wiiu_adapter_t *)handle; if (!adapter || report_length > adapter->tx_size) @@ -848,25 +847,21 @@ static int32_t wiiu_hid_set_protocol(void *data, uint8_t protocol) NULL, NULL); } -static int32_t wiiu_hid_read(void *data, void *buffer, size_t size) +static int32_t wiiu_hid_read(void *data, void *buffer, size_t len) { wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; int32_t result; - if (!adapter) return -1; - - if (size > adapter->rx_size) + if (len > adapter->rx_size) return -1; - - if ((result = HIDRead(adapter->handle, buffer, size, NULL, NULL)) < 0) + if ((result = HIDRead(adapter->handle, buffer, len, NULL, NULL)) < 0) wiiu_hid_report_hid_error("read failed", adapter, result); - return result; } - -static void wiiu_hid_init_cachealigned_buffer(int32_t min_size, uint8_t **out_buf_ptr, int32_t *actual_size) +static void wiiu_hid_init_cachealigned_buffer(int32_t min_size, + uint8_t **out_buf_ptr, int32_t *actual_size) { *actual_size = (min_size + 0x3f) & ~0x3f; *out_buf_ptr = wiiu_hid_alloc_zeroed(64, *actual_size); diff --git a/input/drivers_hid/wiiusb_hid.c b/input/drivers_hid/wiiusb_hid.c index 4756d5e273..bab98695bb 100644 --- a/input/drivers_hid/wiiusb_hid.c +++ b/input/drivers_hid/wiiusb_hid.c @@ -15,6 +15,8 @@ */ #include +#include +#include #include #include @@ -120,21 +122,21 @@ static int32_t wiiusb_hid_read_cb(int32_t size, void *data) } static void wiiusb_hid_device_send_control(void *data, - uint8_t* data_buf, size_t size) + uint8_t *s, size_t len) { uint8_t control_type; struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)data; - if (!adapter || !data_buf || !adapter->send_control_buffer) + if (!adapter || !s || !adapter->send_control_buffer) return; /* first byte contains the type of control to use * which can be NONE, INT_MSG, CTRL_MSG, CTRL_MSG2 */ - control_type = data_buf[0]; + control_type = s[0]; /* decrement size by one as we are getting rid of first byte */ - adapter->send_control_size = size - 1; + adapter->send_control_size = len - 1; /* increase the buffer address so we access the actual data */ - data_buf++; - memcpy(adapter->send_control_buffer, data_buf, adapter->send_control_size); + s++; + memcpy(adapter->send_control_buffer, s, adapter->send_control_size); /* Activate it so it can be processed in the adapter thread */ adapter->send_control_type = control_type; } @@ -143,20 +145,15 @@ static void wiiusb_hid_device_add_autodetect(unsigned idx, const char *device_name, const char *driver_name, uint16_t dev_vid, uint16_t dev_pid) { - input_autoconfigure_connect( - device_name, - NULL, - "hid", - idx, - dev_vid, - dev_pid); + input_autoconfigure_connect(device_name, NULL, "hid", + idx, dev_vid, dev_pid); } static void wiiusb_get_description(usb_device_entry *device, struct wiiusb_adapter *adapter, usb_devdesc *devdesc) { - unsigned char c; unsigned i, k; + unsigned char c; for (c = 0; c < devdesc->bNumConfigurations; c++) { diff --git a/input/drivers_joypad/dinput_joypad.c b/input/drivers_joypad/dinput_joypad.c index 6063d6eeaf..0dd016b5cf 100644 --- a/input/drivers_joypad/dinput_joypad.c +++ b/input/drivers_joypad/dinput_joypad.c @@ -17,6 +17,7 @@ #include #include #include +#define WIN32_LEAN_AND_MEAN #include #include diff --git a/input/drivers_joypad/dinput_joypad_inl.h b/input/drivers_joypad/dinput_joypad_inl.h index a4b3b9b1da..53163ae997 100644 --- a/input/drivers_joypad/dinput_joypad_inl.h +++ b/input/drivers_joypad/dinput_joypad_inl.h @@ -124,9 +124,9 @@ static int32_t dinput_joypad_button_state( static const unsigned check1 = (JOY_POVRIGHT/2); static const unsigned check2 = (JOY_POVLEFT+JOY_POVRIGHT/2); return ( - (pov == JOY_POVFORWARD) || - (pov == check1) || - (pov == check2) + (pov == JOY_POVFORWARD) + || (pov == check1) + || (pov == check2) ); } case HAT_RIGHT_MASK: @@ -134,20 +134,20 @@ static int32_t dinput_joypad_button_state( static const unsigned check1 = (JOY_POVRIGHT/2); static const unsigned check2 = (JOY_POVRIGHT+JOY_POVRIGHT/2); return ( - (pov == JOY_POVRIGHT) || - (pov == check1) || - (pov == check2) + (pov == JOY_POVRIGHT) + || (pov == check1) + || (pov == check2) ); } case HAT_DOWN_MASK: { static const unsigned check1 = (JOY_POVRIGHT+JOY_POVRIGHT/2); static const unsigned check2 = (JOY_POVBACKWARD+JOY_POVRIGHT/2); - return + return ( - (pov == JOY_POVBACKWARD) || - (pov == check1) || - (pov == check2) + (pov == JOY_POVBACKWARD) + || (pov == check1) + || (pov == check2) ); } case HAT_LEFT_MASK: @@ -157,9 +157,9 @@ static int32_t dinput_joypad_button_state( return ( - (pov == JOY_POVLEFT) || - (pov == check1) || - (pov == check2) + (pov == JOY_POVLEFT) + || (pov == check1) + || (pov == check2) ); } default: @@ -284,12 +284,12 @@ static int16_t dinput_joypad_state( const uint32_t joyaxis = (binds[i].joyaxis != AXIS_NONE) ? binds[i].joyaxis : joypad_info->auto_binds[i].joyaxis; if ( - (uint16_t)joykey != NO_BTN + (uint16_t)joykey != NO_BTN && dinput_joypad_button_state( pad, (uint16_t)joykey)) ret |= ( 1 << i); else if (joyaxis != AXIS_NONE && - ((float)abs(dinput_joypad_axis_state(pad, joyaxis)) + ((float)abs(dinput_joypad_axis_state(pad, joyaxis)) / 0x8000) > joypad_info->axis_threshold) ret |= (1 << i); } diff --git a/input/drivers_joypad/gx_joypad.c b/input/drivers_joypad/gx_joypad.c index 9fb75383e8..50fd77f745 100644 --- a/input/drivers_joypad/gx_joypad.c +++ b/input/drivers_joypad/gx_joypad.c @@ -142,8 +142,10 @@ static void power_callback(void) } #endif -static void reset_cb(void) +static void reset_cb(unsigned int a, void *b) { + (void)a; + (void)b; g_menu = true; } diff --git a/input/drivers_joypad/rwebpad_joypad.c b/input/drivers_joypad/rwebpad_joypad.c index 1c63cf690f..09e75258cc 100644 --- a/input/drivers_joypad/rwebpad_joypad.c +++ b/input/drivers_joypad/rwebpad_joypad.c @@ -19,6 +19,7 @@ #include #include #include +#include "../../frontend/drivers/platform_emscripten.h" #include "../input_driver.h" @@ -26,6 +27,17 @@ #include "../../verbosity.h" #define CLAMPDOUBLE(x) MIN(1.0, MAX(-1.0, (x))) +#define NUM_BUTTONS 64 +#define NUM_AXES 64 + +typedef struct +{ + struct EmscriptenGamepadEvent pads[DEFAULT_MAX_PADS]; + bool live_pads[DEFAULT_MAX_PADS]; +} rwebpad_joypad_data_t; + +/* TODO/FIXME - static globals */ +static rwebpad_joypad_data_t *rwebpad_joypad_data = NULL; static EM_BOOL rwebpad_gamepad_cb(int event_type, const EmscriptenGamepadEvent *gamepad_event, void *user_data) @@ -36,6 +48,8 @@ static EM_BOOL rwebpad_gamepad_cb(int event_type, switch (event_type) { case EMSCRIPTEN_EVENT_GAMEPADCONNECTED: + rwebpad_joypad_data->pads[gamepad_event->index] = *gamepad_event; + rwebpad_joypad_data->live_pads[gamepad_event->index] = true; input_autoconfigure_connect( gamepad_event->id, /* name */ NULL, /* display name */ @@ -45,6 +59,7 @@ static EM_BOOL rwebpad_gamepad_cb(int event_type, pid); /* pid */ break; case EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED: + rwebpad_joypad_data->live_pads[gamepad_event->index] = false; input_autoconfigure_disconnect(gamepad_event->index, rwebpad_joypad.ident); break; @@ -61,58 +76,56 @@ static void *rwebpad_joypad_init(void *data) if (r == EMSCRIPTEN_RESULT_NOT_SUPPORTED) return NULL; - /* callbacks needs to be registered for gamepads to connect */ + if (!rwebpad_joypad_data) + { + rwebpad_joypad_data = (rwebpad_joypad_data_t*)calloc(1, sizeof(rwebpad_joypad_data_t)); + if (!rwebpad_joypad_data) + return NULL; + } + + /* callbacks need to be registered for gamepads to connect */ r = emscripten_set_gamepadconnected_callback(NULL, false, rwebpad_gamepad_cb); r = emscripten_set_gamepaddisconnected_callback(NULL, false, rwebpad_gamepad_cb); - return (void*)-1; + return (void*)(-1); } static const char *rwebpad_joypad_name(unsigned pad) { - static EmscriptenGamepadEvent gamepad_state; - EMSCRIPTEN_RESULT r = emscripten_get_gamepad_status(pad, &gamepad_state); - if (r == EMSCRIPTEN_RESULT_SUCCESS) - return gamepad_state.id; - return ""; + if (pad >= DEFAULT_MAX_PADS || !rwebpad_joypad_data->live_pads[pad]) { + return ""; + } + return rwebpad_joypad_data->pads[pad].id; } static int32_t rwebpad_joypad_button(unsigned port, uint16_t joykey) { EmscriptenGamepadEvent gamepad_state; - EMSCRIPTEN_RESULT r = emscripten_get_gamepad_status( - port, &gamepad_state); - - if (port >= DEFAULT_MAX_PADS) - return 0; - if (r != EMSCRIPTEN_RESULT_SUCCESS) + if (port >= DEFAULT_MAX_PADS || !rwebpad_joypad_data->live_pads[port]) return 0; + gamepad_state = rwebpad_joypad_data->pads[port]; if (joykey < gamepad_state.numButtons) return gamepad_state.digitalButton[joykey]; return 0; } -static void rwebpad_joypad_get_buttons(unsigned port_num, input_bits_t *state) +static void rwebpad_joypad_get_buttons(unsigned port, input_bits_t *state) { EmscriptenGamepadEvent gamepad_state; - EMSCRIPTEN_RESULT r = emscripten_get_gamepad_status( - port_num, &gamepad_state); - - if (r == EMSCRIPTEN_RESULT_SUCCESS) - { - unsigned i; - - for (i = 0; i < gamepad_state.numButtons; i++) - { - if (gamepad_state.digitalButton[i]) - BIT256_SET_PTR(state, i); - } - } - else + unsigned i; + if (port >= DEFAULT_MAX_PADS || !rwebpad_joypad_data->live_pads[port]) { BIT256_CLEAR_ALL_PTR(state); + return; + } + gamepad_state = rwebpad_joypad_data->pads[port]; + for (i = 0; i < gamepad_state.numButtons; i++) + { + if (gamepad_state.digitalButton[i]) + BIT256_SET_PTR(state, i); + } } static int16_t rwebpad_joypad_axis_state( @@ -138,11 +151,10 @@ static int16_t rwebpad_joypad_axis_state( static int16_t rwebpad_joypad_axis(unsigned port, uint32_t joyaxis) { - EmscriptenGamepadEvent gamepad_state; - EMSCRIPTEN_RESULT r = emscripten_get_gamepad_status(port, &gamepad_state); - if (r != EMSCRIPTEN_RESULT_SUCCESS) + if (port >= DEFAULT_MAX_PADS || !rwebpad_joypad_data->live_pads[port]) { return 0; - return rwebpad_joypad_axis_state(&gamepad_state, port, joyaxis); + } + return rwebpad_joypad_axis_state(&rwebpad_joypad_data->pads[port], port, joyaxis); } static int16_t rwebpad_joypad_state( @@ -154,13 +166,9 @@ static int16_t rwebpad_joypad_state( EmscriptenGamepadEvent gamepad_state; int16_t ret = 0; uint16_t port_idx = joypad_info->joy_idx; - EMSCRIPTEN_RESULT r = emscripten_get_gamepad_status( - port_idx, &gamepad_state); - if (r != EMSCRIPTEN_RESULT_SUCCESS) + if (port_idx >= DEFAULT_MAX_PADS || !rwebpad_joypad_data->live_pads[port]) return 0; - if (port_idx >= DEFAULT_MAX_PADS) - return 0; - + gamepad_state = rwebpad_joypad_data->pads[port]; for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++) { /* Auto-binds are per joypad, not per user. */ @@ -184,19 +192,25 @@ static int16_t rwebpad_joypad_state( return ret; } +static void rwebpad_joypad_do_poll(void *data) +{ + int i; + emscripten_sample_gamepad_data(); + for (i = 0; i < DEFAULT_MAX_PADS; i++) + { + if (rwebpad_joypad_data->live_pads[i]) + emscripten_get_gamepad_status(i, &rwebpad_joypad_data->pads[i]); + } +} + static void rwebpad_joypad_poll(void) { - emscripten_sample_gamepad_data(); + platform_emscripten_run_on_browser_thread_sync(rwebpad_joypad_do_poll, NULL); } static bool rwebpad_joypad_query_pad(unsigned pad) { - EmscriptenGamepadEvent gamepad_state; - EMSCRIPTEN_RESULT r = emscripten_get_gamepad_status(pad, &gamepad_state); - - if (r == EMSCRIPTEN_RESULT_SUCCESS) - return gamepad_state.connected == EM_TRUE; - return false; + return rwebpad_joypad_data->live_pads[pad]; } static void rwebpad_joypad_destroy(void) { } diff --git a/input/drivers_joypad/sdl_dingux_joypad.c b/input/drivers_joypad/sdl_dingux_joypad.c index b110b9d121..b8a80ec41f 100644 --- a/input/drivers_joypad/sdl_dingux_joypad.c +++ b/input/drivers_joypad/sdl_dingux_joypad.c @@ -194,8 +194,8 @@ static bool sdl_dingux_rumble_init(dingux_joypad_rumble_t *rumble) /* Check whether shake device has the required * feature set */ - if (!Shake_QueryEffectSupport(rumble->device, SHAKE_EFFECT_PERIODIC) || - !Shake_QueryWaveformSupport(rumble->device, SHAKE_PERIODIC_SINE)) + if ( !Shake_QueryEffectSupport(rumble->device, SHAKE_EFFECT_PERIODIC) + || !Shake_QueryWaveformSupport(rumble->device, SHAKE_PERIODIC_SINE)) goto error; /* In most cases it is recommended to use SHAKE_EFFECT_PERIODIC @@ -311,8 +311,7 @@ static bool sdl_dingux_joypad_set_rumble(unsigned pad, { dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; - if ((pad != 0) || - !joypad->rumble.device) + if ((pad != 0) || !joypad->rumble.device) return false; switch (effect) @@ -336,8 +335,7 @@ static bool sdl_dingux_joypad_set_rumble_gain(unsigned pad, unsigned gain) { dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; - if ((pad != 0) || - !joypad->rumble.device) + if ((pad != 0) || !joypad->rumble.device) return false; /* Gain is automatically capped by Shake_SetGain(), diff --git a/input/drivers_joypad/switch_joypad.c b/input/drivers_joypad/switch_joypad.c index 65d4ff0278..308f930ee6 100644 --- a/input/drivers_joypad/switch_joypad.c +++ b/input/drivers_joypad/switch_joypad.c @@ -430,7 +430,7 @@ bool switch_joypad_set_rumble(unsigned pad, HidVibrationDeviceHandle* handle; float amp; - if (pad >= DEFAULT_MAX_PADS || !vibration_handles[pad]) + if (pad >= DEFAULT_MAX_PADS) return false; amp = (float)strength / 65535.0f; diff --git a/input/drivers_joypad/test_joypad.c b/input/drivers_joypad/test_joypad.c index 28b475fa81..c4c93c2b07 100644 --- a/input/drivers_joypad/test_joypad.c +++ b/input/drivers_joypad/test_joypad.c @@ -125,7 +125,7 @@ static bool JTifJSONObjectEndHandler(void* context) return true; } -static bool JTifJSONObjectMemberHandler(void* context, const char *pValue, size_t length) +static bool JTifJSONObjectMemberHandler(void* context, const char *pValue, size_t len) { JTifJSONContext *pCtx = (JTifJSONContext*)context; @@ -133,7 +133,7 @@ static bool JTifJSONObjectMemberHandler(void* context, const char *pValue, size_ if (pCtx->current_entry_str_val) return false; - if (length) + if (len) { if (string_is_equal(pValue, "frame")) pCtx->current_entry_uint_val = &pCtx->frame; @@ -149,11 +149,11 @@ static bool JTifJSONObjectMemberHandler(void* context, const char *pValue, size_ return true; } -static bool JTifJSONNumberHandler(void* context, const char *pValue, size_t length) +static bool JTifJSONNumberHandler(void* context, const char *pValue, size_t len) { JTifJSONContext *pCtx = (JTifJSONContext*)context; - if (pCtx->current_entry_uint_val && length && !string_is_empty(pValue)) + if (pCtx->current_entry_uint_val && len && !string_is_empty(pValue)) *pCtx->current_entry_uint_val = string_to_unsigned(pValue); /* ignore unknown members */ @@ -162,11 +162,11 @@ static bool JTifJSONNumberHandler(void* context, const char *pValue, size_t leng return true; } -static bool JTifJSONStringHandler(void* context, const char *pValue, size_t length) +static bool JTifJSONStringHandler(void* context, const char *pValue, size_t len) { JTifJSONContext *pCtx = (JTifJSONContext*)context; - if (pCtx->current_entry_str_val && length && !string_is_empty(pValue)) + if (pCtx->current_entry_str_val && len && !string_is_empty(pValue)) { if (*pCtx->current_entry_str_val) free(*pCtx->current_entry_str_val); @@ -394,9 +394,7 @@ static int16_t test_joypad_state( ? binds[i].joykey : joypad_info->auto_binds[i].joykey; /* Test input driver uses same button layout internally as RA, so no conversion is needed */ if (joykey != NO_BTN && (test_joypads[port_idx].button_state & (1 << i))) - { ret |= ( 1 << i); - } } } @@ -426,8 +424,8 @@ static void test_joypad_poll(void) test_joypad_autodetect_remove(input_test_steps[i].param_num); input_test_steps[i].handled = true; } - else if( input_test_steps[i].action >= JOYPAD_TEST_COMMAND_BUTTON_PRESS_FIRST && - input_test_steps[i].action <= JOYPAD_TEST_COMMAND_BUTTON_PRESS_LAST) + else if ( input_test_steps[i].action >= JOYPAD_TEST_COMMAND_BUTTON_PRESS_FIRST + && input_test_steps[i].action <= JOYPAD_TEST_COMMAND_BUTTON_PRESS_LAST) { unsigned targetpad = input_test_steps[i].action - JOYPAD_TEST_COMMAND_BUTTON_PRESS_FIRST; test_joypads[targetpad].button_state |= input_test_steps[i].param_num; @@ -436,8 +434,8 @@ static void test_joypad_poll(void) "[Test joypad driver]: Pressing device %d buttons %x, new state %x.\n", targetpad,input_test_steps[i].param_num,test_joypads[targetpad].button_state); } - else if( input_test_steps[i].action >= JOYPAD_TEST_COMMAND_BUTTON_RELEASE_FIRST && - input_test_steps[i].action <= JOYPAD_TEST_COMMAND_BUTTON_RELEASE_LAST) + else if ( input_test_steps[i].action >= JOYPAD_TEST_COMMAND_BUTTON_RELEASE_FIRST + && input_test_steps[i].action <= JOYPAD_TEST_COMMAND_BUTTON_RELEASE_LAST) { unsigned targetpad = input_test_steps[i].action - JOYPAD_TEST_COMMAND_BUTTON_RELEASE_FIRST; test_joypads[targetpad].button_state &= ~input_test_steps[i].param_num; @@ -446,8 +444,8 @@ static void test_joypad_poll(void) "[Test joypad driver]: Releasing device %d buttons %x, new state %x.\n", targetpad,input_test_steps[i].param_num,test_joypads[targetpad].button_state); } - else if( input_test_steps[i].action >= JOYPAD_TEST_COMMAND_BUTTON_AXIS_FIRST && - input_test_steps[i].action <= JOYPAD_TEST_COMMAND_BUTTON_AXIS_LAST) + else if ( input_test_steps[i].action >= JOYPAD_TEST_COMMAND_BUTTON_AXIS_FIRST + && input_test_steps[i].action <= JOYPAD_TEST_COMMAND_BUTTON_AXIS_LAST) { unsigned targetpad = (input_test_steps[i].action - JOYPAD_TEST_COMMAND_BUTTON_AXIS_FIRST) / MAX_AXIS; @@ -482,10 +480,7 @@ static bool test_joypad_query_pad(unsigned pad) return (pad < MAX_USERS); } -static void test_joypad_destroy(void) -{ - -} +static void test_joypad_destroy(void) { } input_device_driver_t test_joypad = { test_joypad_init, diff --git a/input/drivers_joypad/udev_joypad.c b/input/drivers_joypad/udev_joypad.c index d06bb00b8e..4e7fd4049c 100644 --- a/input/drivers_joypad/udev_joypad.c +++ b/input/drivers_joypad/udev_joypad.c @@ -520,17 +520,18 @@ static void udev_joypad_poll(void) for (p = 0; p < MAX_USERS; p++) { - int i, len; + int i; + ssize_t _len; struct input_event events[32]; struct udev_joypad *pad = &udev_pads[p]; if (pad->fd < 0) continue; - while ((len = read(pad->fd, events, sizeof(events))) > 0) + while ((_len = read(pad->fd, events, sizeof(events))) > 0) { - len /= sizeof(*events); - for (i = 0; i < len; i++) + _len /= sizeof(*events); + for (i = 0; i < _len; i++) { uint16_t type = events[i].type; uint16_t code = events[i].code; diff --git a/input/drivers_keyboard/keyboard_event_apple.h b/input/drivers_keyboard/keyboard_event_apple.h index d1a5b6c131..4737791381 100644 --- a/input/drivers_keyboard/keyboard_event_apple.h +++ b/input/drivers_keyboard/keyboard_event_apple.h @@ -166,6 +166,8 @@ enum RETRO_BEGIN_DECLS +void apple_input_keyboard_reset(void); + void apple_input_keyboard_event(bool down, unsigned code, uint32_t character, uint32_t mod, unsigned device); diff --git a/input/drivers_keyboard/keyboard_event_xkb.c b/input/drivers_keyboard/keyboard_event_xkb.c index 4f7292559c..75f2912f6c 100644 --- a/input/drivers_keyboard/keyboard_event_xkb.c +++ b/input/drivers_keyboard/keyboard_event_xkb.c @@ -56,39 +56,35 @@ void free_xkb(void) xkb_state = NULL; } -int init_xkb(int fd, size_t size) +int init_xkb(int fd, size_t len) { - mod_map_idx = (xkb_mod_index_t *)calloc( + mod_map_idx = (xkb_mod_index_t *)calloc( MOD_MAP_SIZE, sizeof(xkb_mod_index_t)); if (!mod_map_idx) goto error; - mod_map_bit = (uint16_t*) - calloc(MOD_MAP_SIZE, sizeof(uint16_t)); - - if (!mod_map_bit) + if (!(mod_map_bit = (uint16_t*) + calloc(MOD_MAP_SIZE, sizeof(uint16_t)))) goto error; - xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - if (xkb_ctx) + if ((xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS))) { if (fd >= 0) { - char *map_str = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + char *map_str = (char*)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); if (map_str == MAP_FAILED) goto error; xkb_map = xkb_keymap_new_from_string(xkb_ctx, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - munmap(map_str, size); + munmap(map_str, len); } else { struct xkb_rule_names rule = {0}; settings_t *settings = config_get_ptr(); - const char *input_keyboard_layout = + const char *input_keyboard_layout = settings->arrays.input_keyboard_layout; rule.rules = "evdev"; diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h index b6e63dcfc1..c3c6d1441b 100644 --- a/input/include/hid_driver.h +++ b/input/include/hid_driver.h @@ -49,12 +49,12 @@ struct hid_driver bool (*set_rumble)(void *handle, unsigned pad, enum retro_rumble_effect effect, uint16_t); const char *(*name)(void *handle, unsigned pad); const char *ident; - void (*send_control)(void *handle, uint8_t *buf, size_t size); - int32_t (*set_report)(void *handle, uint8_t report_type, uint8_t report_id, uint8_t *data, size_t length); - int32_t (*get_report)(void *handle, uint8_t report_type, uint8_t report_id, uint8_t *data, size_t length); + void (*send_control)(void *handle, uint8_t *s, size_t len); + int32_t (*set_report)(void *handle, uint8_t report_type, uint8_t report_id, uint8_t *data, size_t len); + int32_t (*get_report)(void *handle, uint8_t report_type, uint8_t report_id, uint8_t *data, size_t len); int32_t (*set_idle)(void *handle, uint8_t amount); int32_t (*set_protocol)(void *handle, uint8_t protocol); - int32_t (*read)(void *handle, void *buf, size_t size); + int32_t (*read)(void *handle, void *s, size_t len); }; #endif /* HID_DRIVER_H__ */ diff --git a/input/input_defines.h b/input/input_defines.h index 5ba2f88fe8..7c03962b2a 100644 --- a/input/input_defines.h +++ b/input/input_defines.h @@ -166,6 +166,7 @@ enum RARCH_RECORDING_TOGGLE, RARCH_STREAMING_TOGGLE, + RARCH_TURBO_FIRE_TOGGLE, RARCH_GRAB_MOUSE_TOGGLE, RARCH_GAME_FOCUS_TOGGLE, RARCH_FULLSCREEN_TOGGLE_KEY, @@ -230,21 +231,6 @@ enum input_turbo_mode INPUT_TURBO_MODE_LAST }; -enum input_turbo_default_button -{ - INPUT_TURBO_DEFAULT_BUTTON_B = 0, - INPUT_TURBO_DEFAULT_BUTTON_Y, - INPUT_TURBO_DEFAULT_BUTTON_A, - INPUT_TURBO_DEFAULT_BUTTON_X, - INPUT_TURBO_DEFAULT_BUTTON_L, - INPUT_TURBO_DEFAULT_BUTTON_R, - INPUT_TURBO_DEFAULT_BUTTON_L2, - INPUT_TURBO_DEFAULT_BUTTON_R2, - INPUT_TURBO_DEFAULT_BUTTON_L3, - INPUT_TURBO_DEFAULT_BUTTON_R3, - INPUT_TURBO_DEFAULT_BUTTON_LAST -}; - enum input_device_reservation_type { INPUT_DEVICE_RESERVATION_NONE = 0, diff --git a/input/input_driver.c b/input/input_driver.c index e47a935ff5..03767c49d2 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -61,6 +61,8 @@ #include "../tasks/tasks_internal.h" #include "../verbosity.h" +#include "../ai/game_ai.h" + #define HOLD_BTN_DELAY_SEC 2 /* Depends on ASCII character values */ @@ -523,10 +525,8 @@ bool input_driver_set_sensor( port, action, rate); } else if (input_driver_st.primary_joypad && input_driver_st.primary_joypad->set_sensor_state) - { return input_driver_st.primary_joypad->set_sensor_state(NULL, port, action, rate); - } return false; } @@ -545,10 +545,8 @@ float input_driver_get_sensor( } else if (sensors_enable && input_driver_st.primary_joypad && input_driver_st.primary_joypad->get_sensor_input) - { return input_driver_st.primary_joypad->get_sensor_input(NULL, port, id); - } } return 0.0f; @@ -647,10 +645,10 @@ static bool input_driver_button_combo_hold( bool input_driver_pointer_is_offscreen(int16_t x, int16_t y) { const int edge_detect = 32700; - if ((x >= -edge_detect) && - (y >= -edge_detect) && - (x <= edge_detect) && - (y <= edge_detect)) + if ( (x >= -edge_detect) + && (y >= -edge_detect) + && (x <= edge_detect) + && (y <= edge_detect)) return false; return true; } @@ -769,7 +767,7 @@ static int32_t input_state_wrap( unsigned idx, unsigned id) { - int32_t ret = 0; + int32_t ret = 0; if (!binds) return 0; @@ -781,11 +779,9 @@ static int32_t input_state_wrap( if (id == RETRO_DEVICE_ID_JOYPAD_MASK) { if (joypad) - ret |= joypad->state( - joypad_info, binds[_port], _port); + ret |= joypad->state(joypad_info, binds[_port], _port); if (sec_joypad) - ret |= sec_joypad->state( - joypad_info, binds[_port], _port); + ret |= sec_joypad->state(joypad_info, binds[_port], _port); } else { @@ -857,7 +853,7 @@ static int16_t input_joypad_axis( const input_device_driver_t *drv, unsigned port, uint32_t joyaxis, float normal_mag) { - int16_t val = (joyaxis != AXIS_NONE) ? drv->axis(port, joyaxis) : 0; + int16_t val = (joyaxis != AXIS_NONE) ? drv->axis(port, joyaxis) : 0; if (input_analog_deadzone) { @@ -878,14 +874,11 @@ static int16_t input_joypad_axis( if (input_analog_sensitivity != 1.0f) { float normalized = (1.0f / 0x7fff) * val; - int new_val = 0x7fff * normalized * - input_analog_sensitivity; - + int new_val = 0x7fff * normalized * input_analog_sensitivity; if (new_val > 0x7fff) return 0x7fff; else if (new_val < -0x7fff) return -0x7fff; - return new_val; } @@ -919,9 +912,9 @@ static int16_t input_joypad_analog_button( unsigned ident, const struct retro_keybind *bind) { - int16_t res = 0; - float normal_mag = 0.0f; - uint32_t axis = (bind->joyaxis == AXIS_NONE) + int16_t res = 0; + float normal_mag = 0.0f; + uint32_t axis = (bind->joyaxis == AXIS_NONE) ? joypad_info->auto_binds[ident].joyaxis : bind->joyaxis; @@ -998,8 +991,8 @@ static int16_t input_joypad_analog_axis( input_conv_analog_id_to_bind_id(idx, ident, ident_minus, ident_plus); - bind_minus = &binds[ident_minus]; - bind_plus = &binds[ident_plus]; + bind_minus = &binds[ident_minus]; + bind_plus = &binds[ident_plus]; if (!bind_minus->valid || !bind_plus->valid) return 0; @@ -1022,6 +1015,39 @@ static int16_t input_joypad_analog_axis( if (!bind_y_minus->valid || !bind_y_plus->valid) return 0; + /* Keyboard bind priority */ + if ( bind_plus->key != RETROK_UNKNOWN + || bind_minus->key != RETROK_UNKNOWN) + { + input_driver_state_t *input_st = &input_driver_st; + + if (bind_plus->key && input_state_wrap( + input_st->current_driver, + input_st->current_data, + input_st->primary_joypad, + NULL, + joypad_info, + (*input_st->libretro_input_binds), + (input_st->flags & INP_FLAG_KB_MAPPING_BLOCKED) ? true : false, + 0, RETRO_DEVICE_KEYBOARD, 0, + bind_plus->key)) + res = 0x7fff; + if (bind_minus->key && input_state_wrap( + input_st->current_driver, + input_st->current_data, + input_st->primary_joypad, + NULL, + joypad_info, + (*input_st->libretro_input_binds), + (input_st->flags & INP_FLAG_KB_MAPPING_BLOCKED) ? true : false, + 0, RETRO_DEVICE_KEYBOARD, 0, + bind_minus->key)) + res += -0x7fff; + + if (res) + return res; + } + { uint32_t axis_minus = (bind_minus->joyaxis == AXIS_NONE) ? joypad_info->auto_binds[ident_minus].joyaxis @@ -1050,16 +1076,16 @@ static int16_t input_joypad_analog_axis( ? joypad_info->auto_binds[ident_y_plus].joyaxis : bind_y_plus->joyaxis; /* normalized magnitude for radial scaled analog deadzone */ - if (x_axis_plus != AXIS_NONE) + if (x_axis_plus != AXIS_NONE && drv->axis) x = drv->axis( joypad_info->joy_idx, x_axis_plus); - if (x_axis_minus != AXIS_NONE) + if (x_axis_minus != AXIS_NONE && drv->axis) x += drv->axis(joypad_info->joy_idx, x_axis_minus); - if (y_axis_plus != AXIS_NONE) + if (y_axis_plus != AXIS_NONE && drv->axis) y = drv->axis( joypad_info->joy_idx, y_axis_plus); - if (y_axis_minus != AXIS_NONE) + if (y_axis_minus != AXIS_NONE && drv->axis) y += drv->axis( joypad_info->joy_idx, y_axis_minus); normal_mag = (1.0f / 0x7fff) * sqrt(x * x + y * y); @@ -1087,9 +1113,9 @@ static int16_t input_joypad_analog_axis( uint16_t key_plus = (bind_plus->joykey == NO_BTN) ? joypad_info->auto_binds[ident_plus].joykey : bind_plus->joykey; - if (drv->button(joypad_info->joy_idx, key_plus)) + if (drv->button && drv->button(joypad_info->joy_idx, key_plus)) res = 0x7fff; - if (drv->button(joypad_info->joy_idx, key_minus)) + if (drv->button && drv->button(joypad_info->joy_idx, key_minus)) res += -0x7fff; } @@ -1101,8 +1127,7 @@ void input_keyboard_line_append( const char *word, size_t len) { size_t i; - char *newbuf = (char*)realloc( - keyboard_line->buffer, + char *newbuf = (char*)realloc(keyboard_line->buffer, keyboard_line->size + len * 2); if (!newbuf) @@ -1162,34 +1187,32 @@ const char **input_keyboard_start_line( } #ifdef HAVE_OVERLAY -static int16_t input_overlay_device_mouse_state(input_overlay_t *ol, unsigned id) +static int16_t input_overlay_device_mouse_state( + input_overlay_t *ol, unsigned id) { - input_overlay_pointer_state_t *ptr_st = &ol->pointer_state; int16_t res; + input_overlay_pointer_state_t *ptr_st = &ol->pointer_state; switch(id) { case RETRO_DEVICE_ID_MOUSE_X: ptr_st->device_mask |= (1 << RETRO_DEVICE_MOUSE); - - res = ptr_st->mouse.scale_x + res = (ptr_st->mouse.scale_x) * (ptr_st->screen_x - ptr_st->mouse.prev_screen_x); - ptr_st->mouse.prev_screen_x = ptr_st->screen_x; return res; case RETRO_DEVICE_ID_MOUSE_Y: - res = ptr_st->mouse.scale_y + res = (ptr_st->mouse.scale_y) * (ptr_st->screen_y - ptr_st->mouse.prev_screen_y); - ptr_st->mouse.prev_screen_y = ptr_st->screen_y; return res; case RETRO_DEVICE_ID_MOUSE_LEFT: - return (ptr_st->mouse.click & 0x1) || - (ptr_st->mouse.hold & 0x1); + return (ptr_st->mouse.click & 0x1) + || (ptr_st->mouse.hold & 0x1); case RETRO_DEVICE_ID_MOUSE_RIGHT: - return (ptr_st->mouse.click & 0x2) || - (ptr_st->mouse.hold & 0x2); + return (ptr_st->mouse.click & 0x2) + || (ptr_st->mouse.hold & 0x2); case RETRO_DEVICE_ID_MOUSE_MIDDLE: - return (ptr_st->mouse.click & 0x4) || - (ptr_st->mouse.hold & 0x4); + return (ptr_st->mouse.click & 0x4) + || (ptr_st->mouse.hold & 0x4); default: break; } @@ -1197,7 +1220,8 @@ static int16_t input_overlay_device_mouse_state(input_overlay_t *ol, unsigned id return 0; } -static int16_t input_overlay_lightgun_state(settings_t *settings, +static int16_t input_overlay_lightgun_state( + bool input_overlay_lightgun_allow_offscreen, input_overlay_t *ol, unsigned id) { unsigned rarch_id; @@ -1210,19 +1234,19 @@ static int16_t input_overlay_lightgun_state(settings_t *settings, case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X: ptr_st->device_mask |= (1 << RETRO_DEVICE_LIGHTGUN); if ( ( ptr_st->ptr[0].x > -0x7fff && ptr_st->ptr[0].x != 0x7fff) - || !settings->bools.input_overlay_lightgun_allow_offscreen) + || !input_overlay_lightgun_allow_offscreen) return ptr_st->ptr[0].x; else return -0x8000; case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y: if ( ( ptr_st->ptr[0].y > -0x7fff && ptr_st->ptr[0].y != 0x7fff) - || !settings->bools.input_overlay_lightgun_allow_offscreen) + || !input_overlay_lightgun_allow_offscreen) return ptr_st->ptr[0].y; else return -0x8000; case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN: ptr_st->device_mask |= (1 << RETRO_DEVICE_LIGHTGUN); - return ( settings->bools.input_overlay_lightgun_allow_offscreen + return ( input_overlay_lightgun_allow_offscreen && input_driver_pointer_is_offscreen(ptr_st->ptr[0].x, ptr_st->ptr[0].y)); case RETRO_DEVICE_ID_LIGHTGUN_AUX_A: case RETRO_DEVICE_ID_LIGHTGUN_AUX_B: @@ -1252,7 +1276,7 @@ static int16_t input_overlay_pointer_state(input_overlay_t *ol, input_overlay_pointer_state_t *ptr_st, unsigned idx, unsigned id) { - ptr_st->device_mask |= (1 << RETRO_DEVICE_POINTER); + ptr_st->device_mask |= (1 << RETRO_DEVICE_POINTER); switch (id) { @@ -1273,7 +1297,9 @@ static int16_t input_overlay_pointer_state(input_overlay_t *ol, return 0; } -static int16_t input_overlay_pointing_device_state(settings_t *settings, +static int16_t input_overlay_pointing_device_state( + int input_overlay_lightgun_port, + bool input_overlay_lightgun_allow_offscreen, input_overlay_t *ol, unsigned port, unsigned device, unsigned idx, unsigned id) { @@ -1282,9 +1308,11 @@ static int16_t input_overlay_pointing_device_state(settings_t *settings, case RETRO_DEVICE_MOUSE: return input_overlay_device_mouse_state(ol, id); case RETRO_DEVICE_LIGHTGUN: - if ( settings->ints.input_overlay_lightgun_port == -1 - || settings->ints.input_overlay_lightgun_port == (int)port) - return input_overlay_lightgun_state(settings, ol, id); + if ( input_overlay_lightgun_port == -1 + || input_overlay_lightgun_port == (int)port) + return input_overlay_lightgun_state( + input_overlay_lightgun_allow_offscreen, + ol, id); break; case RETRO_DEVICE_POINTER: return input_overlay_pointer_state(ol, @@ -1394,10 +1422,8 @@ input_remote_t *input_driver_init_remote( settings_t *settings, unsigned num_active_users) { - unsigned network_remote_base_port = settings->uints.network_remote_base_port; - return input_remote_new( - settings, - network_remote_base_port, + return input_remote_new(settings, + settings->uints.network_remote_base_port, num_active_users); } #endif @@ -1471,8 +1497,9 @@ static int16_t input_state_device( * > 'id' is not equal to remapped button index * If these conditions are met, input here * is ignored */ - if ((menu_driver_alive || !input_remap_binds_enable) || - (id == remap_button)) + if ( (menu_driver_alive + || !input_remap_binds_enable) + || (id == remap_button)) res |= 1; } #endif @@ -1480,14 +1507,24 @@ static int16_t input_state_device( /* Don't allow turbo for D-pad unless explicitly allowed. */ if ( (id < RETRO_DEVICE_ID_JOYPAD_UP) - || ( ((settings->bools.input_allow_turbo_dpad) + || ( ((settings->bools.input_turbo_allow_dpad || settings->ints.input_turbo_bind != -1) || (id > RETRO_DEVICE_ID_JOYPAD_RIGHT)) && (id <= RETRO_DEVICE_ID_JOYPAD_R3))) { /* * Apply turbo button if activated. */ - unsigned turbo_mode = settings->uints.input_turbo_mode; + uint8_t turbo_period = settings->uints.input_turbo_period; + uint8_t turbo_duty_cycle = settings->uints.input_turbo_duty_cycle; + uint8_t turbo_mode = settings->uints.input_turbo_mode; + + if (turbo_duty_cycle == 0) + turbo_duty_cycle = turbo_period / 2; + + /* Clear underlying button to prevent duplicates. */ + if ( input_st->turbo_btns.frame_enable[port] + && (int)id == settings->ints.input_turbo_bind) + res = 0; if (turbo_mode > INPUT_TURBO_MODE_CLASSIC_TOGGLE) { @@ -1502,27 +1539,13 @@ static int16_t input_state_device( input_st->turbo_btns.turbo_pressed[port] &= ~(1 << 31); else if (input_st->turbo_btns.turbo_pressed[port] >= 0) { + unsigned turbo_button = settings->uints.input_turbo_button; + unsigned remap_button = settings->uints.input_remap_ids[port][turbo_button]; + input_st->turbo_btns.turbo_pressed[port] |= (1 << 31); /* Toggle turbo for selected buttons. */ - if (input_st->turbo_btns.enable[port] - != (1 << settings->uints.input_turbo_default_button)) - { - static const int button_map[]={ - RETRO_DEVICE_ID_JOYPAD_B, - RETRO_DEVICE_ID_JOYPAD_Y, - RETRO_DEVICE_ID_JOYPAD_A, - RETRO_DEVICE_ID_JOYPAD_X, - RETRO_DEVICE_ID_JOYPAD_L, - RETRO_DEVICE_ID_JOYPAD_R, - RETRO_DEVICE_ID_JOYPAD_L2, - RETRO_DEVICE_ID_JOYPAD_R2, - RETRO_DEVICE_ID_JOYPAD_L3, - RETRO_DEVICE_ID_JOYPAD_R3}; - input_st->turbo_btns.enable[port] = 1 << button_map[ - MIN( - ARRAY_SIZE(button_map) - 1, - settings->uints.input_turbo_default_button)]; - } + if (input_st->turbo_btns.enable[port] != (1 << remap_button)) + input_st->turbo_btns.enable[port] = (1 << remap_button); input_st->turbo_btns.mode1_enable[port] ^= 1; } @@ -1544,20 +1567,15 @@ static int16_t input_state_device( } } /* Hold mode stops turbo on release */ - else if ( - turbo_mode == INPUT_TURBO_MODE_SINGLEBUTTON_HOLD - && input_st->turbo_btns.enable[port] - && input_st->turbo_btns.mode1_enable[port]) + else if ((turbo_mode == INPUT_TURBO_MODE_SINGLEBUTTON_HOLD) + && (input_st->turbo_btns.enable[port]) + && (input_st->turbo_btns.mode1_enable[port])) input_st->turbo_btns.mode1_enable[port] = 0; - if (!res && input_st->turbo_btns.mode1_enable[port] && - input_st->turbo_btns.enable[port] & (1 << id)) - { - /* If turbo button is enabled for this key ID */ - res = (( input_st->turbo_btns.count - % settings->uints.input_turbo_period) - < settings->uints.input_turbo_duty_cycle); - } + if ( (!res) + && (input_st->turbo_btns.mode1_enable[port]) + && (input_st->turbo_btns.enable[port] & (1 << id))) + res = ((input_st->turbo_btns.count % turbo_period) < turbo_duty_cycle); } else if (turbo_mode == INPUT_TURBO_MODE_CLASSIC) { @@ -1573,9 +1591,7 @@ static int16_t input_state_device( if (input_st->turbo_btns.enable[port] & (1 << id)) /* if turbo button is enabled for this key ID */ - res = ((input_st->turbo_btns.count - % settings->uints.input_turbo_period) - < settings->uints.input_turbo_duty_cycle); + res = ((input_st->turbo_btns.count % turbo_period) < turbo_duty_cycle); } else input_st->turbo_btns.enable[port] &= ~(1 << id); @@ -1598,17 +1614,13 @@ static int16_t input_state_device( } } else - { input_st->turbo_btns.turbo_pressed[port] &= ~(1 << id); - } if (res) { if (input_st->turbo_btns.enable[port] & (1 << id)) /* If turbo button is enabled for this key ID */ - res = (( input_st->turbo_btns.count - % settings->uints.input_turbo_period) - < settings->uints.input_turbo_duty_cycle); + res = ((input_st->turbo_btns.count % turbo_period) < turbo_duty_cycle); } } } @@ -1758,11 +1770,13 @@ static int16_t input_state_device( if ( (input_st->overlay_ptr) && (input_st->overlay_ptr->flags & INPUT_OVERLAY_ENABLE) && (settings->bools.input_overlay_pointer_enable)) - res = input_overlay_pointing_device_state(settings, + res = input_overlay_pointing_device_state( + settings->ints.input_overlay_lightgun_port, + settings->bools.input_overlay_lightgun_allow_offscreen, input_st->overlay_ptr, port, device, idx, id); #endif - if (input_st->flags & INP_FLAG_BLOCK_POINTER_INPUT) + if (res || input_st->flags & INP_FLAG_BLOCK_POINTER_INPUT) break; if (id < RARCH_FIRST_META_KEY) @@ -1796,17 +1810,18 @@ static int16_t input_state_internal( unsigned idx, unsigned id) { rarch_joypad_info_t joypad_info; - unsigned mapped_port; float input_analog_deadzone = settings->floats.input_analog_deadzone; float input_analog_sensitivity = settings->floats.input_analog_sensitivity; unsigned *input_remap_port_map = settings->uints.input_remap_port_map[port]; - bool input_driver_analog_requested = input_st->analog_requested[port]; + uint8_t max_users = settings->uints.input_max_users; const input_device_driver_t *joypad = input_st->primary_joypad; #ifdef HAVE_MFI const input_device_driver_t *sec_joypad = input_st->secondary_joypad; #else const input_device_driver_t *sec_joypad = NULL; #endif + uint8_t mapped_port = 0; + int16_t result = 0; #ifdef HAVE_MENU struct menu_state *menu_st = menu_state_get_ptr(); bool input_blocked = (menu_st->input_driver_flushing_input > 0) @@ -1814,9 +1829,8 @@ static int16_t input_state_internal( #else bool input_blocked = (input_st->flags & INP_FLAG_BLOCK_LIBRETRO_INPUT) ? true : false; #endif + bool input_driver_analog_requested = input_st->analog_requested[port]; bool bitmask_enabled = false; - unsigned max_users = settings->uints.input_max_users; - int16_t result = 0; device &= RETRO_DEVICE_MASK; bitmask_enabled = (device == RETRO_DEVICE_JOYPAD) @@ -1827,12 +1841,12 @@ static int16_t input_state_internal( * 'virtual' port index */ while ((mapped_port = *(input_remap_port_map++)) < MAX_USERS) { - int32_t ret = 0; - int32_t port_result = 0; - unsigned input_analog_dpad_mode = settings->uints.input_analog_dpad_mode[mapped_port]; + int16_t ret = 0; + int16_t port_result = 0; + uint8_t input_analog_dpad_mode = settings->uints.input_analog_dpad_mode[mapped_port]; - joypad_info.joy_idx = settings->uints.input_joypad_index[mapped_port]; - joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx]; + joypad_info.joy_idx = settings->uints.input_joypad_index[mapped_port]; + joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx]; /* Skip disabled input devices */ if (mapped_port >= max_users) @@ -1871,8 +1885,13 @@ static int16_t input_state_internal( (input_st->flags & INP_FLAG_KB_MAPPING_BLOCKED) ? true : false, mapped_port, device, idx, id); - if ( (device == RETRO_DEVICE_ANALOG) - && (ret == 0)) + /* Ignore analog sticks when using Analog to Digital */ + if ( (device == RETRO_DEVICE_ANALOG) + && (input_analog_dpad_mode != ANALOG_DPAD_NONE)) + ret = 0; + + if ( (device == RETRO_DEVICE_ANALOG) + && (ret == 0)) { if (input_st->libretro_input_binds[mapped_port]) { @@ -1942,7 +1961,7 @@ static int16_t input_state_internal( if (bitmask_enabled) { - unsigned i; + uint8_t i; for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++) if (input_state_device(input_st, settings, handle, @@ -1955,6 +1974,69 @@ static int16_t input_state_internal( settings, handle, input_analog_dpad_mode, ret, mapped_port, device, idx, id, false); + + /* Handle Analog to Digital */ + if ( (device == RETRO_DEVICE_JOYPAD) + && (input_analog_dpad_mode != ANALOG_DPAD_NONE) + && (bitmask_enabled || (id >= RETRO_DEVICE_ID_JOYPAD_UP && id <= RETRO_DEVICE_ID_JOYPAD_RIGHT))) + { + int16_t ret_axis; + uint8_t s; + uint8_t a; + + for (s = RETRO_DEVICE_INDEX_ANALOG_LEFT; s <= RETRO_DEVICE_INDEX_ANALOG_RIGHT; s++) + { + if ( (s == RETRO_DEVICE_INDEX_ANALOG_LEFT && input_analog_dpad_mode != ANALOG_DPAD_LSTICK) + || (s == RETRO_DEVICE_INDEX_ANALOG_RIGHT && input_analog_dpad_mode != ANALOG_DPAD_RSTICK)) + continue; + + for (a = RETRO_DEVICE_ID_ANALOG_X; a <= RETRO_DEVICE_ID_ANALOG_Y; a++) + { + ret_axis = input_joypad_analog_axis( + ANALOG_DPAD_NONE, + settings->floats.input_analog_deadzone, + settings->floats.input_analog_sensitivity, + joypad, + &joypad_info, + s, + a, + (*input_st->libretro_input_binds[mapped_port])); + + if (ret_axis) + { + if (a == RETRO_DEVICE_ID_ANALOG_Y && (float)ret_axis / 0x7fff < -joypad_info.axis_threshold) + { + if (bitmask_enabled) + port_result |= (1 << RETRO_DEVICE_ID_JOYPAD_UP); + else if (id == RETRO_DEVICE_ID_JOYPAD_UP) + port_result = RETRO_DEVICE_ID_JOYPAD_UP; + } + else if (a == RETRO_DEVICE_ID_ANALOG_Y && (float)ret_axis / 0x7fff > joypad_info.axis_threshold) + { + if (bitmask_enabled) + port_result |= (1 << RETRO_DEVICE_ID_JOYPAD_DOWN); + else if (id == RETRO_DEVICE_ID_JOYPAD_DOWN) + port_result = RETRO_DEVICE_ID_JOYPAD_DOWN; + } + + if (a == RETRO_DEVICE_ID_ANALOG_X && (float)ret_axis / 0x7fff < -joypad_info.axis_threshold) + { + if (bitmask_enabled) + port_result |= (1 << RETRO_DEVICE_ID_JOYPAD_LEFT); + else if (id == RETRO_DEVICE_ID_JOYPAD_LEFT) + port_result = RETRO_DEVICE_ID_JOYPAD_LEFT; + } + else if (a == RETRO_DEVICE_ID_ANALOG_X && (float)ret_axis / 0x7fff > joypad_info.axis_threshold) + { + if (bitmask_enabled) + port_result |= (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT); + else if (id == RETRO_DEVICE_ID_JOYPAD_RIGHT) + port_result = RETRO_DEVICE_ID_JOYPAD_RIGHT; + } + } + } + } + } } /* Digital values are represented by a bitmap; @@ -2277,27 +2359,31 @@ static void input_overlay_get_analog_state( if (first_touch) { - unsigned recenter_zone = + unsigned recenter_zone = /* [0,100] */ config_get_ptr()->uints.input_overlay_analog_recenter_zone; - /* Reset analog center */ - x_center[b] = desc->x_shift; - y_center[b] = desc->y_shift; - if (recenter_zone != 0) { - /* Get analog state without adjusting center or saturation */ - x_val = (x - desc->x_shift) / desc->range_x; - y_val = (y - desc->y_shift) / desc->range_y; + float touch_dist, w; - /* Recenter if within zone */ - if ( (x_val * x_val + y_val * y_val) * 1e4 - < (recenter_zone * recenter_zone) - || recenter_zone >= 100) - { - x_center[b] = x; - y_center[b] = y; - } + x_val = (x - desc->x_shift) / desc->range_x; + y_val = (y - desc->y_shift) / desc->range_y; + touch_dist = sqrt((x_val * x_val + y_val * y_val) * 1e4); + + /* Inside zone, recenter to first touch. + * Outside zone, recenter to zone perimeter. */ + if (touch_dist <= recenter_zone || recenter_zone >= 100) + w = 0.0f; + else + w = (touch_dist - recenter_zone) / touch_dist; + + x_center[b] = x * (1.0f - w) + desc->x_shift * w; + y_center[b] = y * (1.0f - w) + desc->y_shift * w; + } + else + { + x_center[b] = desc->x_shift; + y_center[b] = desc->y_shift; } } @@ -3085,18 +3171,15 @@ static void input_overlay_get_mouse_scale(settings_t *settings, { video_driver_state_t *video_st = video_state_get_ptr(); struct retro_game_geometry *geom = &video_st->av_info.geometry; - float swipe_thres; - float adj_x, adj_y; - float display_aspect, core_aspect; - float speed; if (geom->base_height) { - speed = settings->floats.input_overlay_mouse_speed; - swipe_thres = + float adj_x, adj_y; + float speed = settings->floats.input_overlay_mouse_speed; + float swipe_thres = 655.35f * settings->floats.input_overlay_mouse_swipe_threshold; - display_aspect = (float)video_st->width / video_st->height; - core_aspect = (float)geom->base_width / geom->base_height; + float display_aspect = (float)video_st->width / video_st->height; + float core_aspect = (float)geom->base_width / geom->base_height; if (display_aspect > core_aspect) { @@ -3173,14 +3256,9 @@ static void input_overlay_poll_mouse(settings_t *settings, mouse_st->click = 0; pending_click = false; - if (ptr_count) - { - /* Assume main pointer changed. Reset deltas */ - mouse_st->prev_screen_x = x_start = ptr_st->screen_x; - mouse_st->prev_screen_y = y_start = ptr_st->screen_y; - } - else - old_peak_ptr_count = peak_ptr_count; + /* Assume main pointer changed. Reset deltas */ + mouse_st->prev_screen_x = x_start = ptr_st->screen_x; + mouse_st->prev_screen_y = y_start = ptr_st->screen_y; if (ptr_count > old_ptr_count) { @@ -3189,8 +3267,12 @@ static void input_overlay_poll_mouse(settings_t *settings, start_usec = now_usec; } else + { /* Pointer removed */ mouse_st->hold = 0; + if (!ptr_count) + old_peak_ptr_count = peak_ptr_count; + } } /* Action type */ @@ -3368,11 +3450,13 @@ static void input_overlay_update_pointer_coords( if ( !ptr_st->count && (ptr_st->device_mask & (1 << RETRO_DEVICE_MOUSE))) { + ptr_st->mouse.prev_screen_x = ptr_st->screen_x; ptr_st->screen_x = current_input->input_state( input_data, NULL, NULL, NULL, NULL, true, 0, RARCH_DEVICE_POINTER_SCREEN, touch_idx, RETRO_DEVICE_ID_POINTER_X); + ptr_st->mouse.prev_screen_y = ptr_st->screen_y; ptr_st->screen_y = current_input->input_state( input_data, NULL, NULL, NULL, NULL, true, 0, RARCH_DEVICE_POINTER_SCREEN, @@ -3538,8 +3622,6 @@ static void input_poll_overlay( if (ptr_state->device_mask & (1 << RETRO_DEVICE_MOUSE)) input_overlay_poll_mouse(settings, &ptr_state->mouse, ol, ptr_state->count, old_ptr_count); - - ptr_state->device_mask = 0; } if ( OVERLAY_GET_KEY(ol_state, RETROK_LSHIFT) @@ -3629,11 +3711,20 @@ static void input_poll_overlay( (input_overlay_show_inputs == OVERLAY_SHOW_INPUT_TOUCHED), input_overlay_show_inputs_port); - if (button_pressed || ol_ptr_enable) + /* Block other touchscreen input as needed. */ + if ( button_pressed +#ifdef IOS + || (ptr_state->device_mask & (1 << RETRO_DEVICE_LIGHTGUN)) + || (ol->flags & INPUT_OVERLAY_BLOCKED)) +#else + || ol_ptr_enable) +#endif input_st->flags |= INP_FLAG_BLOCK_POINTER_INPUT; else input_st->flags &= ~INP_FLAG_BLOCK_POINTER_INPUT; + ptr_state->device_mask = 0; + if (input_overlay_show_inputs == OVERLAY_SHOW_INPUT_NONE) button_pressed = false; @@ -3912,7 +4003,7 @@ void osk_update_last_codepoint( #ifdef HAVE_LANGEXTRA /* combine 3 korean elements. make utf8 character */ -static unsigned get_kr_utf8( int c1,int c2,int c3) +static unsigned get_kr_utf8(int c1, int c2, int c3) { int uv = c1 * (28 * 21) + c2 * 28 + c3 + 0xac00; int tv = (uv >> 12) | ((uv & 0x0f00) << 2) | ((uv & 0xc0) << 2) | ((uv & 0x3f) << 16); @@ -3920,7 +4011,7 @@ static unsigned get_kr_utf8( int c1,int c2,int c3) } /* utf8 korean composition */ -static unsigned get_kr_composition( char* pcur, char* padd) +static unsigned get_kr_composition(char* pcur, char* padd) { size_t _len; static char cc1[] = {"ㄱㄱㄲ ㄷㄷㄸ ㅂㅂㅃ ㅅㅅㅆ ㅈㅈㅉ"}; @@ -4088,7 +4179,6 @@ static bool input_keyboard_line_event( bool ret = false; const char *word = NULL; char c = (character >= 128) ? '?' : character; - #ifdef HAVE_LANGEXTRA static uint32_t composition = 0; /* reset composition, when edit box is opened. */ @@ -4099,12 +4189,12 @@ static bool input_keyboard_line_event( composition = 0; if (IS_COMPOSITION(character) || IS_END_COMPOSITION(character)) { - size_t len = strlen((char*)&composition); - if (composition && state->buffer && state->size >= len && state->ptr >= len) + size_t _len = strlen((char*)&composition); + if (composition && state->buffer && state->size >= _len && state->ptr >= _len) { - memmove(state->buffer + state->ptr-len, state->buffer + state->ptr, len + 1); - state->ptr -= len; - state->size -= len; + memmove(state->buffer + state->ptr - _len, state->buffer + state->ptr, _len + 1); + state->ptr -= _len; + state->size -= _len; } if (IS_COMPOSITION_KR(character) && composition) { @@ -4123,7 +4213,7 @@ static bool input_keyboard_line_event( composition = character & 0xffffff; character &= 0xffffff; } - if (len && composition == 0) + if (_len && composition == 0) word = state->buffer; if (character) input_keyboard_line_append(state, (char*)&character, strlen((char*)&character)); @@ -4134,7 +4224,6 @@ static bool input_keyboard_line_event( /* Treat extended chars as ? as we cannot support * printable characters for unicode stuff. */ - if (c == '\r' || c == '\n') { state->cb(state->userdata, state->buffer); @@ -4206,7 +4295,7 @@ void input_event_osk_append( int ptr, bool show_symbol_pages, const char *word, - size_t word_len) + size_t len) { #ifdef HAVE_LANGEXTRA if (string_is_equal(word, "\xe2\x87\xa6")) /* backspace character */ @@ -4237,7 +4326,7 @@ void input_event_osk_append( else *osk_idx = ((enum osk_type)(OSK_TYPE_UNKNOWN + 1)); } - else if (*osk_idx == OSK_KOREAN_PAGE1 && word && word_len == 3) + else if (*osk_idx == OSK_KOREAN_PAGE1 && word && len == 3) { unsigned character = *((unsigned*)word) | 0x01000000; input_keyboard_line_event(&input_driver_st, keyboard_line, character); @@ -4260,7 +4349,7 @@ void input_event_osk_append( #endif else { - input_keyboard_line_append(keyboard_line, word, word_len); + input_keyboard_line_append(keyboard_line, word, len); osk_update_last_codepoint( osk_last_codepoint, osk_last_codepoint_len, @@ -4353,8 +4442,7 @@ void input_mapper_reset(void *data) bool input_set_sensor_state(unsigned port, enum retro_sensor_action action, unsigned rate) { - settings_t *settings = config_get_ptr(); - bool input_sensors_enable = settings->bools.input_sensors_enable; + bool input_sensors_enable = config_get_ptr()->bools.input_sensors_enable; return input_driver_set_sensor( port, input_sensors_enable, action, rate); } @@ -4403,9 +4491,7 @@ void joypad_driver_reinit(void *data, const char *joypad_driver_name) **/ float input_get_sensor_state(unsigned port, unsigned id) { - settings_t *settings = config_get_ptr(); - bool input_sensors_enable = settings->bools.input_sensors_enable; - + bool input_sensors_enable = config_get_ptr()->bools.input_sensors_enable; return input_driver_get_sensor(port, input_sensors_enable, id); } @@ -4448,17 +4534,14 @@ bool input_set_rumble_state(unsigned port, **/ bool input_set_rumble_gain(unsigned gain) { - settings_t *settings = config_get_ptr(); - if (input_driver_set_rumble_gain( - gain, settings->uints.input_max_users)) - return true; - return false; + return (input_driver_set_rumble_gain( + gain, config_get_ptr()->uints.input_max_users)); } uint64_t input_driver_get_capabilities(void) { - if ( !input_driver_st.current_driver || - !input_driver_st.current_driver->get_capabilities) + if ( !input_driver_st.current_driver + || !input_driver_st.current_driver->get_capabilities) return 0; return input_driver_st.current_driver->get_capabilities(input_driver_st.current_data); } @@ -4489,7 +4572,6 @@ bool input_key_pressed(int key, bool keyboard_pressed) ) ) { - settings_t *settings = config_get_ptr(); const input_device_driver_t *joypad = (const input_device_driver_t*) input_driver_st.primary_joypad; @@ -4498,7 +4580,7 @@ bool input_key_pressed(int key, bool keyboard_pressed) const uint64_t autobind_joykey = input_autoconf_binds[0][key].joykey; const uint64_t autobind_joyaxis= input_autoconf_binds[0][key].joyaxis; uint16_t port = 0; - float axis_threshold = settings->floats.input_axis_threshold; + float axis_threshold = config_get_ptr()->floats.input_axis_threshold; const uint64_t joykey = (bind_joykey != NO_BTN) ? bind_joykey : autobind_joykey; const uint64_t joyaxis = (bind_joyaxis != AXIS_NONE) @@ -4560,8 +4642,8 @@ bool video_driver_init_input( /* This should never really happen as tmp (driver.input) is always * found before this in find_driver_input(), or we have aborted * in a similar fashion anyways. */ - if ( !input_driver_st.current_driver || - !(new_data = input_driver_init_wrap( + if ( !input_driver_st.current_driver + || !(new_data = input_driver_init_wrap( input_driver_st.current_driver, settings->arrays.input_joypad_driver))) { @@ -4626,7 +4708,6 @@ void input_config_reset(void) void input_config_set_device(unsigned port, unsigned id) { settings_t *settings = config_get_ptr(); - if (settings && (port < MAX_USERS)) configuration_set_uint(settings, settings->uints.input_libretro_device[port], id); @@ -4635,10 +4716,8 @@ void input_config_set_device(unsigned port, unsigned id) unsigned input_config_get_device(unsigned port) { settings_t *settings = config_get_ptr(); - if (settings && (port < MAX_USERS)) return settings->uints.input_libretro_device[port]; - return RETRO_DEVICE_NONE; } @@ -4656,10 +4735,8 @@ const struct retro_keybind *input_config_get_bind_auto( unsigned *input_config_get_device_ptr(unsigned port) { settings_t *settings = config_get_ptr(); - if (settings && (port < MAX_USERS)) return &settings->uints.input_libretro_device[port]; - return NULL; } @@ -5018,10 +5095,14 @@ void input_driver_init_command(input_driver_state_t *input_st, } #endif -#ifdef HAVE_LAKKA +#if defined(HAVE_LAKKA) if (!(input_st->command[2] = command_uds_new())) RARCH_ERR("Failed to initialize the UDS command interface.\n"); +#elif defined(EMSCRIPTEN) + if (!(input_st->command[2] = command_emscripten_new())) + RARCH_ERR("Failed to initialize the emscripten command interface.\n"); #endif + } void input_driver_deinit_command(input_driver_state_t *input_st) @@ -5176,11 +5257,11 @@ static void input_overlay_swap_with_cached(void) void input_overlay_unload(void) { - settings_t *settings = config_get_ptr(); + bool input_overlay_enable = config_get_ptr()->bools.input_overlay_enable; runloop_state_t *runloop_st = runloop_state_get_ptr(); /* Free if overlays disabled or initing/deiniting core */ - if ( !settings->bools.input_overlay_enable + if ( !input_overlay_enable || !(runloop_st->flags & RUNLOOP_FLAG_IS_INITED) || (runloop_st->flags & RUNLOOP_FLAG_SHUTDOWN_INITIATED)) input_overlay_deinit(); @@ -5229,7 +5310,6 @@ static bool input_overlay_want_hidden(void) void input_overlay_check_mouse_cursor(void) { - settings_t *settings = config_get_ptr(); input_driver_state_t *input_st = &input_driver_st; video_driver_state_t *video_st = video_state_get_ptr(); input_overlay_t *ol = input_st->overlay_ptr; @@ -5238,7 +5318,7 @@ void input_overlay_check_mouse_cursor(void) && video_st->poke && video_st->poke->show_mouse) { - if (settings->bools.input_overlay_show_mouse_cursor) + if (config_get_ptr()->bools.input_overlay_show_mouse_cursor) video_st->poke->show_mouse(video_st->data, true); else if (input_st->flags & INP_FLAG_GRAB_MOUSE_STATE) video_st->poke->show_mouse(video_st->data, false); @@ -5249,15 +5329,14 @@ void input_overlay_check_mouse_cursor(void) static void input_overlay_loaded(retro_task_t *task, void *task_data, void *user_data, const char *err) { - settings_t *settings = config_get_ptr(); +#ifdef HAVE_MENU + uint16_t overlay_types; +#endif overlay_task_data_t *data = (overlay_task_data_t*)task_data; input_overlay_t *ol = NULL; input_driver_state_t *input_st = &input_driver_st; bool enable_overlay = !input_overlay_want_hidden() - && settings->bools.input_overlay_enable; -#ifdef HAVE_MENU - uint16_t overlay_types; -#endif + && config_get_ptr()->bools.input_overlay_enable; if (err) return; @@ -5513,7 +5592,7 @@ static void input_keys_pressed( const input_device_driver_t *joypad, const input_device_driver_t *sec_joypad, rarch_joypad_info_t *joypad_info, - settings_t *settings) + bool input_hotkey_device_merge) { unsigned i; input_driver_state_t *input_st = &input_driver_st; @@ -5529,7 +5608,7 @@ static void input_keys_pressed( if (!binds) return; - if ( settings->bools.input_hotkey_device_merge + if ( input_hotkey_device_merge && (libretro_hotkey_set || keyboard_hotkey_set)) libretro_hotkey_set = keyboard_hotkey_set = true; @@ -5615,15 +5694,13 @@ static void input_keys_pressed( if (!libretro_input_pressed) { - bool keyboard_menu_pressed = false; - /* Ignore keyboard menu toggle button and check * joypad menu toggle button for pressing * it without 'enable_hotkey', because Guide button * is not part of the usual buttons. */ i = RARCH_MENU_TOGGLE; - keyboard_menu_pressed = binds[port][i].valid + if (!(binds[port][i].valid && input_state_wrap( input_st->current_driver, input_st->current_data, @@ -5633,9 +5710,7 @@ static void input_keys_pressed( binds, (input_st->flags & INP_FLAG_KB_MAPPING_BLOCKED) ? true : false, port, RETRO_DEVICE_KEYBOARD, 0, - input_config_binds[port][i].key); - - if (!keyboard_menu_pressed) + input_config_binds[port][i].key))) { bool bit_pressed = binds[port][i].valid && input_state_wrap( @@ -5823,7 +5898,8 @@ static void input_keys_pressed( /* Forward declaration */ void bsv_movie_free(bsv_movie_t*); -void bsv_movie_enqueue(input_driver_state_t *input_st, bsv_movie_t * state, enum bsv_flags flags) +void bsv_movie_enqueue(input_driver_state_t *input_st, + bsv_movie_t * state, enum bsv_flags flags) { if (input_st->bsv_movie_state_next_handle) bsv_movie_free(input_st->bsv_movie_state_next_handle); @@ -5850,7 +5926,8 @@ void bsv_movie_frame_rewind(void) { input_driver_state_t *input_st = &input_driver_st; bsv_movie_t *handle = input_st->bsv_movie_state_handle; - bool recording = (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_RECORDING) ? true : false; + bool recording = (input_st->bsv_movie_state.flags + & BSV_FLAG_MOVIE_RECORDING) ? true : false; if (!handle) return; @@ -5892,7 +5969,12 @@ void bsv_movie_frame_rewind(void) { /* We rewound past the beginning. */ - if (!handle->playback) + if (handle->playback) + { + intfstream_seek(handle->file, (int)handle->min_file_pos, SEEK_SET); + bsv_movie_read_next_events(handle); + } + else { retro_ctx_serialize_info_t serial_info; @@ -5909,25 +5991,9 @@ void bsv_movie_frame_rewind(void) intfstream_write(handle->file, handle->state, handle->state_size); } - else - { - intfstream_seek(handle->file, (int)handle->min_file_pos, SEEK_SET); - bsv_movie_read_next_events(handle); - } } } -/* Zero out key events when playing back or recording */ -static void bsv_movie_handle_clear_key_events(bsv_movie_t *movie) -{ - movie->key_event_count = 0; -} -/* Zero out input events when playing back or recording */ -static void bsv_movie_handle_clear_input_events(bsv_movie_t *movie) -{ - movie->input_event_count = 0; -} - void bsv_movie_handle_push_key_event(bsv_movie_t *movie, uint8_t down, uint16_t mod, uint32_t code, uint32_t character) { @@ -5940,8 +6006,9 @@ void bsv_movie_handle_push_key_event(bsv_movie_t *movie, movie->key_events[movie->key_event_count] = data; movie->key_event_count++; } + void bsv_movie_handle_push_input_event(bsv_movie_t *movie, - uint8_t port, uint8_t dev, uint8_t idx, uint16_t id, int16_t val) + uint8_t port, uint8_t dev, uint8_t idx, uint16_t id, int16_t val) { bsv_input_data_t data; data.port = port; @@ -5953,24 +6020,25 @@ void bsv_movie_handle_push_input_event(bsv_movie_t *movie, movie->input_events[movie->input_event_count] = data; movie->input_event_count++; } + bool bsv_movie_handle_read_input_event(bsv_movie_t *movie, - uint8_t port, uint8_t dev, uint8_t idx, uint16_t id, int16_t* val) + uint8_t port, uint8_t dev, uint8_t idx, uint16_t id, int16_t* val) { int i; /* if movie is old, just read two bytes and hope for the best */ if (movie->version == 0) { - int read = intfstream_read(movie->file, val, 2); - *val = swap_if_big16(*val); - return read == 2; + int64_t read = intfstream_read(movie->file, val, 2); + *val = swap_if_big16(*val); + return (read == 2); } for (i = 0; i < movie->input_event_count; i++) { bsv_input_data_t evt = movie->input_events[i]; - if (evt.port == port && - evt.device == dev && - evt.idx == idx && - evt.id == id) + if ( (evt.port == port) + && (evt.device == dev) + && (evt.idx == idx) + && (evt.id == id)) { *val = swap_if_big16(evt.value); return true; @@ -5981,13 +6049,14 @@ bool bsv_movie_handle_read_input_event(bsv_movie_t *movie, void bsv_movie_finish_rewind(input_driver_state_t *input_st) { - bsv_movie_t *handle = input_st->bsv_movie_state_handle; + bsv_movie_t *handle = input_st->bsv_movie_state_handle; if (!handle) return; handle->frame_counter += 1; - handle->first_rewind = !handle->did_rewind; - handle->did_rewind = false; + handle->first_rewind = !handle->did_rewind; + handle->did_rewind = false; } + void bsv_movie_read_next_events(bsv_movie_t *handle) { input_driver_state_t *input_st = input_state_get_ptr(); @@ -5996,7 +6065,8 @@ void bsv_movie_read_next_events(bsv_movie_t *handle) int i; for (i = 0; i < handle->key_event_count; i++) { - if (intfstream_read(handle->file, &(handle->key_events[i]), sizeof(bsv_key_data_t)) != sizeof(bsv_key_data_t)) + if (intfstream_read(handle->file, &(handle->key_events[i]), + sizeof(bsv_key_data_t)) != sizeof(bsv_key_data_t)) { /* Unnatural EOF */ RARCH_ERR("[Replay] Keyboard replay ran out of keyboard inputs too early\n"); @@ -6020,7 +6090,8 @@ void bsv_movie_read_next_events(bsv_movie_t *handle) handle->input_event_count = swap_if_big16(handle->input_event_count); for (i = 0; i < handle->input_event_count; i++) { - if (intfstream_read(handle->file, &(handle->input_events[i]), sizeof(bsv_input_data_t)) != sizeof(bsv_input_data_t)) + if (intfstream_read(handle->file, &(handle->input_events[i]), + sizeof(bsv_input_data_t)) != sizeof(bsv_input_data_t)) { /* Unnatural EOF */ RARCH_ERR("[Replay] Input replay ran out of inputs too early\n"); @@ -6040,24 +6111,22 @@ void bsv_movie_read_next_events(bsv_movie_t *handle) { uint8_t next_frame_type=REPLAY_TOKEN_INVALID; - if (intfstream_read(handle->file, (uint8_t *)(&next_frame_type), sizeof(uint8_t)) != sizeof(uint8_t)) + if (intfstream_read(handle->file, (uint8_t *)(&next_frame_type), + sizeof(uint8_t)) != sizeof(uint8_t)) { /* Unnatural EOF */ RARCH_ERR("[Replay] Replay ran out of frames\n"); input_st->bsv_movie_state.flags |= BSV_FLAG_MOVIE_END; return; } - else if (next_frame_type == REPLAY_TOKEN_REGULAR_FRAME) - { - /* do nothing */ - } else if (next_frame_type == REPLAY_TOKEN_CHECKPOINT_FRAME) { uint64_t size; uint8_t *st; retro_ctx_serialize_info_t serial_info; - if (intfstream_read(handle->file, &(size), sizeof(uint64_t)) != sizeof(uint64_t)) + if (intfstream_read(handle->file, &(size), + sizeof(uint64_t)) != sizeof(uint64_t)) { RARCH_ERR("[Replay] Replay ran out of frames\n"); input_st->bsv_movie_state.flags |= BSV_FLAG_MOVIE_END; @@ -6081,17 +6150,17 @@ void bsv_movie_read_next_events(bsv_movie_t *handle) } } } + void bsv_movie_next_frame(input_driver_state_t *input_st) { - settings_t *settings = config_get_ptr(); - unsigned checkpoint_interval = settings->uints.replay_checkpoint_interval; + unsigned checkpoint_interval = config_get_ptr()->uints.replay_checkpoint_interval; /* if bsv_movie_state_next_handle is not null, deinit and set bsv_movie_state_handle to bsv_movie_state_next_handle and clear next_handle */ bsv_movie_t *handle = input_st->bsv_movie_state_handle; if (input_st->bsv_movie_state_next_handle) { - if(handle) + if (handle) bsv_movie_deinit(input_st); handle = input_st->bsv_movie_state_next_handle; input_st->bsv_movie_state_handle = handle; @@ -6112,29 +6181,35 @@ void bsv_movie_next_frame(input_driver_state_t *input_st) /* write key events, frame is over */ intfstream_write(handle->file, &(handle->key_event_count), 1); for (i = 0; i < handle->key_event_count; i++) - intfstream_write(handle->file, &(handle->key_events[i]), sizeof(bsv_key_data_t)); - bsv_movie_handle_clear_key_events(handle); + intfstream_write(handle->file, &(handle->key_events[i]), + sizeof(bsv_key_data_t)); + /* Zero out key events when playing back or recording */ + handle->key_event_count = 0; /* write input events, frame is over */ intfstream_write(handle->file, &evt_count, 2); for (i = 0; i < handle->input_event_count; i++) - intfstream_write(handle->file, &(handle->input_events[i]), sizeof(bsv_input_data_t)); - bsv_movie_handle_clear_input_events(handle); + intfstream_write(handle->file, &(handle->input_events[i]), + sizeof(bsv_input_data_t)); + /* Zero out input events when playing back or recording */ + handle->input_event_count = 0; /* Maybe record checkpoint */ - if (checkpoint_interval != 0 && handle->frame_counter > 0 && (handle->frame_counter % (checkpoint_interval*60) == 0)) + if ( (checkpoint_interval != 0) + && (handle->frame_counter > 0) + && (handle->frame_counter % (checkpoint_interval*60) == 0)) { retro_ctx_serialize_info_t serial_info; uint8_t frame_tok = REPLAY_TOKEN_CHECKPOINT_FRAME; - size_t info_size = core_serialize_size(); - uint64_t size = swap_if_big64(info_size); - uint8_t *st = (uint8_t*)malloc(info_size); + size_t _len = core_serialize_size(); + uint64_t size = swap_if_big64(_len); + uint8_t *st = (uint8_t*)malloc(_len); serial_info.data = st; - serial_info.size = info_size; + serial_info.size = _len; core_serialize(&serial_info); /* "next frame is a checkpoint" */ intfstream_write(handle->file, (uint8_t *)(&frame_tok), sizeof(uint8_t)); intfstream_write(handle->file, &size, sizeof(uint64_t)); - intfstream_write(handle->file, st, info_size); + intfstream_write(handle->file, st, _len); free(st); } else @@ -6146,9 +6221,7 @@ void bsv_movie_next_frame(input_driver_state_t *input_st) } if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_PLAYBACK) - { bsv_movie_read_next_events(handle); - } handle->frame_pos[handle->frame_counter & handle->frame_mask] = intfstream_tell(handle->file); } @@ -6167,8 +6240,8 @@ bool replay_get_serialized_data(void* buffer) if (input_st->bsv_movie_state.flags & (BSV_FLAG_MOVIE_RECORDING | BSV_FLAG_MOVIE_PLAYBACK)) { - long file_end = intfstream_tell(handle->file); - long read_amt = 0; + int64_t file_end = intfstream_tell(handle->file); + int64_t read_amt = 0; long file_end_lil = swap_if_big32(file_end); uint8_t *file_end_bytes = (uint8_t *)(&file_end_lil); uint8_t *buf = buffer; @@ -6180,7 +6253,8 @@ bool replay_get_serialized_data(void* buffer) intfstream_rewind(handle->file); read_amt = intfstream_read(handle->file, (void *)buf, file_end); if (read_amt != file_end) - RARCH_ERR("[Replay] Failed to write correct number of replay bytes into state file: %d / %d\n", read_amt, file_end); + RARCH_ERR("[Replay] Failed to write correct number of replay bytes into state file: %d / %d\n", + read_amt, file_end); } return true; } @@ -6222,16 +6296,16 @@ bool replay_set_serialized_data(void* buf) } else { - int32_t loaded_len = swap_if_big32(((int32_t *)buffer)[0]); /* TODO: should factor the next few lines away, magic numbers ahoy */ - uint32_t *header = (uint32_t *)(buffer+sizeof(int32_t)); - int64_t *identifier_spot = (int64_t *)(header+4); - int64_t identifier = swap_if_big64(*identifier_spot); - int64_t handle_idx = intfstream_tell(input_st->bsv_movie_state_handle->file); - bool is_compatible = identifier == input_st->bsv_movie_state_handle->identifier; + uint32_t *header = (uint32_t *)(buffer + sizeof(int32_t)); + int64_t *ident_spot = (int64_t *)(header + 4); + int64_t ident = swap_if_big64(*ident_spot); - if (is_compatible) + if (ident == input_st->bsv_movie_state_handle->identifier) /* is compatible? */ { + int32_t loaded_len = swap_if_big32(((int32_t *)buffer)[0]); + int64_t handle_idx = intfstream_tell( + input_st->bsv_movie_state_handle->file); /* If the state is part of this replay, go back to that state and rewind/fast forward the replay. @@ -6299,11 +6373,12 @@ void input_driver_poll(void) *sec_joypad = NULL; #endif bool input_remap_binds_enable = settings->bools.input_remap_binds_enable; + float input_axis_threshold = settings->floats.input_axis_threshold; uint8_t max_users = (uint8_t)settings->uints.input_max_users; - if ( joypad && joypad->poll) + if (joypad && joypad->poll) joypad->poll(); - if ( sec_joypad && sec_joypad->poll) + if (sec_joypad && sec_joypad->poll) sec_joypad->poll(); if ( input_st->current_driver && input_st->current_driver->poll) @@ -6323,23 +6398,24 @@ void input_driver_poll(void) * when mapping analog stick to dpad input. */ for (i = 0; i < max_users; i++) { - joypad_info[i].axis_threshold = settings->floats.input_axis_threshold; - joypad_info[i].joy_idx = settings->uints.input_joypad_index[i]; - joypad_info[i].auto_binds = input_autoconf_binds[joypad_info[i].joy_idx]; + uint16_t button_id = RARCH_TURBO_ENABLE; - input_st->turbo_btns.frame_enable[i] = (*input_st->libretro_input_binds[i])[RARCH_TURBO_ENABLE].valid ? - input_state_wrap( - input_st->current_driver, - input_st->current_data, - joypad, - sec_joypad, - &joypad_info[i], + if (settings->ints.input_turbo_bind != -1) + button_id = settings->ints.input_turbo_bind; + + joypad_info[i].axis_threshold = input_axis_threshold; + joypad_info[i].joy_idx = settings->uints.input_joypad_index[i]; + joypad_info[i].auto_binds = input_autoconf_binds[joypad_info[i].joy_idx]; + + input_st->turbo_btns.frame_enable[i] = + (*input_st->libretro_input_binds[i])[button_id].valid + && settings->bools.input_turbo_enable ? + input_state_wrap(input_st->current_driver, input_st->current_data, + joypad, sec_joypad, &joypad_info[i], (*input_st->libretro_input_binds), (input_st->flags & INP_FLAG_KB_MAPPING_BLOCKED) ? true : false, (unsigned)i, - RETRO_DEVICE_JOYPAD, - 0, - RARCH_TURBO_ENABLE) : 0; + RETRO_DEVICE_JOYPAD, 0, button_id) : 0; } #ifdef HAVE_OVERLAY @@ -6480,11 +6556,8 @@ void input_driver_poll(void) input_analog_dpad_mode, input_analog_deadzone, input_analog_sensitivity, - joypad, - &joypad_info[i], - k, - j, - (*input_st->libretro_input_binds[i])); + joypad, &joypad_info[i], + k, j, (*input_st->libretro_input_binds[i])); if (val >= 0) p_new_state->analogs[offset] = val; @@ -6520,21 +6593,15 @@ void input_driver_poll(void) * 32767; } else - { - current_button_value = - BIT256_GET_PTR(p_new_state, j); - } + current_button_value = BIT256_GET_PTR(p_new_state, j); #ifdef HAVE_OVERLAY if (poll_overlay && i == 0) { - input_overlay_state_t *ol_state = - overlay_pointer - ? &overlay_pointer->overlay_state - : NULL; + input_overlay_state_t *ol_state = overlay_pointer + ? &overlay_pointer->overlay_state : NULL; if (ol_state) - current_button_value |= - BIT256_GET(ol_state->buttons, j); + current_button_value |= BIT256_GET(ol_state->buttons, j); } #endif /* Press */ @@ -6588,12 +6655,11 @@ void input_driver_poll(void) if (poll_overlay && i == 0) { input_overlay_state_t *ol_state = - overlay_pointer + overlay_pointer ? &overlay_pointer->overlay_state : NULL; if (ol_state) - current_button_value |= - BIT256_GET(ol_state->buttons, j); + current_button_value |= BIT256_GET(ol_state->buttons, j); } #endif remap_valid = @@ -6661,8 +6727,8 @@ void input_driver_poll(void) if (remap_axis_bind < sizeof(handle->analog_value[i])) { int invert = 1; - if ( (k % 2 == 0 && remap_axis % 2 != 0) || - (k % 2 != 0 && remap_axis % 2 == 0) + if ( (k % 2 == 0 && remap_axis % 2 != 0) + || (k % 2 != 0 && remap_axis % 2 == 0) ) invert = -1; @@ -6710,7 +6776,12 @@ void input_driver_poll(void) ssize_t ret; struct remote_message msg; + +#if defined(_WIN32) + if (input_st->remote->net_fd[user] == INVALID_SOCKET) +#else if (input_st->remote->net_fd[user] < 0) +#endif return; FD_ZERO(&fds); @@ -6752,10 +6823,13 @@ void input_driver_poll(void) rcheevos_pause_hardcore(); #endif k = input_st->bsv_movie_state_handle->key_events[i]; - input_keyboard_event(k.down, swap_if_big32(k.code), swap_if_big32(k.character), swap_if_big16(k.mod), RETRO_DEVICE_KEYBOARD); + input_keyboard_event(k.down, swap_if_big32(k.code), + swap_if_big32(k.character), swap_if_big16(k.mod), + RETRO_DEVICE_KEYBOARD); } /* Have to clear here so we don't double-apply key events */ - bsv_movie_handle_clear_key_events(input_st->bsv_movie_state_handle); + /* Zero out key events when playing back or recording */ + input_st->bsv_movie_state_handle->key_event_count = 0; } } #endif @@ -6775,12 +6849,7 @@ int16_t input_driver_state_wrapper(unsigned port, unsigned device, int16_t bsv_result = 0; bsv_movie_t *movie = input_st->bsv_movie_state_handle; if (bsv_movie_handle_read_input_event( - movie, - port, - device, - idx, - id, - &bsv_result)) + movie, port, device, idx, id, &bsv_result)) { #ifdef HAVE_CHEEVOS rcheevos_pause_hardcore(); @@ -6805,7 +6874,6 @@ int16_t input_driver_state_wrapper(unsigned port, unsigned device, #ifdef HAVE_BSV_MOVIE /* Save input to BSV record, if enabled */ if (BSV_MOVIE_IS_RECORDING()) - { bsv_movie_handle_push_input_event( input_st->bsv_movie_state_handle, port, @@ -6813,7 +6881,13 @@ int16_t input_driver_state_wrapper(unsigned port, unsigned device, idx, id, result); - } +#endif + +#ifdef HAVE_GAME_AI + if (settings->bools.game_ai_override_p1 && port == 0) + result |= game_ai_input(port, device, idx, id, result); + if (settings->bools.game_ai_override_p2 && port == 1) + result |= game_ai_input(port, device, idx, id, result); #endif return result; @@ -6829,10 +6903,7 @@ void *hid_driver_get_data(void) * HID driver; the memory will have already been freed, so we need to * reset the pointer. */ -void hid_driver_reset_data(void) -{ - input_driver_st.hid_data = NULL; -} +void hid_driver_reset_data(void) { input_driver_st.hid_data = NULL; } /** * config_get_hid_driver_options: @@ -6892,12 +6963,17 @@ void input_remapping_cache_global_config(void) RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE, &i)) device = settings->uints.input_libretro_device[i]; - input_st->old_analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i]; - input_st->old_libretro_device[i] = device; + input_st->remapping_cache.analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i]; + input_st->remapping_cache.libretro_device[i] = device; } - input_st->flags |= INP_FLAG_OLD_ANALOG_DPAD_MODE_SET - | INP_FLAG_OLD_LIBRETRO_DEVICE_SET; + input_st->remapping_cache.turbo_enable = settings->bools.input_turbo_enable; + input_st->remapping_cache.turbo_allow_dpad = settings->bools.input_turbo_allow_dpad; + input_st->remapping_cache.turbo_bind = settings->ints.input_turbo_bind; + input_st->remapping_cache.turbo_mode = settings->uints.input_turbo_mode; + input_st->remapping_cache.turbo_button = settings->uints.input_turbo_button; + input_st->remapping_cache.turbo_period = settings->uints.input_turbo_period; + input_st->remapping_cache.turbo_duty_cycle = settings->uints.input_turbo_duty_cycle; } void input_remapping_restore_global_config(bool clear_cache, bool restore_analog_dpad_mode) @@ -6911,27 +6987,47 @@ void input_remapping_restore_global_config(bool clear_cache, bool restore_analog for (i = 0; i < MAX_USERS; i++) { - if ( (input_st->flags & INP_FLAG_OLD_ANALOG_DPAD_MODE_SET) - && restore_analog_dpad_mode - && (settings->uints.input_analog_dpad_mode[i] != - input_st->old_analog_dpad_mode[i])) + if (restore_analog_dpad_mode) configuration_set_uint(settings, settings->uints.input_analog_dpad_mode[i], - input_st->old_analog_dpad_mode[i]); + input_st->remapping_cache.analog_dpad_mode[i]); - if ( (input_st->flags & INP_FLAG_OLD_LIBRETRO_DEVICE_SET) - && (settings->uints.input_libretro_device[i] != - input_st->old_libretro_device[i])) - configuration_set_uint(settings, - settings->uints.input_libretro_device[i], - input_st->old_libretro_device[i]); + configuration_set_uint(settings, + settings->uints.input_libretro_device[i], + input_st->remapping_cache.libretro_device[i]); } + configuration_set_bool(settings, + settings->bools.input_turbo_enable, + input_st->remapping_cache.turbo_enable); + + configuration_set_bool(settings, + settings->bools.input_turbo_allow_dpad, + input_st->remapping_cache.turbo_allow_dpad); + + configuration_set_int(settings, + settings->ints.input_turbo_bind, + input_st->remapping_cache.turbo_bind); + + configuration_set_uint(settings, + settings->uints.input_turbo_mode, + input_st->remapping_cache.turbo_mode); + + configuration_set_uint(settings, + settings->uints.input_turbo_button, + input_st->remapping_cache.turbo_button); + + configuration_set_uint(settings, + settings->uints.input_turbo_period, + input_st->remapping_cache.turbo_period); + + configuration_set_uint(settings, + settings->uints.input_turbo_duty_cycle, + input_st->remapping_cache.turbo_duty_cycle); + end: if (clear_cache) - input_st->flags &= ~(INP_FLAG_OLD_ANALOG_DPAD_MODE_SET - | INP_FLAG_OLD_LIBRETRO_DEVICE_SET - | INP_FLAG_REMAPPING_CACHE_ACTIVE); + input_st->flags &= ~INP_FLAG_REMAPPING_CACHE_ACTIVE; } void input_remapping_update_port_map(void) @@ -7040,9 +7136,8 @@ void input_remapping_set_defaults(bool clear_cache) void input_driver_collect_system_input(input_driver_state_t *input_st, settings_t *settings, input_bits_t *current_bits) { - int port; rarch_joypad_info_t joypad_info; - unsigned block_delay = settings->uints.input_hotkey_block_delay; + input_driver_t *current_input = input_st->current_driver; const input_device_driver_t *joypad = input_st->primary_joypad; #ifdef HAVE_MFI const input_device_driver_t @@ -7051,16 +7146,17 @@ void input_driver_collect_system_input(input_driver_state_t *input_st, const input_device_driver_t *sec_joypad = NULL; #endif + unsigned block_delay = settings->uints.input_hotkey_block_delay; + uint8_t max_users = settings->uints.input_max_users; + uint8_t port = 0; #ifdef HAVE_MENU + bool all_users_control_menu = settings->bools.input_all_users_control_menu; bool display_kb = menu_input_dialog_get_display_kb(); bool menu_is_alive = (menu_state_get_ptr()->flags & MENU_ST_FLAG_ALIVE) ? true : false; bool menu_input_active = menu_is_alive && !(settings->bools.menu_unified_controls && !display_kb); #endif - input_driver_t *current_input = input_st->current_driver; - unsigned max_users = settings->uints.input_max_users; - bool all_users_control_menu = settings->bools.input_all_users_control_menu; joypad_info.axis_threshold = settings->floats.input_axis_threshold; /* Gather input from each (enabled) joypad */ @@ -7068,68 +7164,46 @@ void input_driver_collect_system_input(input_driver_state_t *input_st, { const struct retro_keybind *binds_norm = &input_config_binds[port][RARCH_ENABLE_HOTKEY]; const struct retro_keybind *binds_auto = &input_autoconf_binds[port][RARCH_ENABLE_HOTKEY]; - struct retro_keybind *auto_binds = input_autoconf_binds[port]; - struct retro_keybind *general_binds = input_config_binds[port]; + joypad_info.joy_idx = settings->uints.input_joypad_index[port]; joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx]; #ifdef HAVE_MENU if (menu_is_alive) { - int k; - int s; - - /* Remember original analog D-pad binds. */ - for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++) - { - (auto_binds)[k].orig_joyaxis = (auto_binds)[k].joyaxis; - (general_binds)[k].orig_joyaxis = (general_binds)[k].joyaxis; - } + uint8_t s; + uint8_t a; /* Read input from analog sticks according to settings. */ for (s = RETRO_DEVICE_INDEX_ANALOG_LEFT; s <= RETRO_DEVICE_INDEX_ANALOG_RIGHT; s++) { - unsigned x_plus = RARCH_ANALOG_LEFT_X_PLUS; - unsigned y_plus = RARCH_ANALOG_LEFT_Y_PLUS; - unsigned x_minus = RARCH_ANALOG_LEFT_X_MINUS; - unsigned y_minus = RARCH_ANALOG_LEFT_Y_MINUS; + if ( (settings->bools.menu_disable_left_analog && s == RETRO_DEVICE_INDEX_ANALOG_LEFT) + || (settings->bools.menu_disable_right_analog && s == RETRO_DEVICE_INDEX_ANALOG_RIGHT)) + continue; - if ((settings->bools.menu_disable_left_analog && s == RETRO_DEVICE_INDEX_ANALOG_LEFT ) || - (settings->bools.menu_disable_right_analog && s == RETRO_DEVICE_INDEX_ANALOG_RIGHT)) - continue; - if (s == RETRO_DEVICE_INDEX_ANALOG_RIGHT) + for (a = RETRO_DEVICE_ID_ANALOG_X; a <= RETRO_DEVICE_ID_ANALOG_Y; a++) { - x_plus = RARCH_ANALOG_RIGHT_X_PLUS; - y_plus = RARCH_ANALOG_RIGHT_Y_PLUS; - x_minus = RARCH_ANALOG_RIGHT_X_MINUS; - y_minus = RARCH_ANALOG_RIGHT_Y_MINUS; - } + int16_t ret = input_joypad_analog_axis( + ANALOG_DPAD_NONE, + settings->floats.input_analog_deadzone, + settings->floats.input_analog_sensitivity, + joypad, + &joypad_info, + s, + a, + (*input_st->libretro_input_binds[port])); - if (!INHERIT_JOYAXIS(auto_binds)) - { - unsigned j = x_plus + 3; - /* Inherit joyaxis from analogs. */ - for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++) + if (ret) { - if ((auto_binds)[j].joyaxis != AXIS_NONE && - ((float)abs(joypad->axis(port, (uint32_t)(auto_binds)[j].joyaxis)) - / 0x8000) > joypad_info.axis_threshold) - (auto_binds)[k].joyaxis = (auto_binds)[j].joyaxis; - j--; - } - } + if (a == RETRO_DEVICE_ID_ANALOG_Y && (float)ret / 0x7fff < -joypad_info.axis_threshold) + BIT256_SET_PTR(current_bits, RETRO_DEVICE_ID_JOYPAD_UP); + else if (a == RETRO_DEVICE_ID_ANALOG_Y && (float)ret / 0x7fff > joypad_info.axis_threshold) + BIT256_SET_PTR(current_bits, RETRO_DEVICE_ID_JOYPAD_DOWN); - if (!INHERIT_JOYAXIS(general_binds)) - { - unsigned j = x_plus + 3; - /* Inherit joyaxis from analogs. */ - for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++) - { - if ((general_binds)[j].joyaxis != AXIS_NONE && - ((float)abs(joypad->axis(port, (uint32_t)(general_binds)[j].joyaxis)) - / 0x8000) > joypad_info.axis_threshold) - (general_binds)[k].joyaxis = (general_binds)[j].joyaxis; - j--; + if (a == RETRO_DEVICE_ID_ANALOG_X && (float)ret / 0x7fff < -joypad_info.axis_threshold) + BIT256_SET_PTR(current_bits, RETRO_DEVICE_ID_JOYPAD_LEFT); + else if (a == RETRO_DEVICE_ID_ANALOG_X && (float)ret / 0x7fff > joypad_info.axis_threshold) + BIT256_SET_PTR(current_bits, RETRO_DEVICE_ID_JOYPAD_RIGHT); } } } @@ -7150,20 +7224,11 @@ void input_driver_collect_system_input(input_driver_state_t *input_st, joypad, sec_joypad, &joypad_info, - settings); + settings->bools.input_hotkey_device_merge); #ifdef HAVE_MENU if (menu_is_alive) { - int k; - - /* Restore analog D-pad binds temporarily overridden. */ - for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++) - { - (auto_binds)[k].joyaxis = (auto_binds)[k].orig_joyaxis; - (general_binds)[k].joyaxis = (general_binds)[k].orig_joyaxis; - } - if (!all_users_control_menu) break; } @@ -7374,20 +7439,20 @@ static const char *accessibility_lut_name(char key) void input_keyboard_event(bool down, unsigned code, uint32_t character, uint16_t mod, unsigned device) { - runloop_state_t *runloop_st = runloop_state_get_ptr(); + runloop_state_t *runloop_st = runloop_state_get_ptr(); retro_keyboard_event_t - *key_event = &runloop_st->key_event; + *key_event = &runloop_st->key_event; input_driver_state_t - *input_st = &input_driver_st; + *input_st = &input_driver_st; #ifdef HAVE_ACCESSIBILITY - access_state_t *access_st = access_state_get_ptr(); - settings_t *settings = config_get_ptr(); - bool accessibility_enable = settings->bools.accessibility_enable; + access_state_t *access_st = access_state_get_ptr(); + settings_t *settings = config_get_ptr(); + bool accessibility_enable = settings->bools.accessibility_enable; unsigned accessibility_narrator_speech_speed - = settings->uints.accessibility_narrator_speech_speed; + = settings->uints.accessibility_narrator_speech_speed; #endif #ifdef HAVE_MENU - struct menu_state *menu_st = menu_state_get_ptr(); + struct menu_state *menu_st = menu_state_get_ptr(); /* If screensaver is active, then it should be * disabled if: @@ -7410,20 +7475,20 @@ void input_keyboard_event(bool down, unsigned code, { if ( (down) && (code != RETROK_UNKNOWN) - && (menu_input_dialog_get_display_kb() || - !((code == RETROK_SPACE) || /* RETRO_DEVICE_ID_JOYPAD_START */ - (code == RETROK_SLASH) || /* RETRO_DEVICE_ID_JOYPAD_X */ - (code == RETROK_RSHIFT) || /* RETRO_DEVICE_ID_JOYPAD_SELECT */ - (code == RETROK_RIGHT) || /* RETRO_DEVICE_ID_JOYPAD_RIGHT */ - (code == RETROK_LEFT) || /* RETRO_DEVICE_ID_JOYPAD_LEFT */ - (code == RETROK_DOWN) || /* RETRO_DEVICE_ID_JOYPAD_DOWN */ - (code == RETROK_UP) || /* RETRO_DEVICE_ID_JOYPAD_UP */ - (code == RETROK_PAGEUP) || /* RETRO_DEVICE_ID_JOYPAD_L */ - (code == RETROK_PAGEDOWN) || /* RETRO_DEVICE_ID_JOYPAD_R */ - (code == RETROK_BACKSPACE)|| /* RETRO_DEVICE_ID_JOYPAD_B */ - (code == RETROK_RETURN) || /* RETRO_DEVICE_ID_JOYPAD_A */ - (code == RETROK_DELETE) || /* RETRO_DEVICE_ID_JOYPAD_Y */ - BIT512_GET(input_st->keyboard_mapping_bits, code)))) + && (menu_input_dialog_get_display_kb() + || !((code == RETROK_SPACE) /* RETRO_DEVICE_ID_JOYPAD_START */ + || (code == RETROK_SLASH) /* RETRO_DEVICE_ID_JOYPAD_X */ + || (code == RETROK_RSHIFT) /* RETRO_DEVICE_ID_JOYPAD_SELECT */ + || (code == RETROK_RIGHT) /* RETRO_DEVICE_ID_JOYPAD_RIGHT */ + || (code == RETROK_LEFT) /* RETRO_DEVICE_ID_JOYPAD_LEFT */ + || (code == RETROK_DOWN) /* RETRO_DEVICE_ID_JOYPAD_DOWN */ + || (code == RETROK_UP) /* RETRO_DEVICE_ID_JOYPAD_UP */ + || (code == RETROK_PAGEUP) /* RETRO_DEVICE_ID_JOYPAD_L */ + || (code == RETROK_PAGEDOWN) /* RETRO_DEVICE_ID_JOYPAD_R */ + || (code == RETROK_BACKSPACE) /* RETRO_DEVICE_ID_JOYPAD_B */ + || (code == RETROK_RETURN) /* RETRO_DEVICE_ID_JOYPAD_A */ + || (code == RETROK_DELETE) /* RETRO_DEVICE_ID_JOYPAD_Y */ + || (BIT512_GET(input_st->keyboard_mapping_bits, code))))) { struct menu_state *menu_st = menu_state_get_ptr(); menu_st->flags &= ~MENU_ST_FLAG_SCREENSAVER_ACTIVE; @@ -7439,9 +7504,9 @@ void input_keyboard_event(bool down, unsigned code, menu_st->input_last_time_us = menu_st->current_time_us; #ifdef HAVE_ACCESSIBILITY - if (menu_input_dialog_get_display_kb() - && down && is_accessibility_enabled( - accessibility_enable, + if ( menu_input_dialog_get_display_kb() + && down + && is_accessibility_enabled(accessibility_enable, access_st->enabled)) { if (code != 303 && code != 0) @@ -7455,10 +7520,8 @@ void input_keyboard_event(bool down, unsigned code, say_char[1] = '\0'; if (character == 127 || character == 8) - accessibility_speak_priority( - accessibility_enable, - accessibility_narrator_speech_speed, - "backspace", 10); + accessibility_speak_priority(accessibility_enable, + accessibility_narrator_speech_speed, "backspace", 10); else { const char *lut_name = accessibility_lut_name(c); @@ -7511,7 +7574,7 @@ void input_keyboard_event(bool down, unsigned code, input_keyboard_line_free(input_st); /* Unblock all hotkeys. */ - input_st->flags &= ~INP_FLAG_KB_MAPPING_BLOCKED; + input_st->flags &= ~INP_FLAG_KB_MAPPING_BLOCKED; } else { @@ -7532,9 +7595,9 @@ void input_keyboard_event(bool down, unsigned code, && BIT512_GET(input_st->keyboard_mapping_bits, code) && device != RETRO_DEVICE_POINTER) { + unsigned j; settings_t *settings = config_get_ptr(); unsigned max_users = settings->uints.input_max_users; - unsigned j; bool hotkey_pressed = (input_st->input_hotkey_block_counter > 0); bool block_key_event = false; @@ -7548,9 +7611,9 @@ void input_keyboard_event(bool down, unsigned code, * and only when modifier is a keyboard key. */ if ( j == 0 && !block_key_event - && !( !hotkey_pressed - && hotkey_code != RETROK_UNKNOWN - && hotkey_code != code)) + && !( !hotkey_pressed + && hotkey_code != RETROK_UNKNOWN + && hotkey_code != code)) { for (k = RARCH_FIRST_META_KEY; k < RARCH_BIND_LIST_END; k++) { @@ -7562,7 +7625,8 @@ void input_keyboard_event(bool down, unsigned code, } } - /* RetroPad blocking needed only when emulated device type is active. */ + /* RetroPad blocking needed only when emulated + * device type is active. */ if ( input_config_get_device(j) && !block_key_event) { @@ -7592,9 +7656,9 @@ void input_keyboard_event(bool down, unsigned code, #ifdef HAVE_BSV_MOVIE /* Save input to BSV record, if recording */ if (BSV_MOVIE_IS_RECORDING()) - { - bsv_movie_handle_push_key_event(input_st->bsv_movie_state_handle, down, mod, code, character); - } + bsv_movie_handle_push_key_event( + input_st->bsv_movie_state_handle, down, mod, + code, character); #endif } (*key_event)(down, code, character, mod); diff --git a/input/input_driver.h b/input/input_driver.h index 09174b9219..8835a96505 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -32,6 +32,10 @@ #include "../config.h" #endif /* HAVE_CONFIG_H */ +#if defined(_WIN32) && !defined(SOCKET) +#include +#endif + #include "input_defines.h" #include "input_types.h" #ifdef HAVE_OVERLAY @@ -100,8 +104,6 @@ #define MAPPER_SET_KEY(state, key) (state)->keys[(key) / 32] |= 1 << ((key) % 32) #define MAPPER_UNSET_KEY(state, key) (state)->keys[(key) / 32] &= ~(1 << ((key) % 32)) -#define INHERIT_JOYAXIS(binds) (((binds)[x_plus].joyaxis == (binds)[x_minus].joyaxis) || ( (binds)[y_plus].joyaxis == (binds)[y_minus].joyaxis)) - #define REPLAY_TOKEN_INVALID '\0' #define REPLAY_TOKEN_REGULAR_FRAME 'f' #define REPLAY_TOKEN_CHECKPOINT_FRAME 'c' @@ -153,11 +155,9 @@ enum input_driver_state_flags INP_FLAG_BLOCK_LIBRETRO_INPUT = (1 << 4), INP_FLAG_BLOCK_POINTER_INPUT = (1 << 5), INP_FLAG_GRAB_MOUSE_STATE = (1 << 6), - INP_FLAG_OLD_ANALOG_DPAD_MODE_SET = (1 << 7), - INP_FLAG_OLD_LIBRETRO_DEVICE_SET = (1 << 8), - INP_FLAG_REMAPPING_CACHE_ACTIVE = (1 << 9), - INP_FLAG_DEFERRED_WAIT_KEYS = (1 << 10), - INP_FLAG_WAIT_INPUT_RELEASE = (1 << 11) + INP_FLAG_REMAPPING_CACHE_ACTIVE = (1 << 7), + INP_FLAG_DEFERRED_WAIT_KEYS = (1 << 8), + INP_FLAG_WAIT_INPUT_RELEASE = (1 << 9) }; #ifdef HAVE_BSV_MOVIE @@ -288,7 +288,11 @@ struct remote_message struct input_remote { #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD) +#ifdef _WIN32 + SOCKET net_fd[MAX_USERS]; +#else int net_fd[MAX_USERS]; +#endif #endif bool state[RARCH_BIND_LIST_END]; }; @@ -556,10 +560,9 @@ typedef struct turbo_buttons_t turbo_btns; /* int32_t alignment */ input_mapper_t mapper; /* uint32_t alignment */ + input_remap_cache_t remapping_cache; input_device_info_t input_device_info[MAX_INPUT_DEVICES]; /* unsigned alignment */ input_mouse_info_t input_mouse_info[MAX_INPUT_DEVICES]; - unsigned old_analog_dpad_mode[MAX_USERS]; - unsigned old_libretro_device[MAX_USERS]; unsigned osk_last_codepoint; unsigned osk_last_codepoint_len; unsigned input_hotkey_block_counter; diff --git a/input/input_keymaps.c b/input/input_keymaps.c index 1a71d2edf0..5afaab5ad9 100644 --- a/input/input_keymaps.c +++ b/input/input_keymaps.c @@ -221,7 +221,7 @@ const struct input_key_map input_config_key_map[] = { { "media", RETROK_LAUNCH_MEDIA }, { "app1", RETROK_LAUNCH_APP1 }, { "app2", RETROK_LAUNCH_APP2 }, - + { "nul", RETROK_UNKNOWN }, { NULL, RETROK_UNKNOWN }, }; @@ -1189,7 +1189,7 @@ const struct rarch_key_map rarch_key_map_x11[] = { { XFVK_KP0, RETROK_KP0 }, { XFVK_KPDL, RETROK_KP_PERIOD }, { XFVK_KPEQ, RETROK_KP_EQUALS }, - + { XFVK_MUTE, RETROK_VOLUME_MUTE }, { XFVK_VOUP, RETROK_VOLUME_UP }, { XFVK_VODN, RETROK_VOLUME_DOWN }, @@ -1914,7 +1914,7 @@ const struct rarch_key_map rarch_key_map_ps3[] = { { KB_RAWKEY_SCROLL_LOCK, RETROK_SCROLLOCK }, { KB_RAWKEY_PAUSE, RETROK_BREAK }, - /* + /* { KB_RAWKEY_HASHTILDE, RETROK_HASH }, { KB_RAWKEY_KPLEFTPAREN, RETROK_LEFTPAREN }, { KB_RAWKEY_KPRIGHTPAREN, RETROK_RIGHTPAREN }, @@ -2091,12 +2091,6 @@ enum retro_key rarch_keysym_lut[RETROK_LAST]; static unsigned *rarch_keysym_rlut = NULL; static unsigned rarch_keysym_rlut_size = 0; -/** - * input_keymaps_init_keyboard_lut: - * @map : Keyboard map. - * - * Initializes and sets the keyboard layout to a keyboard map (@map). - **/ void input_keymaps_init_keyboard_lut(const struct rarch_key_map *map) { const struct rarch_key_map *map_start = map; @@ -2124,15 +2118,6 @@ void input_keymaps_init_keyboard_lut(const struct rarch_key_map *map) rarch_keysym_rlut_size = 0; } -/** - * input_keymaps_translate_keysym_to_rk: - * @sym : Key symbol. - * - * Translates a key symbol from the keyboard layout table - * to an associated retro key identifier. - * - * Returns: Retro key identifier. - **/ enum retro_key input_keymaps_translate_keysym_to_rk(unsigned sym) { unsigned i; @@ -2153,25 +2138,16 @@ enum retro_key input_keymaps_translate_keysym_to_rk(unsigned sym) return RETROK_UNKNOWN; } -/** - * input_keymaps_translate_rk_to_str: - * @key : Retro key identifier. - * @buf : Buffer. - * @size : Size of @buf. - * - * Translates a retro key identifier to a human-readable - * identifier string. - **/ -void input_keymaps_translate_rk_to_str(enum retro_key key, char *buf, size_t size) +void input_keymaps_translate_rk_to_str(enum retro_key key, char *s, size_t len) { unsigned i; - *buf = '\0'; + *s = '\0'; if (key >= RETROK_a && key <= RETROK_z) { - buf[0] = (key - RETROK_a) + 'a'; - buf[1] = '\0'; + s[0] = (key - RETROK_a) + 'a'; + s[1] = '\0'; return; } @@ -2180,7 +2156,7 @@ void input_keymaps_translate_rk_to_str(enum retro_key key, char *buf, size_t siz if (input_config_key_map[i].key != key) continue; - strlcpy(buf, input_config_key_map[i].str, size); + strlcpy(s, input_config_key_map[i].str, len); break; } } diff --git a/input/input_keymaps.h b/input/input_keymaps.h index 2ffee2b67f..fecbe00abd 100644 --- a/input/input_keymaps.h +++ b/input/input_keymaps.h @@ -223,13 +223,13 @@ enum retro_key input_keymaps_translate_keysym_to_rk(unsigned sym); /** * input_keymaps_translate_rk_to_str: * @key : Retro key identifier. - * @buf : Buffer. - * @size : Size of @buf. + * @s : Buffer. + * @len : Size of @s. * * Translates a retro key identifier to a human-readable * identifier string. **/ -void input_keymaps_translate_rk_to_str(enum retro_key key, char *buf, size_t size); +void input_keymaps_translate_rk_to_str(enum retro_key key, char *s, size_t len); /** * input_translate_rk_to_ascii: diff --git a/input/input_osk.h b/input/input_osk.h index 8c1f9d607e..a7733bd966 100644 --- a/input/input_osk.h +++ b/input/input_osk.h @@ -56,7 +56,7 @@ void input_event_osk_append( int ptr, bool show_symbol_pages, const char *word, - size_t word_len); + size_t len); void osk_update_last_codepoint( unsigned *last_codepoint, diff --git a/input/input_types.h b/input/input_types.h index 301d6d6842..b5b97ccb4d 100644 --- a/input/input_types.h +++ b/input/input_types.h @@ -75,8 +75,6 @@ struct retro_keybind uint32_t joyaxis; /* Default joy axis binding value for resetting bind to default. */ uint32_t def_joyaxis; - /* Used by input_{push,pop}_analog_dpad(). */ - uint32_t orig_joyaxis; enum msg_hash_enums enum_idx; @@ -114,6 +112,19 @@ typedef struct input_mapper input_bits_t buttons[MAX_USERS]; } input_mapper_t; +typedef struct +{ + unsigned analog_dpad_mode[MAX_USERS]; + unsigned libretro_device[MAX_USERS]; + unsigned turbo_mode; + unsigned turbo_button; + unsigned turbo_period; + unsigned turbo_duty_cycle; + int turbo_bind; + bool turbo_enable; + bool turbo_allow_dpad; +} input_remap_cache_t; + typedef struct input_game_focus_state { bool enabled; diff --git a/intl/msg_hash_ar.h b/intl/msg_hash_ar.h index 0cf9004c90..56b5c1c85d 100644 --- a/intl/msg_hash_ar.h +++ b/intl/msg_hash_ar.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "حدد النواة المستخدمة." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "إيقاف تشغيل النواة" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "إلغاء تحميل النواة." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "تصفح لتنفيذ أساسيات ليبرترو. حيث يبدأ المتصفح يعتمد على مسار الدليل الأساسي الخاص بك. إذا كان فارغاً، فسيبدأ في الجذر.\nإذا كان الدليل الأساسي هو الدليل، فستستخدم القائمة ذلك كالمجلد الأعلى. إذا كان الدليل الأساسي هو المسار الكامل، فإنه سيبدأ في المجلد الذي يوجد فيه الملف." @@ -523,6 +531,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SERIALIZED, "متسلسل (حفظ/تحميل, إعادة)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DETERMINISTIC, + "سلوك الأداء (الحفظ، الرجوع، التشغيل المسبق، اللعب الجماعي)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, "البرنامج الثابت فيرموير" @@ -531,6 +543,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_IN_CONTENT_DIRECTORY, "- ملاحظة: تم تمكين 'ملفات النظام في دليل المحتوى' حاليا." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_PATH, + "البحث في: %s" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MISSING_REQUIRED, "مفقود، مطلوب:" @@ -559,6 +575,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_SET_STANDALONE_EXEMPT, "استبعاد من قائمة 'نوى بلا محتوى'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_SET_STANDALONE_EXEMPT, + "لا تُعرض هذه النواة في تبويب \"النوى غير المرتبطة\"، ويظهر ذلك فقط عند تفعيل وضع العرض المخصص." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_DELETE, "حذف النواة" @@ -634,6 +654,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CPU_CORES, "نَوَيات المُعالِجْ" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_JIT_AVAILABLE, + "يدعم الترجمة الفورية JIT" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER, "واجهة Identifier" @@ -714,6 +738,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "SDL 1-2 دعم" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "دعم Direct3D 8" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "دعم Direct3D 9" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "دعم Direct3D 10" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "دعم Direct3D 11" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "دعم Direct3D 12" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "دعم GDI" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "دعم vulkan" @@ -794,6 +842,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "دعم PulseAudio" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "دعم PipeWire" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "دعم CoreAudio" @@ -874,6 +926,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "دعم Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "دعم SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "دعم libusb" @@ -916,6 +972,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_REGION, "المنطقة" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CONSOLE_EXCLUSIVE, + "حصري على جهاز الألعاب" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PLATFORM_EXCLUSIVE, + "حصري على المنصة" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SCORE, "النقاط" @@ -928,6 +992,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CONTROLS, "التحكم" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ARTSTYLE, + "النمط الفني" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GAMEPLAY, "أسلوب اللعب" @@ -936,6 +1004,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NARRATIVE, "سرد" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PACING, + "نمط الإيقاع" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PERSPECTIVE, "وجهة نظر" @@ -948,6 +1020,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_VISUAL, "بصري" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_VEHICULAR, + "نمط المركبات" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, "الناشر" @@ -984,6 +1060,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, "مراجعة مجلة edg" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, + "شهر الإصدار" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, + "سنة الإصدار" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, "تصنيف BBFC" @@ -1027,18 +1111,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, "تحميل ملف التكوين" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIGURATIONS, + "تحميل الإعدادات الحالية واستبدال القيم الموجودة" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, "قراءة إعدادات التكوين الحالية" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG, + "استبدال ملف الإعدادات الحالي" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, "حفظ الإعدادات" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_NEW_CONFIG, + "حفظ الإعدادات الحالية في ملف منفصل" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESET_TO_DEFAULT_CONFIG, "إعادة التعيين إلى الافتراضي" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESET_TO_DEFAULT_CONFIG, + "إعادة الإعدادات للوضع الافتراضي." + ) /* Main Menu > Help */ @@ -1104,6 +1204,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, "الصوت" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, + "تعديل إعدادات الصوت والإدخال/الإخراج." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, "أجهزة الادخال" @@ -1144,14 +1248,94 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SAVING_SETTINGS, "تغيير اعدادات النواة." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SETTINGS, + "مزامنة سحابية" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SETTINGS, + "تغيير إعدادات المزامنة السحابية." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_ENABLE, + "تفعيل المزامنة السحابية" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_ENABLE, + "محاولة مزامنة الإعدادات، والبيانات المحفوظة، ولقطات الحفظ مع التخزين السحابي." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DESTRUCTIVE, + "مزامنة سحابية تمسح القديم" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_SAVES, + "مزامنة الحفظ والتقدم" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_CONFIGS, + "مزامنة ملفات الإعدادات" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_THUMBS, + "مزامنة الصور المصغّرة للألعاب" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_SYSTEM, + "مزامنة ملفات النظام" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_SAVES, + "عند التفعيل، سيتم مزامنة بيانات الحفظ والحالة مع السحابة." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_CONFIGS, + "عند التفعيل، سيتم مزامنة ملفات الإعدادات مع السحابة." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_THUMBS, + "عند التفعيل، سيتم مزامنة الصور المصغّرة مع السحابة. لا يُنصح بها عادةً إلا عند وجود مجموعة كبيرة من الصور المخصصة. في الحالات الأخرى يُفضّل استخدام أداة تحميل الصور المصغّرة." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_SYSTEM, + "عند التفعيل، تتم مزامنة ملفات النظام للسحابة. قد تؤثر على سرعة المزامنة." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_DESTRUCTIVE, + "إذا تم التعطيل، سيتم نقل الملفات إلى مجلد النسخ الاحتياطي قبل الحذف أو الاستبدال." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DRIVER, + "خدمة المزامنة السحابية" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_DRIVER, + "اختيار خدمة التخزين السحابي." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_URL, + "عنوان موقع التخزين السحابي" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_URL, + "رابط خدمة التخزين السحابي." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_USERNAME, "اسم المستخدم" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_USERNAME, + "اسم المستخدم في السحابة." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_PASSWORD, "كلمة المرور" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_PASSWORD, + "كلمة المرور لحساب السحابة." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, "تسجيل الدخول" @@ -1164,6 +1348,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, "مستعرض الملفات" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, + "تعديل إعدادات مستعرض الملفات.مستعرض الملفات" + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CONFIG, + "ملف الإعدادات." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_COMPRESSED_ARCHIVE, + "ملف أرشيف مضغوط." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_RECORD_CONFIG, + "ملف إعدادات التسجيل." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CURSOR, + "ملف مؤشر قاعدة البيانات." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_FILE_CONFIG, "ملف الإعدادات." @@ -1176,10 +1380,26 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_FILE_BROWSER_SHADER, "مِلف المظلل." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_REMAP, + "ملف تخصيص أزرار التحكم." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_FILE_BROWSER_CHEAT, "ملف الغش." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_OVERLAY, + "ملف التراكب." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_RDB, + "ملف قاعدة البيانات." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_FONT, + "ملف خط TrueType." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_FILE_BROWSER_PLAIN_FILE, "ملف عادي." @@ -1200,6 +1420,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_FILE_BROWSER_IMAGE_OPEN_WITH_VIEWER, "صورة. حدده لفتح هذا الملف مع عارض الصورة." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CORE_SELECT_FROM_COLLECTION, + "نواة ليبرترو. اختيار هذا سيربط هذا النواة باللعبة." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, "خنق الإطار" @@ -1467,6 +1691,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_DRIVER, "نظام تشغيل القائمة" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_DRIVER, + "نوع الواجهة الرئيسية. (يتطلب إعادة التشغيل)" + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_MENU_DRIVER_XMB, + "واجهة XMB مستوحاة من قوائم أجهزة الجيل السابع مثل PS3، وتقدم ميزات مشابهة لـ Ozone." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_MENU_DRIVER_OZONE, + "واجهة Ozone هي الواجهة الرئيسية الافتراضية في RetroArch، ومصممة خصيصًا لتسهيل التنقل بيد التحكم." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_MENU_DRIVER_RGUI, + "واجهة RGUI هي واجهة مدمجة وبسيطة في RetroArch. تُعد الأقل من حيث متطلبات الأداء بين جميع مشغّلات القوائم، ويمكن استخدامها على الشاشات منخفضة الدقة." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_MENU_DRIVER_MATERIALUI, + "في الأجهزة المحمولة، يستخدم RetroArch واجهة المستخدم الخاصة بالموبايل بشكل افتراضي، والمعروفة باسم MaterialUI. تم تصميم هذه الواجهة خصيصًا لتناسب أجهزة اللمس والمؤشرات مثل الماوس أو التراكبول." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, "نظام تشغيل التسجيل" @@ -1554,10 +1798,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_THREADED, "يحسن الأداء على حساب التأخير والمزيد من مقاطع الفيديو. يستخدم فقط إذا لم يكن من الممكن الحصول على السرعة الكاملة خلاف ذلك." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_THREADED, + "تمكين المعالجة المتعددة للفيديو قد يرفع الأداء، لكن فيه احتمال يصير فيه تأخير أو تقطيع بسيط." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, "إدراج الإطار الأسود" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, + "تحذير: الوميض السريع قد يسبب أثرًا دائمًا على بعض الشاشات. استخدم هذا الخيار على مسؤوليتك. إدراج إطار أسود بين الفريمات يقلل بشكل كبير من ضبابية الحركة ويحاكي عرض CRT، لكن يقلل من سطوع الشاشة." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, "لقطة شاشة GPU" @@ -2004,10 +2256,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "كتم صوت المزيج." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "كتم الصوت عند إعادة التوجيه السريع" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "كتم الصوت تلقائياً عند استخدام السرعة إلى الأمام." @@ -2317,26 +2565,19 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, "مقدار الثواني للاحتفاظ بمدخلات لربطها." ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "وضع توربو" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "فترة Turbo" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "دورة واجبات توربو" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "وضع توربو" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "زر توربو الافتراضي" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "الزر الافتراضي النشط لوضع توربو 'زر واحد'." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "وضع توربو" @@ -2422,10 +2663,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, "تبديل القائمة" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "تبديل العرض الحالي بين القائمة ومحتوى التشغيل." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, "خروج" @@ -2478,10 +2715,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, "إرجاع" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "قم بتبديل المحتوى قيد التشغيل بين حالات الإيقاف المؤقت والوضع غير المؤقت." - ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MUTE, @@ -2803,10 +3036,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, "تناظري الأيمن Y-(أعلى)" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "فائق السرعة" - ) /* Settings > Latency */ @@ -3093,13 +3322,17 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "تصفية ملحقات غير معروفة" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "تصفية حسب النواة الحالية" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, "استخدام مشغل الوسائط المدمج" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, - "تصفية حسب النواة الحالية" + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "استخدام عارض الصور المدمج" ) /* Settings > Frame Throttle */ @@ -3537,10 +3770,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "حجم الإشعارات" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "حدد حجم الخط في النقاط." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, "موضع الإشعار (هوريزونتالي)" @@ -4300,7 +4529,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "مستعرض الملفات" + "مجلد البداية" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, @@ -4719,10 +4948,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "استئناف" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "استأنف المحتوى قيد التشغيل حاليا و اترك القائمة السريعة." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, "إعادة التشغيل" @@ -4795,18 +5020,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "الخيارات الأساسية" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "تغيير الإعدادات للمحتوى النشط حاليا." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "التحكم" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "تغيير الإعدادات للمحتوى النشط حاليا." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "شفرات الغش" @@ -6506,6 +6723,23 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_COLLAPSE_SIDEBAR, "اجعل الشريط الجانبي الأيسر مطويًا دائمًا." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "الصورة المصغرة الثانوية" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "استخدام نص المؤشر للبيانات الوصفية للمحتوى" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "عند التمكين، كل عنصر من عناصر بيانات التعريف الخاصة بالمحتوى تظهر على الشريط الجانبي الأيمن لقوائم التشغيل (النواة المرتبطة بها، وقت التشغيل) سيشغل سطراً واحداً؛ المقاطع التي تتجاوز عرض الشريط الجانبي سيتم عرضها كنص شريط تمرير. عند التعطيل، سيتم عرض كل عنصر من بيانات التعر[...]" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "عامل المقياس المصغرة" + ) + MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, "حدد سمة لون مختلفة." @@ -6538,22 +6772,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_LIGHT, "النور المشمس" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "الصورة المصغرة الثانوية" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "استخدام نص المؤشر للبيانات الوصفية للمحتوى" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "عند التمكين، كل عنصر من عناصر بيانات التعريف الخاصة بالمحتوى تظهر على الشريط الجانبي الأيمن لقوائم التشغيل (النواة المرتبطة بها، وقت التشغيل) سيشغل سطراً واحداً؛ المقاطع التي تتجاوز عرض الشريط الجانبي سيتم عرضها كنص شريط تمرير. عند التعطيل، سيتم عرض كل عنصر من بيانات التعر[...]" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "عامل المقياس المصغرة" - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -7454,10 +7673,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "المستخدم" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "استخدام عارض الصور المدمج" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "يلغي مشغل الفيديو أن يستخدم صراحة وضع التخزين المؤقت المحدد." @@ -7561,14 +7776,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "حدد من قائمة التشغيل" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "استئناف" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "استأنف المحتوى قيد التشغيل حاليا و اترك القائمة السريعة." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "عرض قائمة %u مباريات" @@ -8023,10 +8230,6 @@ MSG_HASH( MSG_AUTODETECT, "الكشف التلقائي" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "التحميل التلقائي للحالة من" - ) MSG_HASH( MSG_CAPABILITIES, "القدرات" @@ -8883,6 +9086,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "فشل حساب حجم العرض! سوف يستمر في استخدام البيانات الخام. ربما لن يعمل هذا بشكل صحيح..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "التحميل التلقائي للحالة من" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "فشل التحميل التلقائي لحالة الحفظ من \"%s\"." @@ -9653,10 +9860,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "تمكين الخط" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "عرض خط القائمة السفلية. تمكين عرض أوصاف الأزرار في أسفل الشاشة. يستبعد هذا تاريخ الحفظ." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "لون الخط أحمر" @@ -9712,3 +9915,10 @@ MSG_HASH( MSG_IOS_TOUCH_MOUSE_DISABLED, "الماوس الفأرة معطل" ) +#ifdef HAVE_GAME_AI + + + + + +#endif diff --git a/intl/msg_hash_ast.h b/intl/msg_hash_ast.h index 4ef4f546f3..0483850f19 100644 --- a/intl/msg_hash_ast.h +++ b/intl/msg_hash_ast.h @@ -109,6 +109,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, "Crea y anueva llistes pente la busca de conteníu." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + "Amosar el menú pa escritorios" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_WIMP, + "Abre'l menú tradicional pa escritorios." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_DISABLE_KIOSK_MODE, + "Amuesa toles opciones de configuración rellacionaes." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, "Anovador" @@ -534,6 +546,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "Compatibilidá con SDL 2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Compatibilidá con Direct3D 8" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Compatibilidá con Direct3D 9" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Compatibilidá con Direct3D 10" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Compatibilidá con Direct3D 11" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Compatibilidá con Direct3D 12" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Compatibilidá con Vulkan" @@ -678,6 +710,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Compatibilidá con Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Compatibilidá con SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Compatibilidá con libusb" @@ -1251,7 +1287,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, - "Ayuda a amenorgar les imperfeiciones na sincronización del audiu y videu. Ten curiáu si esta opción ta desactivada, la sincronización afayadiza ye cuasi imposible de consiguir." + "Ayuda a amenorgar les imperfeiciones na sincronización del audiu y videu. Ten curiáu si esta opción ta desactivada, la sincronización correuta ye cuasi imposible de consiguir." ) /* Settings > Audio > MIDI */ @@ -1357,6 +1393,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PAUSE_ON_DISCONNECT, "Posar el conteníu cuando'l mandu se desconecte" ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, "Atayos" @@ -1479,10 +1516,22 @@ MSG_HASH( /* Settings > Core */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DRIVER_SWITCH_ENABLE, + "Permitir que los nucleos cambien el controlador de videu" + ) MSG_HASH( MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, "Dalgunos nucleos tienen una función d'apagáu, la carga d'un nucleu maniquín impide que RetroArch cole." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, + "Comprobar el firmware que falte enantes de cargar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CACHE_ENABLE, + "Atroxar na cache los ficheros d'información de los núcleos" + ) #ifndef HAVE_DYNAMIC #endif MSG_HASH( @@ -1512,6 +1561,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, "Guardar la configuración al colar" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, + "Cargar automáticamente los ficheros d'anulación" + ) /* Settings > Saving */ @@ -1545,6 +1598,10 @@ MSG_HASH( /* Settings > File Browser */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Usar el visor d'imáxenes integráu" + ) /* Settings > Frame Throttle */ @@ -1964,6 +2021,14 @@ MSG_HASH( /* Settings > AI Service */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AI_SERVICE_MODE, + "Salida del serviciu d'IA" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AI_SERVICE_URL, + "URL del serviciu d'IA" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_SOURCE_LANG, "Llingua d'orixe" @@ -2187,7 +2252,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, - "Xestiona les cuentes configuraes anguaño." + "Xestiona les cuentes que tán configuraes." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, @@ -2210,7 +2275,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_DISCORD_ALLOW, - "Permite que l'aplicación Discord amuese datos tocante al conteníu que ta en reproducción.\nEsta función namás ta disponible pal veceru nativu pa ordenadores." + "Permite que l'aplicación Discord amuese datos tocante al conteníu que ta en reproducción.\nEsta función namás ta disponible pal veceru nativu d'ordenador." ) /* Settings > User > Accounts */ @@ -2284,7 +2349,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Restolador de ficheros" + "Direutoriu inicial" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, @@ -2575,10 +2640,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "Siguir" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Sigue col conteníu n'execución y cola del menú rápidu." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, "Zarrar el conteníu" @@ -2669,7 +2730,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_STRENGTH, - "Fuercia del vibrador primariu" + "Intensidá del vibrador primariu" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_DURATION, @@ -2677,7 +2738,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_STRENGTH, - "Fuercia del vibrador secundariu" + "Intensidá del vibrador secundariu" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_DURATION, @@ -2802,7 +2863,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_ITEMS, - "Nun hai elementos" + "Nun hai nengún elementu" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MORE, @@ -2887,6 +2948,10 @@ MSG_HASH( MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_EMU, "Emulador" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, + "Carátula" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ON, "Sí" @@ -3210,6 +3275,11 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Miniatura secundaria" + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_WHITE, "Blancu básico" @@ -3230,10 +3300,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, "Seleniu" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Miniatura secundaria" - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -3411,6 +3478,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER, "Restolador de conteníu" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_BOXART, + "Carátula" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, "Toles llistes" @@ -3690,10 +3761,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Usuariu" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Usar el visor d'imáxenes integráu" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_START, "Aniciar" @@ -3709,14 +3776,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, "Nomatu (LAN): %s" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Siguir" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Sigue col conteníu n'execución y cola del menú rápidu." - ) MSG_HASH( /* FIXME Still exists in a comment about being removed */ MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, "Opacidá del pié" @@ -4204,3 +4263,10 @@ MSG_HASH( MSG_IOS_TOUCH_MOUSE_DISABLED, "El mur táctil ta desactiváu" ) +#ifdef HAVE_GAME_AI + + + + + +#endif diff --git a/intl/msg_hash_be.h b/intl/msg_hash_be.h index 385a270e98..ab7dd847a5 100644 --- a/intl/msg_hash_be.h +++ b/intl/msg_hash_be.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Выбраць ядро на выкарыстанне." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Выгрузіць ядро" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Выгружае загружанае ядро." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Выбар ядра libretro. Пры праглядзе браўзэр адчыняе шлях, паказаны для каталога захоўвання ядраў. Калі шлях не зададзены, прагляд пачынаецца з каранёвага каталога.\nКалі каталог захоўвання ядраў з'яўляецца тэчкай, меню будзе выкарыстоўваць яе ў якасці тэчкі верхняга ўзроўня. Ка[...]" @@ -914,6 +922,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Падтрымка Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Падтрымка SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Падтрымка libusb" @@ -1370,7 +1382,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_FILE_BROWSER_REMAP, - "Файл пераназначэння кіравання." + "Файл прызначэнняў кіравання." ) MSG_HASH( MENU_ENUM_LABEL_HELP_FILE_BROWSER_CHEAT, @@ -1442,7 +1454,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, - "Змяніць накладку на дысплэй і клавіятуру, а таксама налады апавяшчэнняў на экране." + "Змяніць накладку дысплэя і клавіятуры ды налады экранных апавяшчэнняў." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, @@ -1968,7 +1980,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Устаўляе чорны кадр(ы) паміж кадрамі. Можа істотна паменшыць размыццё шляхам эмуляцыі разгорткі ЭПТ, але зніжае яркасць. Не ўключайце адначасова з інтэрвалам абнаўлення > 1, падкадрамі, затрымкай кадра ці сінхранізацыяй з кадравай частатой кантэнту." + "УВАГА: хуткае мігаценне на некаторых дысплэях можа прыводзіць да астаткавай выявы. Выкарыстайце з асцярожнасцю // Устаўляе паміж кадрамі кадр(ы) чорнага колеру. Можа істотна паменшыць размыццё, эмулюючы разгортку ЭПТ, але зніжае яркасць." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2050,10 +2062,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES, "Падкадры шэйдэра" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Устаўляе паміж кадрамі дадатковы кадр(ы) шэйдара. Дазваляе шэйдарам выводзіць эфекты з кадравай частатой вышэй зыходнай частаты кантэнту. Значэнне павінна адпавядаць бягучай частаце экрана. Не ўключайце адначасова з інтэрвалам абнаўлення > 1, устаўкай чорнага кадра, затр[...]" - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, "Устаўляе паміж кадрамі дадатковы кадр(ы) шэйдара для ўсіх шэйдарных эфектаў з частатой вышэй частаты кантэнту. Выкарыстоўвайце значэнне толькі для бягучай частаты абнаўлення. Не дастасавальна з частатой абнаўлення не кратнай 60 Гц, напрыклад 144 Гц, 165 Гц і г. д. Не ўключайце [...]" @@ -2126,10 +2134,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCAN_SUBFRAMES, "Сімуляцыя плывучага радка разгорткі" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Імітуе просты плавальны радок разгорткі па-над некалькімі падкадрамі шляхам дзялення экрана па вертыкалі і адмалёўкі кожнай яго часткі зыходзячы з колькасці падкадраў." - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, "Імітуе просты плавальны радок разгорткі па-над некалькімі падкадрамі шляхам дзялення экрана па вертыкалі і адмалёўкі кожнай яго часткі зыходзячы з колькасці падкадраў ад верха да нізу экрана." @@ -2304,7 +2308,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_ROTATION, - "Прымушае пэўны паварот выявы. Дадаецца да паваротаў, што задае ядро." + "Прымушае ўжыць пэўны паварот выявы. Дадаецца да паваротаў, што задае ядро." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCREEN_ORIENTATION, @@ -2312,7 +2316,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SCREEN_ORIENTATION, - "Прымушае пэўную арыентацыю экрана паводле аперацыйнай сістэмы." + "Прымушае ўжыць пэўную арыентацыю экрана паводле аперацыйнай сістэмы." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_GPU_INDEX, @@ -2328,7 +2332,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_OFFSET_X, - "Прымушае пэўнае зрушэнне выявы па гарызанталі. Ужываецца глабальна." + "Прымушае ўжыць пэўнае зрушэнне выявы па гарызанталі. Ужываецца глабальна." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_OFFSET_Y, @@ -2336,7 +2340,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_OFFSET_Y, - "Прымушае пэўнае зрушэнне выявы па вертыкалі. Ужываецца глабальна." + "Прымушае ўжыць пэўнае зрушэнне выявы па вертыкалі. Ужываецца глабальна." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, @@ -2563,7 +2567,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Змяняць маштаб толькі па вышыні або як па вышыні, так і па шырыні. Паўкрокі прымяняюцца да крыніц з высокай раздзяляльнасцю." + "Змяняць маштаб па вышыні ці па шырыні, або адразу па вышыні ды шырыні. Паўкрокі ўжываюцца толькі на крыніцах з высокай раздзяляльнасцю." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2659,14 +2663,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_Y, "Зрух вобласці прагляду па Y" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Ўстаноўка зрушэння вобласці прагляду па гарызанталі (калі шырыня перавышае вышыню кантэнту). 0.0 адпавядае леваму краю, 1.0 - праваму." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Ўстаноўка зрушэння вобласці прагляду па вертыкалі (калі вышыня перавышае вышыню кантэнту). 0.0 адпавядае леваму краю, 1.0 - праваму." - ) #if defined(RARCH_MOBILE) MSG_HASH( MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, @@ -2684,14 +2680,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, "Зрух вобласці прагляду па Y (партрэтны рэжым)" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Ўстаноўка зрушэння вобласці прагляду па гарызанталі (калі шырыня перавышае вышыню кантэнту). 0.0 адпавядае леваму краю, 1.0 - праваму. Для (партрэтнага рэжыму)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Ўстаноўка зрушэння вобласці прагляду па вертыкалі (калі вышыня перавышае вышыню кантэнту). 0.0 адпавядае леваму краю, 1.0 - праваму. Для (партрэтнага рэжыму)" - ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, @@ -2938,7 +2926,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Сцішванне пры перамотцы наперад" + "Перамотка наперад з адключаным гукам" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2946,12 +2934,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Паскарэнне пры перамотцы наперад" + "Перамотка наперад з паскораным гукам" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Паскараць гук пры перамотцы наперад. Прадухіляе патрэскванне, але змяняе вышыню." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Перамотка назад з адключанымі гукам" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Аўтаматычна адключаць гук пры выкарыстанні перамотцы назад." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Узмацненне гучнасці (дБ)" @@ -3183,7 +3179,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_RATE_CONTROL_DELTA, - "Ўстаноўка на 0 адключае кіраванне частатой. Іншыя значэнні ўплываюць на адхіленне частаты гуку.\nВызначае межы змены зыходнай частаты пры дынамічнай падладцы. Разлічваецца наступным чынам:\\зыходная частата * (1.0 +/- (адхіленне кіравання частатой))" + "Ўстаноўка на 0 адключае кіраванне частатой. Іншыя значэнні ўплываюць на адхіленне частаты гуку.\nВызначае межы змены зыходнай частаты пры дынамічнай падладцы. Разлічваецца наступным чынам:\nзыходная частата * (1.0 +/- (адхіленне кіравання частатой))" ) /* Settings > Audio > MIDI */ @@ -3497,21 +3493,22 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Утрымлівайце" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Турба-кнопкі" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Перыяд турба" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Працягласць націску турба-кнопак (у кадрах)." + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, + "Цыкл дзеяння турба" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Цыкл працы турба" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Колькасць кадраў у перыядзе турбарэжыму, у якія кнопкі будуць націснутыя. Калі дадзенае значэнне больш ці роўна перыяду турбарэжыму, кнопкі будуць націснутыя ўвесь час." + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Палова перыяду" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, @@ -3538,45 +3535,25 @@ MSG_HASH( "Адна кнопка (Утрымліванне)" ) MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Класічны рэжым, дзве кнопкі для спрацоўвання. Утрымлівайце кнопку дзеяння і аднаразова націсніце кнопку Турба, каб актываваць цыкл націснуць-адпусціць.\nКнопку Турба можна прызначыць у Налады/Увод/Прывязкі порта 1." + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Актыватар турба" ) MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Класічны рэжым пераключэння з дзвюма кнопкамі. Для ўключэння турбарэжыму аднаразова націсніце кнопку Турба пад час утрымання кнопкі дзеяння. Для адключэння турба: зноў націсніце кнопку Турба і ўтрымлівайце кнопку дзеяння.\nКнопку Турба можна прызначыць у Налады/Увод/Пры[...]" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Турба-кнопка" ) MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Рэжым пераключэння. Аднаразова націсніце кнопку Турба, каб актываваць цыкл націснуць-адпусціць для абранай кнопкі. Націсніце паўторна для адключэння.\nКнопку Турба можна прызначыць у Налады/Увод/Прывязкі порта 1." + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Дазвол турба на кірункі D-Pad" ) MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Рэжым з утрымліваннем. Цыкл націснуць-адпусціць для зададзенай кнопкі дзейнічае пакуль заціснутая кнопка Турба.\nКнопку Турба можна прызначыць у Налады/Увод/Прывязкі порта.\nДля эмуляцыі аўтаматычнага агню ў стылі эпохі хатніх кампутараў, прызначце кнопкі Турба і дзеянне[...]" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Прадвызначаная кнопка турба" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Кнопка дзеяння, якая выкарыстоўваецца ў турбарэжымах 'Адна кнопка'." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Дазваляць турбакірункі D-Pad" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, "Калі ўключана, уводы лічбавых кірункаў (таксама вядомыя як d-pad ці 'hatswitch') могуць быць турба." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "Турба-кнопкі" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Налады турба-кнопак.\nНататка: для працы функцыі патрабуецца прывязаць турба-кнопку да прылады ўводу ў адпаведным меню 'Прывязкі порта X'." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, "Тактыльная аддача/вібрацыя" @@ -3772,7 +3749,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Пераключае паміж меню ды бягучым змесцівам на бягучым дысплэі." + "Пераключае бягучы дысплэй паміж меню ды змесцівам." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3844,7 +3821,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REWIND_HOTKEY, - "Зваротная перамотка кантэнту пры ўтрыманні кнопкі. Павінна быць уключана 'Падтрымка перамоткі'." + "Перамотка назад бягучага змесціва пры ўтрыманні кнопкі. Мае быць уключана 'Падтрымка перамоткі назад'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, @@ -3852,7 +3829,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Прыпыняе ці аднаўляе бягучы кантэнт." + "Пераключае змесціва паміж станамі з прыпыненнем ды без." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -4090,7 +4067,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_UI_COMPANION_TOGGLE, - "Выклікае дапаможны інтэрфейс WIMP (Windows, Icons, Menus, Pointer)." + "Выклікае дапаможны карыстальніцкі інтэрфейс WIMP (Windows, Icons, Menus, Pointer)." ) MSG_HASH( @@ -4156,7 +4133,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE, - "Захапляе выяву бягучага кантэнту для перакладу і/або агучвае любы тэкст на экране. 'AI-сэрвіс' павінен быць уключаны і наладжаны." + "Захапляе выяву бягучага змесціва на пераклад ды/або агучвае любы тэкст на экране. 'ШІ-сэрвіс' павінен быць уключаны і наладжаны." ) MSG_HASH( @@ -4448,7 +4425,7 @@ MSG_HASH( "Пісталет D-Pad направа" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, "Турба" ) @@ -4581,7 +4558,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Дазволіць абыход магчымасцяў хуткіх захаванняў ва ўласцівасцях ядра, гэта дазваляе эксперыментаваць са звязанымі функцыямі (забяганне, зваротная перамотка і г. д.)." + "Вызначае, ці варта ігнараваць уласцівасці захавання стану ў звестках ядра, што дазваляе эксперыментаваць з адпаведнымі функцыямі (забяганне, перамотка назад і г. д.)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4825,7 +4802,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Аўтаматычна ствараць захаванне пры зачыненні кантэнту. RetroArch будзе аўтаматычна загружаць дадзенае захаванне, калі ўключана 'Аўтазагрузка захаванняў'." + "Аўтаматычна ствараць захаванне стану падчас закрыцця змесціва. Гэты стан будзе загружаны пры запуску, калі ўключана 'Аўтаматычная загрузка стану'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -5003,16 +4980,16 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, - "Фільтраваць файлы, якія паказваюцца файлавым браўзерам, па пашырэннях, якія падтрымліваюцца." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Выкарыстанне ўбудаванага медыяпрайгравальніка" + "Фільтраваць паказ файлаў файлавым браўзерам паводле падтрымкі пашырэння." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Фільтраванне па бягучаму ядру" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Фільтраваць паказ файлаў файлавым браўзерам па бягучаму ядру." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Памятаць апошні выкарыстаны пачатковы каталог" @@ -5021,6 +4998,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Адкрываць файлавы браўзер на апошнім выкарыстаным месцы пры загрузцы змесціва з пачатковага каталога. Заўвага: месца будзе скінута да прадвызначанага пры перазапуску RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Выкарыстанне ўбудаванага медыяпрайгравальніка" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Убудаваны прагляд малюнкаў" + ) /* Settings > Frame Throttle */ @@ -5066,7 +5051,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, - "Хуткасць кантэнту пры выкарыстанні функцыі запавольвання." + "Хуткасць змесціва пры выкарыстанні функцыі запаволенага руху." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, @@ -5093,7 +5078,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, - "Колькасць кадраў перамоткі за адзін крок. Больш высокія значэнні павялічваюць хуткасць перамоткі." + "Колькасць кадраў перамоткі назад на крок. Больш высокія значэнні павялічваюць хуткасць перамоткі назад." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE, @@ -5386,6 +5371,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "Настройка памеру зон перакрыцця для блока кнопак. Усталюйце на 100% для сіметрыі па 8 напрамках." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Зона перацэнтроўкі аналагавага ўвода" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Увод аналагавы стыку будзе адлічвацца адносна першага дотыку пры націсканні ў гэтай зоне." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Накладка" @@ -5719,7 +5712,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, - "Вывад паведамленняў на экран." + "Паказваць экранныя паведамленні." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_WIDGETS_ENABLE, @@ -5821,13 +5814,17 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Апавяшчэнне пра злучэнне прылады ўводу (аўтаканфігурацыя)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Апавяшчэнні пра памылкі прылад увода (аўтаканфігурацыя)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Апавяшчэнні пра чыт-коды" ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_CHEATS_APPLIED, - "Адлюстроўваць паведамленне пры загрузцы чыт-кодаў." + "Адлюстроўваць экраннае паведамленне пры загрузцы чыт-кодаў." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_PATCH_APPLIED, @@ -5835,11 +5832,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_PATCH_APPLIED, - "Адлюстроўваць паведамленне, калі да ROM ужыты софт-патч." + "Адлюстроўваць экраннае паведамленне, калі да ROM ужыты софт-патч." ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, - "Адлюстроўваць паведамленне пры злучэнне/адлучэнне прылад уводу." + "Адлюстроўваць экраннае паведамленне пры злучэнне/адлучэнне прылад уводу." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, @@ -5847,7 +5844,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_REMAP_LOAD, - "Адлюстроўваць паведамленне пры загрузцы файлаў раскладак кіравання." + "Адлюстроўваць экраннае паведамленне пры загрузцы файлаў раскладак кіравання." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD, @@ -5855,7 +5852,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD, - "Паказваць паведамленне пры загрузцы перавызначэння канфігурацыі." + "Паказваць экраннае паведамленне пры загрузцы перавызначэння канфігурацыі." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_SET_INITIAL_DISK, @@ -5863,7 +5860,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_SET_INITIAL_DISK, - "Адлюстроўваць паведамленне пры аўтаматычным запуску апошняга выкарыстанага дыска з дапамогай M3U-плэйліста для мультыдыскавага кантэнту." + "Адлюстроўваць экраннае паведамленне пры аўтаматычным запуску апошняга выкарыстанага дыска з дапамогай M3U-плэйліста для шматдыскавага змесціва." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_DISK_CONTROL, @@ -5871,7 +5868,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_DISK_CONTROL, - "Адлюстроўваць паведамленне пры ўстаўцы і выманні дыска." + "Адлюстроўваць экраннае паведамленне пры ўстаўцы і выманні дыска." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_SAVE_STATE, @@ -5879,7 +5876,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_SAVE_STATE, - "Адлюстроўваць на экране паведамленне пры захаванні ды загрузцы станаў." + "Адлюстроўваць экраннае паведамленне пры захаванні ды загрузцы станаў." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_FAST_FORWARD, @@ -5895,7 +5892,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_SCREENSHOT, - "Адлюстроўваць паведамленне пры захаванні скрыншота." + "Адлюстроўваць экраннае паведамленне пры захаванні здымка экрана." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_SCREENSHOT_DURATION, @@ -5927,7 +5924,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_SCREENSHOT_FLASH, - "Адлюстраванне на экране эфекту ўспышкі з зададзенай працягласцю пры стварэнні скрыншота." + "Адлюстраванне на экране эфекту ўспышкі з зададзенай працягласцю пры стварэнні здымка экрана." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_SCREENSHOT_FLASH_NORMAL, @@ -5943,7 +5940,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_REFRESH_RATE, - "Адлюстроўваць паведамленне пры змене частаты абнаўлення." + "Адлюстроўваць экраннае паведамленне пры змене частаты абнаўлення." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_NETPLAY_EXTRA, @@ -5973,10 +5970,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "Памер апавяшчэнняў" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Ўстаноўка памеру шрыфта апавяшчэнняў." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, "Палажэнне апавяшчэння (па гарызанталі)" @@ -6132,7 +6125,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Прыпыняць запушчаны кантэнт пры выкліку меню." + "Прыпыняць змесціва пры выкліку меню." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6256,15 +6249,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, - "Дадатковы інтэрфейс" + "Дапаможны інтэрфейс" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, - "Запуск дадатковага інтэрфейсу пры загрузцы" + "Запуск дапаможнага інтэрфейсу пры загрузцы" ) MSG_HASH( MENU_ENUM_LABEL_HELP_UI_COMPANION_START_ON_BOOT, - "Запускаць дадатковы драйвер карыстальніцкага інтэрфейсу пры загрузцы (калі даступна)." + "Запускаць драйвер дапаможнага карыстальніцкага інтэрфейсу пры загрузцы (калі даступна)." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DESKTOP_MENU_ENABLE, @@ -6405,7 +6398,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, - "Паказваць меню 'Налады' (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць меню 'Налады'. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS_PASSWORD, @@ -6421,7 +6414,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, - "Паказваць меню 'Упадабанае' (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць меню 'Упадабанае'. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, @@ -6429,7 +6422,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, - "Паказваць меню 'Відарысы' (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць меню 'Відарысы'. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, @@ -6437,7 +6430,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, - "Паказваць меню 'Музыка' (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць меню 'Музыка'. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, @@ -6445,7 +6438,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, - "Паказваць меню 'Відэа' (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць меню 'Відэа'. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, @@ -6453,7 +6446,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, - "Паказваць меню 'Сеткавая гульня' (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць меню 'Сеткавая гульня'. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, @@ -6461,7 +6454,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, - "Паказваць меню нядаўняй гісторыі (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць меню нядаўняй гісторыі. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, @@ -6469,7 +6462,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, - "Паказваць меню 'Імпартаваць змесціва' (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць меню 'Імпартаваць змесціва'. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( /* FIXME can now be replaced with MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD */ MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD_ENTRY, @@ -6493,7 +6486,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Паказваць плэй-лісты (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць плэй-лісты ў галоўным меню. Ігнаруецца ў GLUI, калі ўключаныя карткі плэй-лістоў ды панэлі навігацыі." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Паказ картак плэй-лістоў" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Паказваць карткі плэй-лістоў. Не мае ўплыву на RGUI. Панэль навігацыі мае быць уключаная ў GLUI. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6501,7 +6502,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_EXPLORE, - "Паказваць опцыю даследчыка змесціва (патрабуецца перазапуск на Ozone/XMB)" + "Паказваць опцыю даследчыка змесціва. (Патрабуецца перазапуск на Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_CONTENTLESS_CORES, @@ -6688,11 +6689,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_OVERLAYS, - "Паказваць 'Аверлэі'" + "Паказ 'Экранныя накладкі'" ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_OVERLAYS, - "Паказваць опцыю 'Аверлэі'." + "Паказваць опцыю 'Экранныя накладкі'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO_LAYOUT, @@ -6973,14 +6974,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Паказ 'Карыстальнік'" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Значкі плэй-ліста" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Тып мініяцюры для адлюстравання значкоў плэй-ліста." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Паказваць налады 'Карыстальнік'." @@ -7087,11 +7080,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_REMEMBER_SELECTION, - "Запамінаць выбар пры змене ўкладак" + "Запамінаць выбар пры змене картак" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_REMEMBER_SELECTION, - "Запамінаць пазіцыю курсора на ўкладках. RGUI не мае ўкладак, але Плэйлісты і Налады паводзяць сябе як такія." + "Запамінаць пазіцыю курсора ў картках. RGUI не мае картак, але плэй-лісты ды налады паводзяць сябе гэтаксама." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_REMEMBER_SELECTION_ALWAYS, @@ -7194,7 +7187,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, - "Адключае чыты, перамотку, запаволенне і загрузку захаванняў стану. Дасягненні ў рэжыме хардкора маюць спецыяльную пазнаку, каб паказаць іншым гульцам вашыя навыкі без магчымасцяў эмулятара. Пераключэнне наладкі падчас гульні прывядзе да яе перазапуску." + "Адключае чыты, перамотку, запаволены рух ды загрузку захаванняў стану. Дасягненні ў рэжыме хардкора маюць спецыяльную пазнаку, каб паказаць іншым гульцам вашыя навыкі без магчымасцяў эмулятара. Пераключэнне наладкі падчас гульні прывядзе да яе перазапуску." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, @@ -7257,7 +7250,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_APPEARANCE_SETTINGS, - "Настройка размяшчэння і зрушэнняў для наэкранных апавяшчэнняў аб дасягненнях." + "Змяніць размяшчэнне і зрухі экранных апавяшчэнняў пра дасягненні." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR, @@ -8208,7 +8201,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Файлавы браўзер" + "Пачатковы каталог" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8453,7 +8446,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Выбраць якая інфармацыя аб запушчаным кантэнце будзе перададзена." + "Выбраць, якія звесткі пра змесціва будуць перададзеныя." ) MSG_HASH( @@ -9053,7 +9046,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Закрыць хуткае меню і аднавіць бягучы кантэнт." + "Закрыць хуткае меню і аднавіць змесціва." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -9069,7 +9062,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Закрыць бягучае змесціва. Любыя незахаваныя змены могуць страціцца." + "Закрыць змесціва. Любыя незахаваныя змены могуць быць страчаныя." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9205,7 +9198,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Змяніць опцыі бягучага выканання змесціва." + "Змена опцый для змесціва." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9213,7 +9206,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Змяніць кіраванне бягучым выкананнем змесціва." + "Змяніць кіраванне для змесціва." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9311,11 +9304,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Скінуць опцыі" + "Скід опцый ядра" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Задаць усім опцыям ядра прадвызначаныя значэнні." + "Скінуць усе значэнні опцый бягучага ядра да прадвызначаных." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9839,7 +9832,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Адсочваць змены ў файлах шэйдара. Пасля захавання змен шэйдара ў памяць, ён будзе аўтаматычна перакампіляваны і ўжыты да запушчанага кантэнту." + "Адсочваць змены ў файлах шэйдара. Пасля захавання змен шэйдара на дыск ён будзе аўтаматычна перакампіляваны і ўжыты да змесціва." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10160,7 +10153,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE, - "Прыпыняе рэжым хардкора для дасягненняў у бягучым сеансе. Дадзенае дзеянне актывуе чыт-коды, перамотку, запавольванне і загрузку захаванняў." + "Прыпыняе хардкор рэжым дасягненняў у бягучым сеансе. Гэтае дзеянне актывуе чыт-коды, перамотку, запавольваны рух ды загрузку станаў." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME, @@ -10168,7 +10161,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, - "Аднаўляе дасягненні ў рэжыме хардкора для бягучага сеансу. Дадзенае дзеянне адключыць чыт-коды, перамотку, запавольванне, загрузку захаванняў і перазапусціць гульню." + "Аднаўляе дасягненні ў хардкор рэжыме на бягучы сеанс. Гэтае дзеянне адключае чыт-коды, перамотку назад, запавольванне, загрузку захаванняў стану і перазапускае гульню." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_SERVER_UNREACHABLE, @@ -10304,6 +10297,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Пераключыць эскізы" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Выпадковы выбар" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Назад" @@ -11088,7 +11085,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Адлюстроўваць у фоне запушчаны кантэнт пры выкліку хуткага меню. Адключэнне празрыстасці можа змяніць колеры тэмы." + "Адлюстроўваць у фоне змесціва пры выкліку хуткага меню. Адключэнне празрыстасці можа змяніць колеры тэмы." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11388,6 +11385,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Тып мініяцюры для адлюстравання злева." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Значок мініяцюры" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Тып значка мініяцюры, які адлюстроўваецца ў плэй-лісце." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Дынамічны фон" @@ -11410,7 +11415,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_XMB_ANIMATION_HORIZONTAL_HIGHLIGHT, - "Эфект анімацыі пры пераключэнні ўкладак." + "Эфект анімацыі пры прагортцы картак." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_XMB_ANIMATION_MOVE_UP_DOWN, @@ -11667,6 +11672,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDGAR, "Мідгар" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Цёмна-шэрая" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Светла-шэрая" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11694,6 +11707,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Плэйлісты будуць перасартаваны ў алфавітным парадку пасля выдалення назваў кампаній." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Другарадная мініяцюра" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Замяняе вобласць метададзеных дадатковай мініяцюрай." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Скролінг метададзеных кантэнту" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Калі ўключана, метададзеныя ў правай частцы плэйліста (прывязка ядра, час працы) займаюць адзін радок; запісы больш шырыні бакавой панэлі будуць адлюстраваны бягучым радком. Калі выключана, усе метададзеныя будуць адлюстраваны статычна, займаючы неабходную колькасць рад[...]" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Каэфіцыент маштабавання мініяцюр" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Змяняе памер вобласці мініяцюр." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Колеравая тэма" @@ -11718,10 +11756,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_TWILIGHT_ZONE, "Змрочная зона" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, - "Сэлен" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, "Solarized цёмная" @@ -11739,30 +11773,11 @@ MSG_HASH( "Светла-шэрая" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Другарадная мініяцюра" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Замяняе вобласць метададзеных дадатковай мініяцюрай." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Скролінг метададзеных кантэнту" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Калі ўключана, метададзеныя ў правай частцы плэйліста (прывязка ядра, час працы) займаюць адзін радок; запісы больш шырыні бакавой панэлі будуць адлюстраваны бягучым радком. Калі выключана, усе метададзеныя будуць адлюстраваны статычна, займаючы неабходную колькасць рад[...]" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Каэфіцыент маштабавання мініяцюр" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Змяняе памер вобласці мініяцюр." + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "Сэлен" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -12726,10 +12741,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Клавіятура" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Убудаваны прагляд малюнкаў" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Максімум малюнкаў у свопчэйне" @@ -12865,14 +12876,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Выбраць з плэйліста" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Працягнуць" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Закрыць хуткае меню і аднавіць бягучы кантэнт." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Прагляд спісу %u супадзенняў" @@ -13471,10 +13474,6 @@ MSG_HASH( MSG_AUTODETECT, "Аўтавызначэнне" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Аўтазагрузка захавання з" - ) MSG_HASH( MSG_CAPABILITIES, "Магчымасці" @@ -14333,7 +14332,7 @@ MSG_HASH( ) MSG_HASH( MSG_REWIND_UNSUPPORTED, - "Зваротная перамотка недаступная праз адсутнасць у ядры серыялізаванай падтрымкі захавання стану." + "Перамотка назад недаступная праз адсутнасць у ядры серыялізаванай падтрымкі захавання стану." ) MSG_HASH( MSG_REWIND_INIT, @@ -14567,6 +14566,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Не атрымалася зачыніць латок віртуальнага cd-прывада." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Аўтазагрузка захавання з" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Памылка аўтаматычнай загрузкі захавання стану з \"%s\"." @@ -14865,15 +14868,23 @@ MSG_HASH( ) MSG_HASH( MSG_CHEEVOS_LOAD_STATE_PREVENTED_BY_HARDCORE_MODE, - "Для загрузкі захаванняў патрабуецца адключыць ці прыпыніць Рэжым хардкора для дасягненняў." + "Загрузка станаў патрабуе адключэння ці прыпынення хардкор рэжыму дасягненняў." ) MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED, - "Загружана захаванне стану. Для бягучага сеанса дасягненняў рэжым хардкору адключаны." + "Загружана захаванне стану. Хардкор рэжым дасягненняў у бягучым сеансе адключаны." ) MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, - "Актываваны чыт-код. Рэжым харкдора для дасягненняў у бягучым сеансе адключаны." + "Актываваны чыт-код. Хардкор рэжым дасягненняў у бягучым сеансе адключаны." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Хардкор рэжым дасягненняў зменены хастом." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "Трэба абнавіць хост сеткавай гульні. Хардкор рэжым дасягненняў у бягучым сеансе адключаны." ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, @@ -14885,7 +14896,7 @@ MSG_HASH( ) MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_ENABLE, - "Уключаны рэжым хардкору, захаванне стану ды перамотка назад адключаныя." + "Уключаны хардкор рэжым, захаванне стану ды перамотка назад адключаныя." ) MSG_HASH( MSG_CHEEVOS_GAME_HAS_NO_ACHIEVEMENTS, @@ -15815,7 +15826,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Паказвае шрыфт ніжняга меню. Уключыце для адлюстравання апісання кнопак на ніжнім экране. Не ўключае даты захаванняў." + "Адлюстроўвае шрыфт ніжняга меню. Уключыце, каб бачыць апісанне кнопак на ніжнім экране. Адкідае даты захаванняў стану." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, @@ -15884,3 +15895,42 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "спынены." ) +#ifdef HAVE_GAME_AI + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "Гульнявы ШІ" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Перавызначыць гульца 1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Перавызначыць гульца 1" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Перавызначыць гульца 2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Перавызначыць гульца 2" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Паказ адладкі" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Паказваць адладку" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Паказваць 'Гульнявы ШІ'" + ) +#endif diff --git a/intl/msg_hash_bg.h b/intl/msg_hash_bg.h index eb30cb6dff..18a25905e0 100644 --- a/intl/msg_hash_bg.h +++ b/intl/msg_hash_bg.h @@ -998,6 +998,7 @@ MSG_HASH( "Задръж" ) + /* Settings > Input > Haptic Feedback/Vibration */ @@ -1236,7 +1237,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Разглеждане на файловете" + "Начална Директория" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, @@ -1419,6 +1420,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -1551,4 +1554,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_ca.h b/intl/msg_hash_ca.h index becf7ef2f3..6cdaad3641 100644 --- a/intl/msg_hash_ca.h +++ b/intl/msg_hash_ca.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Selecciona quin nucli utilitzar." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Tanca el nucli" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Allibera el nucli carregat." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Cerca una implementació d'un nucli de libretro. La ubicació d'inici del navegador depèn de la ruta del Directori de Nuclis. En cas de trobar-se en blanc, començarà al directori arrel.\nSi el Directori de Nuclis és un directori, el menú l'usarà com a carpeta inicial. Altrament, si és una ruta completa, el navegador s'iniciarà a la carpeta on es trobi el fitxer." @@ -718,6 +726,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "Compatibilitat amb SDL 2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Compatibilitat amb el Direct3D 8" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Compatibilitat amb el Direct3D 9" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Compatibilitat amb el Direct3D 10" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Compatibilitat amb el Direct3D 11" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Compatibilitat amb el Direct3D 12" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, "Compatibilitat amb GDI" @@ -802,6 +830,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "Compatibilitat amb PulseAudio" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "Suport de PipeWire" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "Compatibilitat amb CoreAudio" @@ -882,6 +914,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Compatibilitat amb Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Compatibilitat amb SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Compatibilitat amb libusb" @@ -1733,6 +1769,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PULSE, "Controlador PulseAudio. Si el sistema utilitza PulseAudio, assegura't de fer servir aquest controlador en compte de, p. ex., l'ALSA." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PIPEWIRE, + "Controlador PipeWire. Si el sistema utilitza PipeWire, assegura't de fer servir aquest controlador en compte de, p. ex., el PulseAudio." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_JACK, "Controlador del Jack Audio Connection Kit (JACK)." @@ -1754,6 +1794,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MICROPHONE_RESAMPLER_DRIVER, "Controlador del remostreig del micròfon que es farà servir." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MICROPHONE_BLOCK_FRAMES, + "Marcs de blocs del micròfon" + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, @@ -1920,7 +1964,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Insereix fotogrames en negre entre fotogrames. Pot reduir considerablement el difuminat per moviment emulant l'escaneig de sortida que fan les pantalles CRT, però a costa de la brillantor. No ho combineu amb intervals d'intercanvi > 1, subfotogrames, retard dels fotogrames ni amb la sincronització a la velocitat de fotogrames del contingut exacta." + "ATENCIÓ: El parpelleig ràpid podria causar una persistència de la imatge en algunes pantalles. Utilitza-ho sota el teu propi risc. // Insereix fotogrames en negre entre fotogrames. Pot reduir molt el desenfocament per moviment emulant l'escaneig d'un monitor CRT, en detriment de la brillantor." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2004,7 +2048,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Insereix fotogrames d'ombreig extra entre fotogrames. Permet a l'ombreig fer efectes que s'executen a fotogrames per segon més alts que la freqüència actual del contingut. S'haura d'establir a la freqüència de la pantalla. No ho combineu amb interval d'intercanvi > 1, BFI, retard dels fotogrames ni amb la sincronització a la velocitat de fotogrames del contingut exacta." + "AVÍS: El parpelleig ràpid pot causar errors gràfics en algunes pantalles. Fes servir aquesta opció sota la teva responsabilitat // Simula una línia d'escaneig en moviment bàsica sobre múltiples subfotogrames dividint la pantalla en vertical i renderitzant cada part d'acord amb quants subfotogrames hi ha." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2080,7 +2124,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Simula una línia d'escaneig en moviment bàsica sobre múltiples subfotogrames dividint la pantalla en vertical i renderitzant cada part d'acord amb quants subfotogrames hi ha." + "AVÍS: El parpelleig ràpid pot causar errors gràfics en algunes pantalles. Fes servir aquesta opció sota la teva responsabilitat // Simula una línia d'escaneig en moviment bàsica sobre múltiples subfotogrames dividint la pantalla en vertical i renderitzant cada part d'acord amb quants subfotogrames hi ha." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2314,6 +2358,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_POLLED, "La freqüència d'actualització que notifica el controlador de la pantalla." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_AUTOSWITCH_REFRESH_RATE, + "Canvia automàticament la freqüència d'actualització" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_AUTOSWITCH_REFRESH_RATE, + "Canvia automàticament la freqüència d'actualització de la pantalla en funció del contingut actual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_AUTOSWITCH_REFRESH_RATE_EXCLUSIVE_FULLSCREEN, "Només en mode de pantalla completa exclusiva" @@ -2326,6 +2378,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_AUTOSWITCH_REFRESH_RATE_ALL_FULLSCREEN, "Tots els modes de pantalla completa" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_AUTOSWITCH_PAL_THRESHOLD, + "Llindar de freqüència d'actualització PAL" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_AUTOSWITCH_PAL_THRESHOLD, + "La taxa de refresc màxima considerada com a PAL." + ) #if defined(DINGUX) && defined(DINGUX_BETA) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_REFRESH_RATE, @@ -2477,6 +2537,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, "Escalat d'enter" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, + "Eix d'escala entera" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, + "Escalat per nombre enter" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_UNDERSCALE, "Reduïr escala" @@ -2535,11 +2603,51 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, "Relació d'aspecte personalitzat (posició X)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, + "Desplaçament personalitzat per definir la posició en l'eix X de l'àrea de visualització." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, "Relació d'aspecte personalitzat (posició Y)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, + "Desplaçament personalitzat per definir la posició en l'eix Y de l'àrea de visualització." + ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_X, + "Compensa l'eix X del punt d'anclatge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_X, + "Compensa l'eix X del punt d'anclatge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_Y, + "Compensa l'eix Y del punt d'anclatge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_Y, + "Compensa l'eix Y del punt d'anclatge" + ) #if defined(RARCH_MOBILE) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, + "Compensació de l'eix X del punt d'ancoratge de l'àrea de visualització (orientació vertical)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, + "Compensació de l'eix X del punt d'ancoratge de l'àrea de visualització (orientació vertical)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, + "Compensació de l'eix Y del punt d'ancoratge de l'àrea de visualització (orientació vertical)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, + "Compensació de l'eix Y del punt d'ancoratge de l'àrea de visualització (orientació vertical)" + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, @@ -2557,6 +2665,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, "Alçada personalitzada de la subàrea de visualització que s'usa si la relació d'aspecte s'estableix a 'Relació d'aspecte personalitzada'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, + "Retalla el sobreescombrat (Es requereix reinici)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, "Retalla uns quants píxels sobre les vores de la imatge deixats en blanc normalment pels desenvolupadors i que de vegades també contenen píxels brossa." @@ -2635,10 +2747,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, "Retard dels fotogrames" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, + "Redueix la latència a canvi d'augmentar la probabilitat que es produeixen estrebades de vídeo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTO, "Retard automàtic de fotograma" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY_AUTO, + "Ajusta el retard de fotogrames real de forma dinàmica." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTOMATIC, "Automàtic" @@ -2691,6 +2811,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_SETTINGS, "Micròfon" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MICROPHONE_SETTINGS, + "Canvia la configuració d'entrada d'àudio." + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_SETTINGS, @@ -2744,9 +2868,17 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "Silencia l'àudio del mesclador." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_RESPECT_SILENT_MODE, + "Respecta el mode silenciós" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE, + "Silencia l'àudio en fer servir el mode silenci." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Silencia en l'avanç ràpid" + "Silencia l'àudio en l'avançament ràpid" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2754,12 +2886,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Accelerar a l'usar l'avançament ràpid" + "Accelerar l'àudio durant l'avançament ràpid" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Accelera l'àudio a l'emprar l'avançament ràpid. Defugirá sorolls en l'àudio però canviant la seva tonalitat." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Silencia l'àudio en rebobinar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Silencia automàticament el so quan s’usa el rebobinat ràpid." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Guany de volum (dB)" @@ -2839,6 +2979,22 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DEVICE, "Força el dispositiu que fa servir el controlador d’àudio. Això depèn del controlador." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DEVICE_ALSA, + "Valor personalitzat del dispositiu PCM pel controlador ALSA." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DEVICE_OSS, + "Valor personalitzat per la ruta del controlador OSS." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DEVICE_JACK, + "Valor personalitzat del nom del port pel controlador JACK (per exemple: system:playback1,system:playback_2)." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DEVICE_RSOUND, + "Direcció IP personalitzada en un servidor RSound pel controlador RSound." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, "Latència de l'àudio (ms)" @@ -2850,10 +3006,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_ENABLE, "Micròfon" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MICROPHONE_ENABLE, + "Activa l'entrada d'àudio en aquells nuclis que siguin compatibles. Si el nucli no fa servir el micròfon, no augmenta la càrrega de la CPU." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_DEVICE, "Dispositiu" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MICROPHONE_DEVICE, + "Força el dispositiu que fa servir el controlador de micròfon. Això depèn del controlador." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_MICROPHONE_DEVICE, + "Força el dispositiu que fa servir el controlador de micròfon. Això depèn del controlador." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_RESAMPLER_QUALITY, "Qualitat del re-sampleig" @@ -2862,6 +3030,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MICROPHONE_RESAMPLER_QUALITY, "Baixeu aquest valor per a afavorir el rendiment/baixa latència sobre la qualitat de l'àudio, augmenteu-lo per a una millor qualitat d'àudio a expenses de rendiment/baixa latència." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MICROPHONE_INPUT_RATE, + "Freqüència d'entrada predeterminada (Hz)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MICROPHONE_INPUT_RATE, + "Indica la freqüència de mostreig de l'entrada d'àudio. S'utilitzarà si els nuclis no demanen un valor concret." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MICROPHONE_LATENCY, + "Latència de l'entrada de so (ms)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_WASAPI_EXCLUSIVE_MODE, "Mode WASAPI exclusiu" @@ -2870,6 +3050,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_WASAPI_FLOAT_FORMAT, "Format WASAPI de coma flotant" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MICROPHONE_WASAPI_FLOAT_FORMAT, + "Fes servir el format de coma flotant pel controlador WASAPI, si és compatible amb el teu dispositiu d'àudio." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_WASAPI_SH_BUFFER_LENGTH, "Mida de la memòria intermèdia compartida de WASAPI" @@ -2955,6 +3139,10 @@ MSG_HASH( /* Settings > Audio > Mixer Settings > Mixer Stream */ +MSG_HASH( + MENU_ENUM_LABEL_MIXER_STREAM, + "Mescla de la retransmissió #%d: %s" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY, "Reprodueix" @@ -3003,6 +3191,26 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, "Ajusta el volum del flux d'àudio." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_NONE, + "Estat: no disponible" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_STOPPED, + "Estat: aturat" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING, + "Estat: reproduint" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_LOOPED, + "Estat: Reproduint (en bucle)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL, + "Estat: Reproduint (Seqüencial)" + ) /* Settings > Audio > Menu Sounds */ @@ -3030,6 +3238,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SOUND_BGM, "Activa el so de 'BGM'" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SOUND_SCROLL, + "Activa el so de desplaçament" + ) /* Settings > Input */ @@ -3041,6 +3253,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, "El número màxim d'usuaris suportat per RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, + "Sistema de votació (Es requereix reinici)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, "Re-mapeja els controls d'aquest nucli" @@ -3049,6 +3265,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, "Sobreescriu les assignacions d'entrada amb les establertes per a aquest nucli." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_REMAP_SORT_BY_CONTROLLER_ENABLE, + "Endreça les assignacions per cada controlador" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_REMAP_SORT_BY_CONTROLLER_ENABLE, + "Les assignacions s'aplicaran només al controlador actiu en el qual s'han desat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, "Auto-configura" @@ -3058,12 +3282,24 @@ MSG_HASH( "Configura automàticament els controladors que tenen un perfil, a l'estil Plug-and-Play." ) #if defined(HAVE_DINPUT) || defined(HAVE_WINRAWINPUT) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_NOWINKEY_ENABLE, + "Deshabilita les combinacions de tecles de Windows (Es requereix reiniciar)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_NOWINKEY_ENABLE, "Manté les combinacions de tecles Windows dins l'aplicació." ) #endif #ifdef ANDROID +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SELECT_PHYSICAL_KEYBOARD, + "Selecciona el teclat físic" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_SELECT_PHYSICAL_KEYBOARD, + "Fes servir aquest dispositiu per un teclat físic i no per un controlador." + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SENSORS_ENABLE, @@ -3149,6 +3385,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, "La quantitat de segons que se sosté una entrada per a assignar-la." ) +MSG_HASH( + MSG_INPUT_BIND_PRESS, + "Clica al teclat, ratolí o controlador" + ) +MSG_HASH( + MSG_INPUT_BIND_RELEASE, + "Deixa anar totes les tecles i botons!" + ) MSG_HASH( MSG_INPUT_BIND_TIMEOUT, "Temps d'espera superat" @@ -3157,21 +3401,30 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Mantingueu premut" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Disparador de turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "En desactivar aquesta opció, s'aturaran totes les opcions de turbo/tir automàtic." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Període de turbo" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "El període (en fotogrames) quan es polsen els botons turbo." + "Indica la duració entre fotogrames quan els botons amb turbo es cliquen." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Cicle de turbo requerit" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, + "Cicle de treball del turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "El nombre de fotogrames que es premen els botons del període de turbo. Si aquest número és igual o major que el període de turbo, els botons mai s'amollaran." + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Mig cicle" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, @@ -3186,17 +3439,49 @@ MSG_HASH( "Clàssic" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Botó per defecte del turbo" + MENU_ENUM_LABEL_VALUE_TURBO_MODE_CLASSIC_TOGGLE, + "Clàssic (Alternar)" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Botó actiu per defecte per al mode 'Botó únic'." + MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON, + "Botó simple (alternar)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, + "Botó simple (Mantenir)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Assignació del turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "L'assignació que activarà el turbo en el RetroPad. Si està buit, s'utilitzarà l'assignació específica del port." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Botó del turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "El botó que es farà servir pel turbo en el mode de botó dedicat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Permet direccions amb la creueta amb turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, + "Permet que els botons digitals de direcció (coneguts com a creueta) puguin fer servir el mode turbo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "Disparador de turbo" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, + "Canvia les opcions per disparar amb turbo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, "Vibració/Resposta Hàptica" @@ -3217,6 +3502,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, "Dreceres de teclat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, + "Canvia la configuració i l'assignació de tecles d'accés ràpid, així com les combinacions de tecles per mostrar o amagar el menú durant la partida." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_RETROPAD_BINDS, "Assignacions dels RetroPad" @@ -3225,6 +3514,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, "Controls del port %u" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_USER_REMAPS, + "Canvia les assignacions d'entrada específiques pel nucli." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ANDROID_INPUT_DISCONNECT_WORKAROUND, "Solució per les desconnexions d’Android" @@ -3283,6 +3576,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_DISABLE_SEARCH_BUTTON, "Si s’activa s’ignoraran les pulsacions del botó de cerca." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DISABLE_LEFT_ANALOG_IN_MENU, + "Deshabilita analògic esquerre en el menú" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DISABLE_LEFT_ANALOG_IN_MENU, + "Impedeix que el joystick esquerra pugui navegar pels menús." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DISABLE_RIGHT_ANALOG_IN_MENU, + "Deshabilita l'analògic dret en els menús" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DISABLE_RIGHT_ANALOG_IN_MENU, + "Impedeix que el joystick dret pugui navegar pels menús." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, "El menú inverteix els botons d'OK i Cancel·la" @@ -3314,6 +3623,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BLOCK_DELAY, "Retard de l'activació de les dreceres de teclat (fotogrames)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BLOCK_DELAY, + "Afegeix un retard en fotogrames abans que l'entrada normal es bloquegi després de polsar la tecla 'Activa dreceres de teclat' assignada. Permet que es capturi l'entrada normal de la tecla 'Activa dreceres de teclat' quan es mapeja a una altra acció (ex. Selecciona al RetroPad)." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_DEVICE_MERGE, + "Fusionar tipus de dispositiu per a tecles ràpides" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, "Commuta el menú (combinació de botons)" @@ -3328,7 +3645,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Canvia la visualització actual entre el menú i el contingut en execució." + "Alterna entre mostrar el menú o el contingut." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, + "Sortir (combinació de botons)" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_QUIT_GAMEPAD_COMBO, @@ -3346,6 +3667,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_CLOSE_CONTENT_KEY, "Tanca contingut" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_CLOSE_CONTENT_KEY, + "Tanca el contingut actual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, "Resetejant el contingut" @@ -3390,18 +3715,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, "Rebobina" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_REWIND_HOTKEY, + "Rebobina el contingut actual mentre es polsa la tecla. Ha d'estar activat 'Suporta rebobinat'." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "Fer pausa" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Canvia entre estats de pausa i no pausa del contingut executat." + "Alterna entre aturar o reprendre el contingut." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, "Avançar fotograma" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_FRAMEADVANCE, + "Avança un fotograma el contingut en pausar." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, @@ -3432,19 +3765,39 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, "Carrega estat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_LOAD_STATE_KEY, + "Carrega un estat desat de la posició actualment seleccionada." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, "Desa estat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_SAVE_STATE_KEY, + "Desa un estat a la posició actualment seleccionada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, + "Següent ranura de desat" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STATE_SLOT_PLUS, "Incrementa l'índex de la posició de l'estat desat que està seleccionat actualment." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, + "Posició anterior de desat ràpid" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STATE_SLOT_MINUS, "Disminueix l'índex de la posició de l'estat desat que està seleccionat actualment." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, + "Expulsa el disc (alternar)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_DISK_EJECT_TOGGLE, "I una safata virtual de disc es troba tancada, l'obre i elimina el disc carregat. Altrament, insereix el disc seleccionat actualment i tanca la safata." @@ -3453,11 +3806,27 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, "Disc Següent" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_DISK_NEXT, + "Incrementa l'índex del disc seleccionat actualment. La safata de disc virtual ha d'estar oberta." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, "Disc Anterior" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_DISK_PREV, + "Disminueix l'índex del disc seleccionat actualment. La safata de disc virtual ha d'estar oberta." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_TOGGLE, + "Shaders (Alternar)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_SHADER_TOGGLE, + "Activa o desactiva el shader seleccionat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, "Següent shader" @@ -3528,10 +3897,50 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, "Reproduir repetició" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_PLAY_REPLAY_KEY, + "Reprodueix el fitxer de repetició des de la posició seleccionada." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, "Enregistrar la repetició" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_RECORD_REPLAY_KEY, + "Enregistra un fitxer de repetició a la posició seleccionada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, + "Atura l'enregistrament/repetició" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_HALT_REPLAY_KEY, + "Atura la gravació/reproducció de la repetició actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, + "Següent posició de repetició" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_PLUS, + "Augmenta l'índex de la posició de la repetició seleccionada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, + "Ranura prèvia de desat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, + "Disminueix l'índex de la posició de la repetició seleccionada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Pulsació de turbo (alternar)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Alterna el mode d'activació del turbo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Agafa el Ratolí (commuta)" @@ -3577,6 +3986,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE, "Canvia a activat/desactivat l'anticipació." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE, + "Fes servir fotogrames preventius (alternar)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_PREEMPT_TOGGLE, + "Activa o desactiva el sistema de fotogrames preventius." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE, @@ -3594,6 +4011,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STATISTICS_TOGGLE, "Canvia entre activada/desactivada la visualització en pantalla de les estadístiques tècniques." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, + "Superposició de teclat (alternar)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_OSK, + "Activa o desactiva la superposició del teclat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, "Següent Superposició" @@ -3607,6 +4032,10 @@ MSG_HASH( "Servei d'IA" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_PING_TOGGLE, + "Latència en el joc en xarxa (alternar)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_NETPLAY_PING_TOGGLE, "Canvia entre activat/desactivat el comptador de ping de l'habitació de netplay actual." @@ -3635,6 +4064,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_NETPLAY_PLAYER_CHAT, "Envia un missatge de xat a la sessió actual de netplay." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FADE_CHAT_TOGGLE, + "Amaga el xat del joc en xarxa (alternar)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_NETPLAY_FADE_CHAT_TOGGLE, "Canvia entre els missatges de xat estàtics o esvaïts." @@ -3655,6 +4088,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, "Tipus de dispositiu" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DEVICE_TYPE, + "Específica el tipus de controlador a emular." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, "Tipus d’analògic a digital" @@ -3663,6 +4100,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, "Índex del dispositiu" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DEVICE_INDEX, + "El controlador físic tal qual el reconeix RetroArch." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_RESERVED_DEVICE_NAME, + "Dispositiu reservat per aquest jugador" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DEVICE_RESERVED_DEVICE_NAME, + "Aquest controlador serà assignat a aquest jugador seguint el mode de reserva." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_NONE, "Sense reserva" @@ -3675,10 +4124,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_RESERVED, "Reservat" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_RESERVATION_TYPE, + "Tipus de reserva del dispositiu" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_REMAP_PORT, "Port assignat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_REMAP_PORT, + "Especifica quin dels ports del nucli rebrà els senyals d'entrada del port del comandament %u." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, "Configura tots els controls" @@ -3687,6 +4144,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, "Restableix els controls per defecte" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_DEFAULTS, + "Restableix la configuració de les assignacions als valors predeterminats." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, "Desa el perfil de controlador" @@ -3695,6 +4156,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, "Índex del ratolí" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_MOUSE_INDEX, + "El ratolí físic tal qual el reconeix RetroArch." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, "Botó B (avall)" @@ -3860,6 +4325,18 @@ MSG_HASH( ) #if !(defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)) #endif +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUNAHEAD_MODE_SINGLE_INSTANCE, + "Mode d'instància única" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUNAHEAD_MODE_SECOND_INSTANCE, + "Mode de doble instància" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUNAHEAD_MODE_PREEMPTIVE_FRAMES, + "Mode de fotogrames preventius" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RUN_AHEAD_HIDE_WARNINGS, "Amagar avisos de la reducció predictiva" @@ -3868,6 +4345,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS, "Amaga el missatge d'avís que es mostra a l'usar la reducció predictiva de latència si el nucli no es compatible amb els desats ràpids." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PREEMPT_FRAMES, + "Nombre de fotogrames preventius" + ) /* Settings > Core */ @@ -3919,7 +4400,15 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_CACHE_ENABLE, "Memòria cau d'arxius d'informació de nuclis" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, + "Ometent la informació del nucli sobre desats ràpids" + ) #ifndef HAVE_DYNAMIC +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, + "Recarrega sempre el nucli en executar contingut" + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, @@ -3935,6 +4424,10 @@ MSG_HASH( "Gestionar nuclis" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_MANAGER_STEAM_LIST, + "Instal·la o desinstal·la nuclis distribuïts a través de Steam." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_STEAM_INSTALL, @@ -3946,19 +4439,147 @@ MSG_HASH( "Desinstal·lar un nucli" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_MANAGER_STEAM, + "Mostra 'Administrar nuclis'" +) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_MANAGER_STEAM, "Mostra l’opció «Gestiona els nuclis» al menú principal." ) +MSG_HASH( + MSG_CORE_STEAM_INSTALLING, + "Instal·lant el nucli: " +) +MSG_HASH( + MSG_CORE_STEAM_UNINSTALLED, + "El nucli serà desinstal·lat quan es tanqui RetroArch." +) +MSG_HASH( + MSG_CORE_STEAM_CURRENTLY_DOWNLOADING, + "El nucli s'està descarregant ara mateix" +) #endif /* Settings > Configuration */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, + "Desa la configuració en sortir" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, + "S'han desat els canvis al fitxer de configuració en tancar RetroArch." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_SAVE_ON_EXIT, + "Desa els fitxers d'assignació en sortir" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_SAVE_ON_EXIT, + "Desa els canvis de qualsevol fitxer d'assignació d'entrada actiu en tancar un contingut o en sortir de RetroArch." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, + "Carrega automàticament les opcions del nucli pel contingut" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, + "Carrega les opcions personalitzades del nucli per defecte en iniciar." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, + "Carrega els fitxers de personalització automàticament" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, + "Carrega la configuració personalitzada en arrancar." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, + "Carrega automàticament fitxers de remapeig" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, + "Carrega els controls personalitzats a l'inici." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INITIAL_DISK_CHANGE_ENABLE, + "Carrega automàticament els fitxers d'índexs de disc inicial" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INITIAL_DISK_CHANGE_ENABLE, + "En executar contingut de diversos dics, es carregarà l'últim disc utilitzat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, + "Carrega els fitxers de shaders automàticament" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GLOBAL_CORE_OPTIONS, + "Fes servir el fitxer global d'opcions del nucli" + ) /* Settings > Saving */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, + "Endreça els fitxers desats per carpetes amb el nom del nucli" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, + "Endreça els fitxers desats en carpetes que continguin el nom del nucli." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, + "Ordena els estats desats en carpetes amb el nom del nucli" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, + "Ordena els estats desats en carpetes amb el nom del nucli utilitzat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_BY_CONTENT_ENABLE, + "Endreça els fitxers desats per carpetes amb el nom del contingut" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SORT_SAVEFILES_BY_CONTENT_ENABLE, + "Endreça els fitxers de desat mitjançant carpetes amb els noms on es troba el contingut." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_BY_CONTENT_ENABLE, + "Endreça els estats desats en carpetes amb el nom del contingut" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SORT_SAVESTATES_BY_CONTENT_ENABLE, + "Endreça els desats ràpids mitjançant carpetes amb el nom on es troba el contingut." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, + "No sobreescriguis la SaveRAM en carregar un desat ràpid" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, + "Interval entre desats automàtics de la SaveRAM" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, + "Desa automàticament la SaveRAM no volàtil a intervals marcats (en segons)." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REPLAY_CHECKPOINT_INTERVAL, + "Interval de punts de control de repetició" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, + "Augmenta automàticament l'índex de l'estat desat" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REPLAY_AUTO_INDEX, + "Augmenta automàticament l'índex de repeticions" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_MAX_KEEP, "Màxim de desats ràpids autoincrementats a mantenir" @@ -3967,13 +4588,17 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_MAX_KEEP, "Limita el nombre de desats ràpids que es crearan quan s’habiliti l’opció «Incrementa l’índex de desat ràpid automàticament». Si se sobrepassa el límit quan es crea un nou desat ràpid s’esborrarà el desat ràpid amb l'índex més baix. Un valor de «0» significa que es crearan desats ràpids sense límit." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REPLAY_MAX_KEEP, + "Nombre màxim de repeticions automàtiques a conservar" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Desat ràpid automàtic" ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Crea un desat ràpid automàticament quan es tanca el contingut. El RetroArch carregarà automàticament aquest desat ràpid si l’opció «Carrega el desat ràpid automàticament» està activada." + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, + "Carrega estat automàticament" ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, @@ -4015,18 +4640,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, "Desa les partides al directori del contingut" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE, + "Fes servir la carpeta de continguts com a carpeta per desar fitxers." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, "Desa els estats al directori del contingut" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATES_IN_CONTENT_DIR_ENABLE, + "Fes servir la carpeta de contingut com a carpeta d'estats desats." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, "Els fitxers de sistema són al directori del contingut" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "Fes servir la carpeta de contingut com a carpeta pel Sistema/BIOS." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, "Desa les captures al directori del contingut" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + "Fes servir la carpeta de contingut com a carpeta de captures de pantalla." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_RUNTIME_LOG, "Desa un registre de temps d’execució (per nucli)" @@ -4109,6 +4750,42 @@ MSG_HASH( /* Settings > File Browser */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, + "Mostra fitxers i carpetes ocults" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, + "Mostra fitxers ocults i carpetes ocultes en l'explorador de fitxers." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Filtrar extensions desconegudes" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Mostra només fitxers que tinguin extensions conegudes a l'explorador de fitxers." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "Filtra pel nucli actual" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtra els fitxers que es mostren a l'explorador de fitxers pel nucli actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, + "Recorda l'última carpeta on has desat" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Fes servir el reproductor integrat" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Fes servir el visualitzador d’imatges integrat" + ) /* Settings > Frame Throttle */ @@ -4116,10 +4793,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, "Rebobina" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_REWIND, + "Canvia la configuració del rebobinat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_SETTINGS, + "Comptador de duració dels fotogrames" + ) MSG_HASH( MENU_ENUM_SUBLABEL_FRAME_TIME_COUNTER_SETTINGS, "Canvia les opcions del comptador de duració de fotogrames.\nNomés en funcionament quan estigui desactivat el vídeo multifil." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, + "Taxa d'avançament ràpid" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FASTFORWARD_FRAMESKIP, + "Omet fotogrames en l'avançament ràpid" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, + "Velocitat de càmera lenta" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, + "Ajusta la velocitat a la qual es reprodueix el contingut si es fa servir càmera lenta." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, "Limita la velocitat de fotogrames al menú" @@ -4139,6 +4840,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY, "Rebobinar fotogrames" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, + "El nombre de fotogrames a rebobinar en cada pas. Valors alts augmenten la velocitat de rebobinat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE, + "Mida de la memòria intermèdia del rebobinat (MB)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE_STEP, + "Mida de la memòria intermèdia dels passos de rebobinat (MB)" + ) /* Settings > Frame Throttle > Frame Time Counter */ @@ -4146,17 +4859,33 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_RESET_AFTER_FASTFORWARDING, "Reiniciar després d'utilitzar l'avançament ràpid" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FRAME_TIME_COUNTER_RESET_AFTER_FASTFORWARDING, + "Reinicia el comptador de duració de fotogrames després d'un avançament ràpid." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_RESET_AFTER_LOAD_STATE, "Reiniciar després de carregar un desat ràpid" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FRAME_TIME_COUNTER_RESET_AFTER_LOAD_STATE, + "Reinicia el comptador de duració de fotogrames després de carregar un estat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_RESET_AFTER_SAVE_STATE, "Reiniciar després de generar un desat ràpid" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FRAME_TIME_COUNTER_RESET_AFTER_SAVE_STATE, + "Reinicia el comptador de duració de fotogrames després de desar un estat." + ) /* Settings > Recording */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_QUALITY, + "Qualitat de l'enregistrament" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_CONFIG_TYPE_RECORDING_CUSTOM, "Personalitzat" @@ -4181,10 +4910,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST, "WebM (ràpida)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_CONFIG_TYPE_RECORDING_WEBM_HIGH_QUALITY, + "Alta qualitat WebM" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, + "Configuració personalitzada de gravació" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_THREADS, + "Fils per a l'enregistrament" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, + "Grava amb els filtres aplicats" + ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, "Captura la imatge després d'aplicar els filtres (però no els shaders). El vídeo es veurà tan elegant com el veieu a la pantalla." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, + "Fes servir l'enregistrament per GPU" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_GPU_RECORD, + "Enregistra la sortida de la GPU amb shaders, si està disponible." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STREAMING_MODE, "Mode de retransmissió" @@ -4193,6 +4946,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_STREAMING_MODE_CUSTOM, "Personalitzat" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_STREAM_QUALITY, + "Qualitat de la retransmissió" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_CONFIG_TYPE_STREAMING_CUSTOM, "Personalitzat" @@ -4209,6 +4966,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_CONFIG_TYPE_STREAMING_HIGH_QUALITY, "Alt" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STREAM_CONFIG, + "Configuració personalitzada de retransmissió" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STREAMING_TITLE, "Emetre títol" @@ -4217,6 +4978,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_STREAMING_URL, "URL de transmissió" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UDP_STREAM_PORT, + "Port de transmissió UDP" + ) /* Settings > On-Screen Display */ @@ -4224,10 +4989,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, "Superposició en Pantalla" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_OVERLAY_SETTINGS, + "Ajustant els marcs i els controls en pantalla." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ONSCREEN_VIDEO_LAYOUT_SETTINGS, "Disposició del vídeo" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_VIDEO_LAYOUT_SETTINGS, + "Ajusta la disposició de vídeo." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, + "Notificacions en pantall" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, + "Configura les notificacions en pantalla." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS, + "Visibilitat de les notificacions" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS, + "Canvia la visibilitat de determinades notificacions." + ) /* Settings > On-Screen Display > On-Screen Overlay */ @@ -4282,6 +5071,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_INPUTS_TOUCHED, "Tàctil" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_INPUTS_PHYSICAL, + "Físic (Controlador)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_INPUTS_PORT, + "Mostra les tecles polsades del port" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_INPUTS_PORT, "Selecciona el port del dispositiu d'entrada a monitorar quan s'estableix 'Mostra les Entrades a la Superposició' a 'Físic (controlador)'." @@ -4310,6 +5107,30 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_AUTO_SCALE, "Ajusta automàticament l'escala de la superposició i de l'espaiat dels elements de la IU per coincidir la relació d'aspecte amb l'orientació de la pantalla. Produeix els millors resultats amb superposicions de controladors." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY, + "Sensibilitat diagonal de la creueta" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY, + "Ajusta la mida de les zones diagonals. Per tenir una simetría en les 8 direccions, selecciona 100%." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, + "Sensibilitat de la sobreposició ABXY" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, + "Ajusta la mida de les zones superposades en el bloc dels botons d'acció. Per obtenir una simetria en les 8 direccions, selecciona el 100%." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Zona de centrat dels gatells analògics" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "El senyal d'entrada dels joysticks analògics serà relativa a la posició del primer clic si es fa dins d'aquesta zona." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Superposició" @@ -4330,14 +5151,94 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, "Superposició predefinida" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_PRESET, + "Selecciona una superposició en l'explorador de fitxers." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE_LANDSCAPE, + "Escala de superposició (mode horitzontal)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_SCALE_LANDSCAPE, + "Dimensiona els elements de la interfície d'usuari quan es fa servir una orientació horitzontal de la pantalla." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_ASPECT_ADJUST_LANDSCAPE, + "Relació d'aspecte de la superposició (mode horitzontal)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_OVERLAY_ASPECT_ADJUST_LANDSCAPE, "Aplica un factor de correcció de la relació d’aspecte a la superposició quan la pantalla està orientada horitzontalment. Els valors positius augmenten l’amplada efectiva de la superposició mentre que els negatius la redueixen." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_X_SEPARATION_LANDSCAPE, + "Separació horitzontal de superposició (mode horitzontal)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_Y_SEPARATION_LANDSCAPE, + "Separació vertical de superposició (mode horitzontal)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_X_OFFSET_LANDSCAPE, + "Desplaçament X de superposició (mode horitzontal)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_Y_OFFSET_LANDSCAPE, + "Desplaçament Y de superposició (mode horitzontal)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE_PORTRAIT, + "Escala de la superposició (mode vertical)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_SCALE_PORTRAIT, + "Dimensiona els elements de la interfície d'usuari quan es fa servir una orientació vertical de la pantalla." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_ASPECT_ADJUST_PORTRAIT, + "Relació d'aspecte de superposició (Mode vertical)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_OVERLAY_ASPECT_ADJUST_PORTRAIT, "Aplica un factor de correcció de la relació d’aspecte a la superposició quan la pantalla està orientada verticalment. Els valors positius augmenten l’alçada efectiva de la superposició mentre que els negatius la redueixen." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_X_SEPARATION_PORTRAIT, + "Separació vertical de superposició (mode vertical)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_Y_SEPARATION_PORTRAIT, + "Separació vertical de superposició (mode vertical)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_X_OFFSET_PORTRAIT, + "Desplaçament X de superposició (mode vertical)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_Y_OFFSET_PORTRAIT, + "Desplaçament Y de superposició (mode vertical)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_SETTINGS, + "Superposició de teclat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OSK_OVERLAY_SETTINGS, + "Selecciona i ajusta una superposició de teclat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_POINTER_ENABLE, + "Activa la superposició per lightgun, ratolí i punter" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_LIGHTGUN_SETTINGS, + "Superposa la pistola de llum" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_LIGHTGUN_SETTINGS, + "Configura l'entrada de la pistola de llum enviada a través de la superposició." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_MOUSE_SETTINGS, "Superposa el ratolí" @@ -4345,6 +5246,30 @@ MSG_HASH( /* Settings > On-Screen Display > On-Screen Overlay > Keyboard Overlay */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_PRESET, + "Ajustament de la superposició del teclat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OSK_OVERLAY_PRESET, + "Selecciona una superposició de teclat en l'explorador de fitxers." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OSK_OVERLAY_AUTO_SCALE, + "Escala automàticament la posició del teclat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OSK_OVERLAY_AUTO_SCALE, + "Ajusta la superposició de teclat a la relació d'aspecte original. Desactiva aquesta opció per estirar el teclat per tota la pantalla." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_OPACITY, + "Opacitat del teclat superposat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OSK_OVERLAY_OPACITY, + "Opacitat dels elements de la interfície de la superposició de teclat." + ) /* Settings > On-Screen Display > On-Screen Overlay > Overlay Lightgun */ @@ -4352,10 +5277,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_PORT, "Port de la pistola de llum" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_PORT, + "Selecciona el port del nucli que rebrà les accions d'entrada de la pistola de llum." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_PORT_ANY, "Qualsevol" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_TRIGGER_ON_TOUCH, + "Dispara en tocar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_TRIGGER_ON_TOUCH, + "Envia un senyal del joystick en conjunt a la del punter." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_TRIGGER_DELAY, + "Retard en el tret (fotogrames)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_TWO_TOUCH_INPUT, "Entrada de 2 dits" @@ -4368,6 +5309,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_FOUR_TOUCH_INPUT, "Entrada de 4 dits" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_ALLOW_OFFSCREEN, + "Permet apuntar fora de la pantalla" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_ALLOW_OFFSCREEN, + "Permet apuntar fora dels límits de la pantalla. Desactiva aquesta opció per limitar l'apuntat a la vora de la pantalla." + ) /* Settings > On-Screen Display > On-Screen Overlay > Overlay Mouse */ @@ -4375,28 +5324,160 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_SPEED, "Velocitat del ratolí" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_SPEED, + "Ajusta la velocitat del ratolí." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_HOLD_TO_DRAG, + "Mantén polsat per arrossegar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_HOLD_TO_DRAG, + "Fes un clic llarg a la pantalla per mantenir clicat el botó." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_HOLD_MSEC, + "Llindar de la pulsació llarga (ms)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_HOLD_MSEC, + "Ajusta el temps necessari per considerar una pulsació llarga." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_DTAP_TO_DRAG, + "Doble toc per arrossegar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_DTAP_MSEC, + "Llindar de la doble pulsació (ms)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_DTAP_MSEC, + "Ajusta el marge de temps entre clics pel qual es detectarà un doble clic." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_SWIPE_THRESHOLD, + "Llindar de lliscament" + ) /* Settings > On-Screen Display > Video Layout */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_ENABLE, + "Activa la disposició de vídeo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_LAYOUT_ENABLE, + "Les disposicions de vídeo es fan servir per posar marcs i altres imatges." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_PATH, + "Ruta de les disposicions del vídeo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_LAYOUT_PATH, + "Selecciona una disposició de vídeo des de l'explorador de fitxers." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_SELECTED_VIEW, "Seleccionar la vista" ) +MSG_HASH( /* FIXME Unused */ + MENU_ENUM_SUBLABEL_VIDEO_LAYOUT_SELECTED_VIEW, + "Selecciona una vista de la disposició carregada." + ) /* Settings > On-Screen Display > On-Screen Notifications */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, + "Notificacions en pantall" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, + "Mostra missatges en pantalla." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WIDGETS_ENABLE, + "Ginys gràfics" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WIDGETS_ENABLE, + "Utilitza animacions, notificacions, indicacions i controls decoratius." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WIDGET_SCALE_AUTO, + "Escalar widgets gràfics automàticament" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_WIDGET_SCALE_AUTO, "Canvia automàticament la mida de les notificacions decorades, indicadors i controls segons l’escala actual del menú." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WIDGET_SCALE_FACTOR_FULLSCREEN, + "Personalitza l'escala dels widgets gràfics (pantalla completa)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_WIDGET_SCALE_FACTOR_FULLSCREEN, "Força un factor d’escalat manual quan es dibuixen ginys de visualització en mode de pantalla completa. Només s’aplica quan l’opció «Escala automàticament els ginys gràfics» està desactivada. Es pot fer servir per augmentar o disminuir la mida de les notificacions decorades, indicadors i controls independentment del menú." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WIDGET_SCALE_FACTOR_WINDOWED, + "Personalitza l'escala dels widgets gràfics (finestra)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_WIDGET_SCALE_FACTOR_WINDOWED, "Força un factor d’escalat manual quan es dibuixen ginys de visualització en mode de finestra. Només s’aplica quan l’opció «Escala automàticament els ginys gràfics» està desactivada. Es pot fer servir per augmentar o disminuir la mida de les notificacions decorades, indicadors i controls independentment del menú." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FPS_SHOW, + "Mostra la velocitat de fotogrames" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FPS_SHOW, + "Mostra el nombre actual de fotogrames per segon." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FPS_UPDATE_INTERVAL, + "Interval d'actualització de fotogrames (en fps)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FPS_UPDATE_INTERVAL, + "El comptador de fotogrames en pantalla s'actualitzarà a la velocitat assignada en fotogrames." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRAMECOUNT_SHOW, + "Mostra el comptador de fotogrames" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FRAMECOUNT_SHOW, + "Mostra en pantalla el comptador de fotogrames." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STATISTICS_SHOW, + "Mostra les estadístiques" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STATISTICS_SHOW, + "Mostrar les estadístiques tècniques en pantalla." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MEMORY_SHOW, + "Mostrar l'ús de la memòria " + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MEMORY_SHOW, + "Mostra la quantitat de memòria que es fa servir i la memòria total del sistema." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MEMORY_UPDATE_INTERVAL, + "Interval d'actualització de l'ús de memòria (en fotogrames)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MEMORY_UPDATE_INTERVAL, + "El comptador de memòria en pantalla s'actualitzarà a la velocitat assignada a fotogrames." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_PING_SHOW, "Mostra el ping del joc en línia" @@ -4405,10 +5486,86 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_PING_SHOW, "Mostra el ping de la sala de joc en línia actual." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CONTENT_ANIMATION, + "Notificació d'inici en carregar contingut" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CONTENT_ANIMATION, + "Mostra una breu animació per indicar que s'ha iniciat un contingut." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, + "Notificacions de connexions d'entrada (configuració automàtica)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Notificacions dels errors d'entrada (autoconfiguració)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, + "Notificacions dels trucs" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_CHEATS_APPLIED, + "Mostra un missatge en pantalla en aplicar trucs." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_PATCH_APPLIED, + "Notificacions de correccions" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_PATCH_APPLIED, + "Mostra un missatge en pantalla al corregir ROM al vol." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, + "Mostra un missatge en pantalla quan es connectin o desconnectin dispositiu d'entrada." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Mostra un missatge en pantalla quan el dispositiu d'entrda no es pot configurar." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, + "Notificacions de la càrrega de reassignacions d'entrada" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_REMAP_LOAD, + "Mostra un missatge en pantalla en carregar fitxers d'assignació d'entrada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD, + "Notificacions de càrrega de configuracions personalitzades" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD, + "Mostra un missatge en pantalla en carregar fitxers de configuració." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_SET_INITIAL_DISK, + "Notificacions en restaurar un disc d'inci" + ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_SET_INITIAL_DISK, "Mostra un missatge en pantalla quan restableix automàticament a l’arrencada el darrer disc usat d’un contingut multidisc carregat mitjançant llistes M3U." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_DISK_CONTROL, + "Notificacions de control de disc" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_DISK_CONTROL, + "Mostra un missatge en pantalla en inserir o extreure discs." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_SAVE_STATE, + "Notificacions dels estat desats" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_SAVE_STATE, + "Mostra un missatge en pantalla en desar i carregar desats ràpids." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_FAST_FORWARD, "Notificacions d’avanç ràpid" @@ -4497,50 +5654,86 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "Mida de les notificacions" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Especifica la mida de la lletra en punts." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, "Posició de les notificacions (horitzontal)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, + "Especifica una posició x personalitzada del text en pantalla respecte a l'eix X. 0 és la vora esquerra." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, "Posició de les notificacions (vertical)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, + "Especifica una posició personalitzada del text en pantalla respecte a l'eix Y. 0 és la vora inferior." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_RED, "Color de les notificacions (vermell)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_COLOR_RED, + "Ajusta el valor del vermell del color del text en els missatges en pantalla. Els valors vàlids són de 0 a 255." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_GREEN, "Color de les notificacions (verd)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_COLOR_GREEN, + "Ajusta el valor del verd del color del text en els missatges en pantalla. Els valors vàlids són de 0 a 255." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_COLOR_BLUE, "Color de les notificacions (blau)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_COLOR_BLUE, + "Ajusta el valor del blau del color del text en els missatges en pantalla. Els valors vàlids són de 0 a 255." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_ENABLE, "Fons de les notificacions" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_BGCOLOR_ENABLE, + "Activa un color de fons pels missatges en pantalla." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_RED, "Color de fons de les notificacions (vermell)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_BGCOLOR_RED, + "Ajusta el valor del vermell del fons dels missatges en pantalla. Els valors vàlids són de 0 a 255." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_GREEN, "Color de fons de les notificacions (verd)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_BGCOLOR_GREEN, + "Ajusta el valor del verd del fons dels missatges en pantalla. Els valors vàlids són de 0 a 255." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_BLUE, "Color de fons de les notificacions (blau)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_BGCOLOR_BLUE, + "Ajusta el valor del blau del fons dels missatges en pantalla. Els valors vàlids són de 0 a 255." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_OPACITY, "Opacitat del fons de les notificacions" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_BGCOLOR_OPACITY, + "Ajusta l'opacitat del fons dels missatges en pantalla. Els valors vàlids estan entre 0,0 i 1,0." + ) /* Settings > User Interface */ @@ -4564,7 +5757,19 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_APPICON_SETTINGS, "Icona de l'Aplicació" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_APPICON_SETTINGS, + "Canvia la icona de l'aplicació." + ) #ifdef _3DS +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_BOTTOM_SETTINGS, + "Aparença de la pantalla inferior de 3DS" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_BOTTOM_SETTINGS, + "Canvia l'ajustament de l'aparença de la pantalla inferior." + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, @@ -4578,6 +5783,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_ENABLE_KIOSK_MODE, "Mode Quiosc" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_ENABLE_KIOSK_MODE, + "Protegeix la configuració amagant la configuració relacionada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_KIOSK_MODE_PASSWORD, + "Estableix una contrasenya per desactivar el mode quiosc" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, + "Navegació en bucle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, + "Posa en pausa el contingut quan el menú estigui actiu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, + "Pausa el contingut si el menú està actiu." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, "Reprendre contingut després d'utilitzar un desat ràpid" @@ -4586,6 +5811,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_INSERT_DISK_RESUME, "Reprendre contingut al canviar de disc" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_INSERT_DISK_RESUME, + "Tanca el menú i reprèn el contingut automàticament després d'inserir o carregar un nou disc." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUIT_ON_CLOSE_CONTENT, + "Surt en tancar el contingut" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_TIMEOUT, + "Temps d'espera de l'estalvi de pantalla del menú" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION, + "Animació de l'estalvi de pantalla del menú" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SCREENSAVER_ANIMATION, "Habilita un efecte d’animació mentre l’estalvi de pantalla del menú està actiu. Afecta moderadament el rendiment." @@ -4650,6 +5891,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, "Els gestors de finestres usen la composició per aplicar efectes visuals i detectar finestres que no responen, entre altres coses." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DISABLE_COMPOSITION, + "Força la desactivació de la composició. Només funciona per Windows Vista o Windows 7." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SCROLL_FAST, "Acceleració del desplaçament del menú" @@ -4666,6 +5911,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SCROLL_DELAY, "Retard inicial en mil·lisegons quan es manté una direcció per desplaçar." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, + "Executa la interfície d'usuari en iniciar" + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_UI_COMPANION_START_ON_BOOT, + "Inicia el controlador de l'assistent de la interfície en iniciar (si està disponible)." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DESKTOP_MENU_ENABLE, + "Menú d'escriptori (Es requereix reinici)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UI_COMPANION_TOGGLE, "Obre el menú d’escriptori a l’inici" @@ -4799,6 +6056,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS, "Mostra 'Opcions'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, + "Mostra el menú 'Configuració'. (Es requereix reiniciar per Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS_PASSWORD, "Establir contrasenya per activar la secció 'Opcions'" @@ -4807,30 +6068,62 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS_PASSWORD, "Estableix una contrasenya per ocultar la pestanya 'Opcions', permetent restaurar-la des del menú principal seleccionant 'Mostrar la pestanya d'Opcions' i introduint la contrasenya." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_FAVORITES, + "Mostra «Favorits»" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, + "Mostra el menú 'Preferits'. (Es requereix reiniciar per Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, "Mostrar Imatges" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, + "Mostra el menú 'Imatges'. (Es requereix reiniciar per Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, "Mostrar 'Música'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, + "Mostra el menú 'Música' (Es requereix reiniciar a Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, "Mostra «Vídeos»" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, + "Mostra el menú 'Vídeos'. (Es requereix reiniciar per Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, "Mostra «Joc en línia»" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, + "Mostra el menú 'Joc en xarxa'. (Es requereix reiniciar per Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, "Mostra «Historial»" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, + "Mostra l'historial d'elements recents (Es requereix reiniciar per Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, "Mostra «Importa contingut»" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, + "Mostra el menú 'Importar contingut'. (Es requereix reiniciar per Ozone/XMB)" + ) MSG_HASH( /* FIXME can now be replaced with MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD */ MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD_ENTRY, "Mostra «Importa contingut»" @@ -4851,10 +6144,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, "Mostra «Llistes de reproducció»" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, + "Mostra les llistes de reproducció en el menú principal. S'ignorarà aquesta opció a GLUI si s'activen les seccions de la llista de reproducció i de la barra de navegació." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Mostra les pestanyes de les llistes de reproducció" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, "Mostra «Explora»" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_EXPLORE, + "Mostra l'opció de l'explorador de continguts (És necessari reiniciar a Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_CONTENTLESS_CORES, "Mostra «Nuclis sense continguts»" @@ -4958,6 +6263,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CLOSE_CONTENT, "Mostra l’opció “Tanca el contingut”." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVESTATE_SUBMENU, + "Mostra el submenú de desat ràpid" + ) MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVESTATE_SUBMENU, "Mostra les opcions de desat ràpid en un submenú." @@ -4970,6 +6279,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, "Mostra les opcions per desar o carregar estats." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_REPLAY, + "Mostra els controls de repetició" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_REPLAY, + "Mostra les opcions per enregistrar o reproduir fitxers de repetició." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, "Mostra “Desfés el desament/càrrega d’estat”" @@ -5054,14 +6371,42 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_REWIND, "Mostra «Rebobina»" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, + "Mostra l'opció 'Rebobinar'." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, "Mostra «Desa els nuclis forçats»" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, + "Mostra l'opció 'Desar personalitzacions del nucli' dins del menú Personalitzacions." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_CONTENT_DIR_OVERRIDES, + "Mostra l'opció 'Desar la personalització de carpetes de continguts'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CONTENT_DIR_OVERRIDES, + "Mostra l'opció 'Desa la personalització de les carpetes de contingut' dins del menú Personalitzacions." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, + "Mostra desar les personalitzacions del joc" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, + "Mostra l'opció 'Desar personalitzacions del nucli' dins del menú Personalitzacions." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CHEATS, "Mostrar trucs" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CHEATS, + "Mostra l'opció 'Trucs'." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SHADERS, "Mostrar Shaders" @@ -5072,11 +6417,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_FAVORITES, - "Mostra “Afegeix als preferits”" + "Mostra «Afegeix als favorits»" ) MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, - "Mostra l’opció “Afegeix als preferits”." + "Mostra l’opció «Afegeix als favorits»." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_PLAYLIST, + "Mostra afegir a una llista de reproducció" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_PLAYLIST, + "Mostra l'opció 'Afegir a una llista de reproducció'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SET_CORE_ASSOCIATION, @@ -5193,27 +6546,111 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_FILE_BROWSER, "Mostra les opcions de «Navegador de fitxers»." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_FRAME_THROTTLE, + "Mostra 'Regulació de fotogrames'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_FRAME_THROTTLE, + "Mostra la configuració de 'Regulació de fotogrames'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_RECORDING, + "Mostra «Enregistrament»" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_RECORDING, + "Mostra la configuració d'enregistrament." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_ONSCREEN_DISPLAY, + "Mostra 'Presentació en pantalla'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_ONSCREEN_DISPLAY, + "Mostra l'opció 'Visualització en pantalla'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER_INTERFACE, + "Mostrar 'Interfície d'usuari'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER_INTERFACE, + "Mostra la configuració 'Interfície d'usuari'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_AI_SERVICE, + "Mostra «Servei d'IA»" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_AI_SERVICE, + "Mostra la configuració de 'Servei AI'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_ACCESSIBILITY, + "Mostra 'Accesibilitat'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_ACCESSIBILITY, + "Mostra la configuració d'accessibilitat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_POWER_MANAGEMENT, + "Mostra 'Administració d'energia'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_POWER_MANAGEMENT, + "Mostra la configuració de 'Gestió energia'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_ACHIEVEMENTS, + "Mostra 'Assoliments'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_ACHIEVEMENTS, + "Mostra la configuració dels assoliments." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_NETWORK, "Mostrar Xarxa" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_NETWORK, + "Mostra la configuració de xarxa." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_PLAYLISTS, "Mostra «Llistes de reproducció»" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_PLAYLISTS, + "Mostra la configuració de les llistes de reproducció." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Mostrar 'Usuari'" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Icones de les llistes de reproducció" + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, + "Mostra 'Configuració d'usuari'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_DIRECTORY, + "Mostra «Directori»" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_DIRECTORY, + "Mostra la configuració de les carpetes." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_STEAM, "Mostrar 'Steam'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SETTINGS_SHOW_STEAM, + "Mostra la configuració de Steam." + ) /* Settings > User Interface > Appearance */ @@ -5221,10 +6658,70 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SCALE_FACTOR, "Factor d'escala" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SCALE_FACTOR, + "Escala la mida dels elements de la interfície d'usuari en el menú." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, + "Imatge de fons" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, + "Opacitat del fons" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, + "Modifica l'opacitat de la imatge de fons." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_FRAMEBUFFER_OPACITY, "Opacitat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_FRAMEBUFFER_OPACITY, + "Modifica l'opacitat de fons del menú." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, + "Fes servir el tema de colors del sistema" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, + "Fes servir el tema de color del sistema operatiu (si n'hi ha). S'ignoraran la configuració del tema." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAILS, + "Miniatura principal" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THUMBNAILS, + "Tipus de miniatures que es mostrarà." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_THUMBNAIL_UPSCALE_THRESHOLD, + "Llindar d'escalat de miniatures" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_TICKER_TYPE, + "Animació de text en moviment" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_TICKER_TYPE, + "Selecciona el mètode desplaçament horitzontal pels texts del menú que siguin molt llargs." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_TICKER_SPEED, + "Velocitat dels texts en moviment" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_TICKER_SPEED, + "La velocitat de l'animació del text en moure's en el menú." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_TICKER_SMOOTH, + "Suavitza el textos en moviment" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_REMEMBER_SELECTION, "Recordar selecció al canviar entre seccions" @@ -5454,10 +6951,102 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SETTINGS, "Visibilitat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_SETTINGS, + "Canvia quins missatges i elements de pantalla es mostraran. Aquesta opció no desactiva la funcionalitat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SUMMARY, + "Resum d'inici" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SUMMARY_ALLGAMES, + "Tots els jocs identificats" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SUMMARY_HASCHEEVOS, + "Jocs amb assoliments" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_UNLOCK, + "Desbloqueja les notificacions" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_UNLOCK, + "Mostra una notificació si un assoliment es desbloqueja." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_MASTERY, + "Notificacions de jocs" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_MASTERY, + "Mostra una notificació quan s'hagin desbloquejat tots els assoliments d'un joc." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_CHALLENGE_INDICATORS, + "Activa els indicadors de desafiament" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_CHALLENGE_INDICATORS, + "Mostra indicadors en pantalla quan es puguin desbloquejar certs assoliments." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_PROGRESS_TRACKER, + "Indicador de progrés" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_PROGRESS_TRACKER, + "Mostra un indicador en pantalla quan es facin progressos per aconseguir certs assoliments." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_LBOARD_START, + "Missatges d'inici de la taula de classificació" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_LBOARD_START, + "Mostra una descripció d'una taula de classificació quan s'activi." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_LBOARD_SUBMIT, + "Missatges enviats a la taula de classificació" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_LBOARD_SUBMIT, + "Mostra un missatge amb el valor enviat en completar l'intent d'entrar en una taula de classificació." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_LBOARD_CANCEL, + "Missatges d'error en la taula de classificació" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_LBOARD_CANCEL, + "Mostra un missatge si falla un intent d'entrar en una taula de classificació." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_LBOARD_TRACKERS, + "Seguiment de la taula de classificació" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_LBOARD_TRACKERS, + "Mostra informació del seguiment en pantalla amb el valor actualitzat de les taules de classifcació actives." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_ACCOUNT, "Missatges d'inici de sessió" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_ACCOUNT, + "Mostra missatges relacionats amb l'inici de sessió al compte de RetroAchievements." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, + "Missatges detallats" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE, + "Mostra diagnòstic addicional i missatges d'error." + ) /* Settings > Network */ @@ -5469,18 +7058,46 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, "Anuncia les partides de joc en línia públicament. Si no està activat els clients s’han de connectar manualment en comptes d’usar el vestíbul públic." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, + "Fes servir un servidor intermediari" + ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Redirigeix les connexions de joc en línia a través d'un servidor intermediari. És útil si l’amfitrió es troba darrere d’un tallafoc o té problemes de NAT/UPnP." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER, + "Ubicació del servidor intermediari" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_CUSTOM_MITM_SERVER, + "Direcció del servidor intermediari personalitzat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_CUSTOM_MITM_SERVER, + "Aquí pots introduir la direcció del teu servidor intermediari personalitzat. Format: Adreça o adreça/port." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_1, + "Nord-amèrica (Costa est, USA)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_2, "Europa Occidental" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_3, + "Sud-amèrica (Sud-est, Brasil)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_4, "Sud-est Àsia" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_5, + "Àsia Oriental (Chuncheon, Corea del sud)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_CUSTOM, "Personalitzat" @@ -5489,14 +7106,50 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, "Direcció del servidor" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, + "Indica l'adreça IP del servidor al qual cal connectar." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, "Port TCP per al joc en línia" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, + "Indica el port del servidor a connectar. Pot ser TCP o UDP." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MAX_CONNECTIONS, + "Nombre màxim de connexions" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_MAX_CONNECTIONS, + "Indica el nombre màxim de connexions actives que admet el servidor abans de rebutjar una nova connexió." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MAX_PING, "Limitació del ping" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_MAX_PING, + "Indica la latència (ping) màxima que acceptarà el servidor d'altres connexions. Selecciona 0 per desactivar el límit." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, + "Contrasenya del servidor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, + "Indica la contrasenya que han de fer servir els clients que es connecten al servidor." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, + "Contrasenya del servidor per espectadors" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, + "Indica la contrasenya que han de fer servir els clients que es connecten al sevidor com a espectadors." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_START_AS_SPECTATOR, "Mode espectador del joc en línia" @@ -5509,6 +7162,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_FADE_CHAT, "Amagar xat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_FADE_CHAT, + "Fes desaparèixer els missatges del xat en un temps determinat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_CHAT_COLOR_NAME, + "Color del xat (Sobrenom)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_CHAT_COLOR_NAME, + "Format: #RRGGBB o RRGGBB" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_CHAT_COLOR_MSG, + "Color del xat (Missatges)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_CHAT_COLOR_MSG, + "Format: #RRGGBB o RRGGBB" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_PAUSING, "Permet la pausa" @@ -5517,6 +7190,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_PAUSING, "Permet als jugadors posar la partida en pausa durant el joc en línia." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ALLOW_SLAVES, + "Permet clients en mode esclau" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_REQUIRE_SLAVES, + "Bloqueja els clients sense el mode esclau" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, "Fotogrames de comprovació de joc en línia" @@ -5525,21 +7206,117 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, "La freqüència (en fotogrames) amb la qual es comprovarà que l’amfitrió i el client estan sincronitzats." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Fotogrames de latència d'entrada" + ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, "El nombre de fotogrames de latència d’entrada per al joc en línia que s’usarà per amagar la latència de la xarxa. Redueix la fluctuació de senyal i l’ús de CPU del joc en línia a canvi d’introduir una latència d’entrada considerable." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Rang de fotogrames de latència d'entrada" + ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, "El rang de fotogrames de latència d’entrada que es poden fer servir per amagar la latència de la xarxa. Redueix la fluctuació de senyal i l’ús de CPU del joc en línia a canvi d’una latència d’entrada imprevisible." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, + "Camí del NAT del joc en xarxa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL, + "Compartir entrada digital" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICE_I, + "Sol·licita el dispositiu %u" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REQUEST_DEVICE_I, + "Sol·licitud per jugar amb el dispositiu d'entrada indicat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, + "Ordres de xarxa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, + "Port de comandes de xarxa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, + "RetroPad de xarxa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, + "Port base de RetroPad a la xarxa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, + "RetroPad de xarxa de l'usuari %d" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, "Comandes stdin" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, + "Interfície de comandes de l'entrada estàndard." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETWORK_ON_DEMAND_THUMBNAILS, + "Descàrrega les miniatures sota demanda" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, + "Configuració de l'actualitzador" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_UPDATER_SETTINGS, + "Accedeix a la configuració d'actualització del nucli" + ) /* Settings > Network > Updater */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, + "URL dels nuclis del Buildbot" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, + "Indica l'adreça web URL per actualitzar els nuclis de buildbot de libretro." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, + "Adreça web de recursos de buildbot" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, + "Indica l'adreça web URL per actualitzar els nuclis de buildbot de libretro." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Extreu automàticament els fitxers descarregats" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Extreu els continguts dels fitxers després de descarregar-los." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES, + "Mostra els nuclis experimentals" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_BACKUP, + "Desar una còpia dels nuclis en actualitzar-los" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE, + "Mida de l'historial de còpies de seguretat del nucli" + ) /* Settings > Playlists */ @@ -5547,13 +7324,61 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, "Historial" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, + "Permet tenir llistes de jocs, imatges, música i vídeos utilitzats recentment." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, "Mida del historial" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, + "Limita el nombre d'entrades a la llista de reproducció recent per jocs, imatges, música i vídeos." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_FAVORITES_SIZE, - "Mida de la llista de preferits" + "Mida dels favorits" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Permet reanomenar els elements" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, + "Permet canviar el nom dels elements de les llistes de reproducció." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, + "Permet eliminar els elements" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, + "Permet eliminar els elements de les llistes de reproducció." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SORT_ALPHABETICAL, + "Ordena les llistes de reproducció alfabèticament" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_USE_OLD_FORMAT, + "Desa les llistes de reproducció en el format antic" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_COMPRESSION, + "Comprimeix les llistes de reproducció" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SHOW_INLINE_CORE_NAME, + "Mostra els nuclis associats a les llistes de reproducció" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SHOW_SUBLABELS, + "Mostra subetiquetes de les llistes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SHOW_HISTORY_ICONS, + "Mostra icones específiques dels continguts a l'historial i als preferits" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_CORE, @@ -5627,6 +7452,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TIME_UNIT_AGO, "abans" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SHOW_ENTRY_IDX, + "Mostar índexs en les llistres de reproducció" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_RUNTIME_TYPE, + "Etiqueta de temps de joc a les llistes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE, + "Estil de data i temps de 'Última reproducció'" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_FUZZY_ARCHIVE_MATCH, + "Cerca aproximada de fitxers" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_WITHOUT_CORE_MATCH, "Cerca sense coincidència de nucli" @@ -5635,6 +7476,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_WITHOUT_CORE_MATCH, "Permet cercar contingut i afegir-lo a una llista de reproducció encara que no hi hagi un nucli instal·lat que l’admeti." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, + "Comprova els duplicats mitjançant les sumes de verificació CRC" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LIST, "Gestiona les llistes de reproducció" @@ -5651,6 +7496,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_PORTABLE_PATHS, "Quan s’activa i també se selecciona el directori del «navegador de fitxers», el valor actual del paràmetre «navegador de fitxers» es desa a la llista de reproducció. Quan es carrega la llista en un altre sistema on s’hagi activat la mateixa opció, el valor del paràmetre «navegador de fitxers» es compara amb el valor de la llista de reproducció; si són diferents els camins de les entrades de la llista s’arreglen automàticament." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_USE_FILENAME, + "Fes servir els noms dels fitxers per cercar miniatures" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_USE_FILENAME, + "Si està activat, es cercaran miniatures mitjançant el nom del fitxer de l'element i no en la seva etiqueta." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ALLOW_NON_PNG, + "Permet tots els tipus d'matge per les miniatures" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MANAGE, "Administrar" @@ -5662,14 +7519,50 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_DEFAULT_CORE, "Nucli per defecte" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_RESET_CORES, + "Reinicia les associacions de nucli" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_RESET_CORES, + "Eliminar totes les associacions als nuclis existents pels elements de les llistes de reproducció." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE, + "Presentació d'etiquetes" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE, + "Canvia la forma de presentar les etiquetes de contingut per aquesta llista." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_SORT_MODE, "Mètode d'ordenació" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_SORT_MODE, + "Determina com les entrades s'ordenen en aquesta llista de reproducció." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_CLEAN_PLAYLIST, "Neteja la llista de reproducció" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_CLEAN_PLAYLIST, + "Confirma les associacions a nuclis i elimina els elements invàlids i duplicats." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_REFRESH_PLAYLIST, + "Actualitza la llista de reproducció" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DELETE_PLAYLIST, + "Esborrar llista de reproducció" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DELETE_PLAYLIST, + "Elimina la llista de reproducció del sistema de fitxers." + ) /* Settings > User */ @@ -5677,14 +7570,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, "Privacitat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, + "Canvia la configuració de privacitat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, "Compte" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, + "Administra els comptes d'usuari configurats." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, "Nom d’usuari" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, + "Introdueix aquí el teu nom d'usuari. Aquest nom es farà servir pel joc en xarxa i altres coses." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, "Llengua" @@ -5700,10 +7605,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, "Permetre la càmera" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CAMERA_ALLOW, + "Tots els nuclis tenen accés a la càmera." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISCORD_ALLOW, + "Presència enriquida de Discord" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, "Permet la localització" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOCATION_ALLOW, + "Permet als nuclis accedir a la teva localització." + ) /* Settings > User > Accounts */ @@ -5733,12 +7650,24 @@ MSG_HASH( /* Settings > User > Accounts > YouTube */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_YOUTUBE_STREAM_KEY, + "Clau de transmissió de Youtube" + ) /* Settings > User > Accounts > Twitch */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TWITCH_STREAM_KEY, + "Clau de transmissió de Twitch" + ) /* Settings > User > Accounts > Facebook Gaming */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FACEBOOK_STREAM_KEY, + "Clau de retransmissió de Facebook Gaming" + ) /* Settings > Directory */ @@ -5784,7 +7713,19 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Navegador de fitxers" + "Directori d'inici" + ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, + "Selecciona la carpeta inicial de l'explorador de fitxers." + ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, + "Fitxers de configuració" + ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, + "El fitxer de configuració predeterminat s'ha desat en aquesta carpeta." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, @@ -5814,14 +7755,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, "Arxius de trucs" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_DATABASE_PATH, + "En aquesta carpeta es desaran els fitxers de trucs." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, "Filtres de vídeo" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FILTER_DIR, + "Els filtres de vídeo basats en CPU es desen en aquesta carpeta." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, "Filtres d'àudio" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_FILTER_DIR, + "Els filtres d'àudio DSP s'emmagatzemen en aquesta carpeta." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, "Shaders de Vídeo" @@ -5834,6 +7787,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, "Enregistraments" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORDING_OUTPUT_DIRECTORY, + "Les gravacions es desaran en aquesta carpeta." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, + "Configuracions dels enregistraments" + ) MSG_HASH( MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, "Les configuracions d’enregistrament es desen en aquest directori." @@ -5846,6 +7807,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OVERLAY_DIRECTORY, "Les superposicions es desen en aquest directori." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_DIRECTORY, + "Superposicions del teclat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OSK_OVERLAY_DIRECTORY, + "En aquesta carpeta es desen les superposicions de teclat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_DIRECTORY, "Disposicions de vídeo" @@ -5888,11 +7857,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_FAVORITES_DIRECTORY, - "Llista de reproducció de preferits" + "Llista de reproducció dels favorits" ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_FAVORITES_DIRECTORY, - "Desa la llista de reproducció de preferits en aquest directori." + "Desa la llista de reproducció de favorits en aquest directori." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_DIRECTORY, @@ -5946,11 +7915,39 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, "Memòria cau" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, + "En aquesta carpeta es desen temporalment els continguts dels fitxers comprimits." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOG_DIR, + "Registres d'esdeveniments del sistema" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOG_DIR, + "El registre d'esdeveniments del sistema es desen en aquesta carpeta." + ) #ifdef HAVE_MIST /* Settings > Steam */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_ENABLE, + "Activa Rich Presence" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_ENABLE, + "Comparteix el teu estat actual dins de RetroArch a través de Steam." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT, + "Format de continguts de presència enriquida" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, + "Decideix quina informació dels continguts es compartirà." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT_CONTENT, @@ -5964,6 +7961,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT_SYSTEM, "Nom del sistema" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT_CONTENT_SYSTEM, + "Contingut (Nom del sistema)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT_CONTENT_CORE, + "Contingut (Nom del nucli)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT_CONTENT_SYSTEM_CORE, + "Contingut (Nom del sistema - Nom del nucli)" + ) #endif /* Music */ @@ -5974,6 +7983,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, "Afegir a la mescla" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_PLAY, + "Afegir a la mescla i reproduir" + ) /* Netplay */ @@ -5993,10 +8006,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, "Desconnecta de l'amfitrió del joc en línia" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, + "Desconnecta una sessió activa del joc en xarxa." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_LOBBY_FILTERS, "Filtres de vestíbul" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHOW_ONLY_CONNECTABLE, + "Mostra només les sales disponibles" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHOW_ONLY_INSTALLED_CORES, + "Només pels nuclis instal·lats" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHOW_PASSWORDED, + "Sales amb contrasenya" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, "Actualitza la llista d’amfitrions de joc en línia" @@ -6016,14 +8045,34 @@ MSG_HASH( /* Netplay > Host */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, + "Inicia un servidor de joc en xarxa" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, + "Inicia el joc en xarxa en el mode servirdor." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, + "Atura el servidor de joc en xarxa" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_KICK, "Expulsar client" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_KICK, + "Expulsa al client de la teva sala." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_BAN, "Vetar client" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_BAN, + "Prohibeix l'accés a un client a la teva sala." + ) /* Import Content */ @@ -6039,6 +8088,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, "" ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_SCAN_THIS_DIRECTORY, + "Selecciona aquesta opció per cerca contingut a la carpeta actual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_FILE, "Cerca en un fitxer" @@ -6066,9 +8119,17 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, "Afegir a la mescla" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY, + "Afegir a la mescla i reproduir" + ) /* Import Content > Manual Scan */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_DIR, + "Directori de contingut" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_DIR, "Selecciona un directori on cercar continguts." @@ -6125,6 +8186,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_DAT_FILE, "Fitxer DAT d’arcade" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_DAT_FILE_FILTER, + "Filtre DAT d'arcade" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_OVERWRITE, "Sobreescriu la llista de reproducció existent" @@ -6364,11 +8429,27 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST, - "Afegeix als preferits" + "Afegeix als favorits" ) MSG_HASH( MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES_PLAYLIST, - "Afegeix el contingut als “Favorits”." + "Afegeix el contingut a «Favorits»." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_PLAYLIST, + "Afegir a la llista de reproducció" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_PLAYLIST, + "Afegeix el contingut a una llista de reproducció." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CREATE_NEW_PLAYLIST, + "Crea una nova llista de reproducció" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CREATE_NEW_PLAYLIST, + "Crea una nova llista de reproducció i afegeix aquest element a la nova llista." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SET_CORE_ASSOCIATION, @@ -6447,54 +8528,138 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "Continua" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESUME_CONTENT, + "Reprèn el contingut i abandona el Menú Ràpid." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, "Reinicia" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESTART_CONTENT, + "Reinicia el contingut des del principi." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, "Tanca contingut" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOSE_CONTENT, + "Tanca el contingut. Es perdrà qualsevol progrés no desat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, "Fes una captura de pantalla" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, + "Captura una imatge de la pantalla." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STATE_SLOT, "Posició de desat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STATE_SLOT, + "Canvia la posició actual de desat ràpid." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_STATE, "Desa estat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_STATE, + "Desa un estat a la posició actualment seleccionada." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOAD_STATE, "Carrega estat" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOAD_STATE, + "Carrega un estat desat des de la posició actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, + "Desfer càrrega ràpida" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, + "Si s'ha carregat un estat desat, el contingut tornarà a l'estat previ a la càrrega." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, + "Desfer desat ràpid" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, + "Si s'ha sobreescrit un desat ràpid, tornarà a tenir les dades prèvies." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_REPLAY_SLOT, "Posició de repitició" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REPLAY_SLOT, + "Canvia la posició actual de desat ràpid." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAY_REPLAY, "Reproduir repetició" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAY_REPLAY, + "Reprodueix el fitxer de repetició des de la posició seleccionada." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RECORD_REPLAY, "Enregistrar la repetició" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORD_REPLAY, + "Enregistra un fitxer de repetició a la posició seleccionada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HALT_REPLAY, + "Atura l'enregistrament/repetició" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_HALT_REPLAY, + "Atura la gravació/reproducció de la repetició actual" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, - "Afegeix als preferits" + "Afegeix als favorits" ) MSG_HASH( MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES, - "Afegeix el contingut als “Favorits”." + "Afegeix el contingut a «Favorits»." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_START_RECORDING, + "Inicia enregistrament" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_START_RECORDING, + "Inicia la gravació de vídeo de la partida." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_STOP_RECORDING, "Atura l'enregistrament" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_STOP_RECORDING, + "Atura la gravació de vídeo." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_START_STREAMING, + "Inicia la transmissió" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_START_STREAMING, + "Inicia una retransmissió en el destí seleccionat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_STOP_STREAMING, "Atura la retransmissió" @@ -6507,14 +8672,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_LIST, "Estats desats" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_LIST, + "Accedeix a les opcions dels desats ràpids." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "Opcions del nucli" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_OPTIONS, + "Canvia les opcions pel contingut." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, + "Canvia els controls del contingut." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Trucs" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, + "Configura els trucs." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, "Control de disc" @@ -6561,17 +8742,41 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_CORE_OPTIONS_CREATE, "Desa les opcions del joc" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_SPECIFIC_CORE_OPTIONS_CREATE, + "Desa les opcions del nucli que s'aplicarà al contingut actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_CORE_OPTIONS_REMOVE, + "Elimina les opcions del joc" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_SPECIFIC_CORE_OPTIONS_REMOVE, + "Elimina les opcions del nucli que s'aplicaran només al contingut actual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FOLDER_SPECIFIC_CORE_OPTIONS_CREATE, "Desa les opcions del directori de contingut" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FOLDER_SPECIFIC_CORE_OPTIONS_REMOVE, + "Elimina les opcions del directori de continguts" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_OPTION_OVERRIDE_INFO, + "Fitxer d'opcions actiu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_OPTION_OVERRIDE_INFO, + "El fitxer d'opcions que està ara mateix en ús." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Reinicia les opcions" + "Reinicia les opcions del nucli" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Estableix totes les opcions del nucli als valors predeterminats." + "Reinicia totes les opcions del nucli als valors predeterminats." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -6594,9 +8799,97 @@ MSG_HASH( /* Quick Menu > Controls */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_MANAGER_LIST, + "Gestiona els fitxers de reassignació" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_MANAGER_LIST, + "Carrega, desa o elimina els fitxers d'assignació d'entrada del contingut actual." + ) /* Quick Menu > Controls > Manage Remap Files */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_INFO, + "Fitxer de reassignació actiu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_INFO, + "El fitxer de reassignació està en ús actualment." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, + "Carrega el fitxer de reassignació" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_LOAD, + "Carrega i substitueix les assignacions actuals d'entrada." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_AS, + "Anomena i desa el fitxer de reassignació" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_SAVE_AS, + "Desa la configuració actual d'assignacions d'entrada en un nou fitxer d'assignacions." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, + "Desa el fitxer de mapeig del nucli" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_SAVE_CORE, + "Desa un fitxer d'assignació que s'aplicarà a tots els continguts que es carreguin amb aquest nucli." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, + "Elimina els fitxers d'assignació del nucli" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_REMOVE_CORE, + "Elimina el fitxer d'assignació que s'aplicarà a tots els cotinguts que es carreguin amb aquest nucli." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CONTENT_DIR, + "Desa la personalització a la carpeta de fitxers" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CONTENT_DIR, + "Elimina el fitxer d'assignació de les carpetes de contingut" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, + "Desa el fitxer de mapeig del nucli" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_SAVE_GAME, + "Desa un fitxer d'assignació que s'aplicarà al contingut actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, + "Elimina els fitxers d'assignació del joc" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_REMOVE_GAME, + "Elimina el fitxer d'assignació que s'aplicarà al contingut actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_RESET, + "Reinicia les assignacions d'entrada" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_RESET, + "Estableix totes les opcions de les assignacions als valors predeterminats." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMAP_FILE_FLUSH, + "Actualitza el fitxer d'assignacions d'entrada" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_FLUSH, + "Sobreescriu el fitxer d'assignació actiu amb les opcions actuals d'assignació d'entrada." + ) /* Quick Menu > Controls > Manage Remap Files > Load Remap File */ @@ -6611,10 +8904,74 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_CONT, "Comença o continua la cerca de trucs" ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_CHEAT_START_OR_CONT, + "Escaneja la memòria per trobar nous trucs." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, + "Carrega el fitxer de trucs (Reemplaça)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, + "Carrega un fitxer de trucs i reemplaça els trucs existents." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD_APPEND, + "Carrega fitxers de trucs (afegir)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD_APPEND, + "Carrega un fitxer de trucs i afegeix-los als trucs actuals." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RELOAD_CHEATS, + "Torna a carregar els trucs específics del joc" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, + "Anomena i desa el fitxer de trucs" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, + "Desa els trucs actuals en un fitxer de trucs." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_TOP, + "Afegeix un nou truc a la part superior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BOTTOM, + "Afegeix un nou truc al final" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_ALL, + "Elimina tots els trucs" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_LOAD, + "Aplica els trucs automàticament durant en carregar un joc" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_LOAD, + "Aplica els trucs automàticament quan es carrega el joc." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_AFTER_TOGGLE, + "Aplica en activar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_APPLY_AFTER_TOGGLE, + "Aplica els trucs immediatament després d'activar-los." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, "Aplica els canvis" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, + "Els canvis en els trucs tindran efecte immediat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT, "Trucs" @@ -6622,16 +8979,128 @@ MSG_HASH( /* Quick Menu > Cheats > Start or Continue Cheat Search */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_RESTART, + "Inicia o reinicia una cerca de trucs" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_START_OR_RESTART, + "Clica esquerra o dreta per canviar la mida en bits." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EXACT, + "Cerca valors en la memòria" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EXACT, + "Clica esquerra o dreta per canviar el valor." + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EXACT_VAL, + "Igual a %u (%X)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LT, + "Cerca valors en la memòria" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_LT_VAL, + "Menys que abans" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_LTE, + "Cerca valors en la memòria" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_LTE_VAL, + "Inferior o igual a l'anterior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GT, + "Cerca valors en la memòria" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_GT_VAL, + "Més grans que l'anterior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_GTE, + "Cerca valors en la memòria" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_GTE_VAL, + "Més gran o igual que l'anterior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQ, + "Cerca valors en la memòria" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EQ_VAL, + "Iguala a l'anterior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_NEQ, + "Cerca valors en la memòria" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_NEQ_VAL, + "Diferents que l'anterior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQPLUS, + "Cerca valors en la memòria" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQPLUS, + "Clica esquerra o dreta per canviar el valor." + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EQPLUS_VAL, + "Iguals a l'anterior +%u (%X)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_EQMINUS, + "Cerca valors en la memòria" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_SEARCH_EQMINUS, + "Clica esquerra o dreta per canviar el valor." + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_SEARCH_EQMINUS_VAL, + "Iguals a l'anterior -%u (%X)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_MATCHES, + "Afegeix %u coincidències a la llista" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_MATCH, "Suprimeix la coincidència #" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_MATCH, + "Crea una coincidència del truc #" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_MATCH, + "Direcció de coincidència: %08X Mask: %02X" + ) /* Quick Menu > Cheats > Load Cheat File (Replace) */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE, + "Fitxer de trucs (Reemplaça)" + ) /* Quick Menu > Cheats > Load Cheat File (Append) */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_APPEND, + "Fitxer de trucs (afegir)" + ) /* Quick Menu > Cheats > Cheat Details */ @@ -6643,6 +9112,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_IDX, "Índex" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_IDX, + "Posició del truc a la llista." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_STATE, "Habilitat" @@ -6651,6 +9124,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DESC, "Descripció" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_MEMORY_SEARCH_SIZE, + "Mida de la memòria de cerca" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_TYPE, "Tipus" @@ -6663,6 +9140,38 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS, "Adreça de memòria" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_BROWSE_MEMORY, + "Examina l'adreça: %08X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS_BIT_POSITION, + "Adreça de memòria" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_ADDRESS_BIT_POSITION, + "Màscara de bits de la direcció si la mida de la cerca en memòria és menor a 8 bits." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_COUNT, + "Nombre d'iteracions" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_ADD_TO_ADDRESS, + "Augmenta la direcció en cada iteració" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_ADD_TO_VALUE, + "Augmentar el valor en cada iteració" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_REPEAT_ADD_TO_VALUE, + "Després de cada iteració, el 'Valor' augmentarà en aquesta quantitat." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_TYPE, + "Vibra si la memòria" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_VALUE, "Valor de la vibració" @@ -6671,10 +9180,46 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PORT, "Port de vibració" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_STRENGTH, + "Força de la vibració primària" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_DURATION, + "Duració (ms) de la vibració primària" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_STRENGTH, + "Força de la vibració secundària" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_SECONDARY_DURATION, + "Duració (ms) de la vibració secundària" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_CODE, "Codi" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_AFTER, + "Afegeix un nou truc després d'aquest" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BEFORE, + "Afegeix un nou truc després d'aquest" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_AFTER, + "Copia aquest truc per més endavant" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_COPY_BEFORE, + "Copia aquest truc per més endavant" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE, + "Elimina aquest truc" + ) /* Quick Menu > Disc Control */ @@ -6690,6 +9235,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, "Carrega un nou disc" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISK_INDEX, + "Índex del disc actual" + ) /* Quick Menu > Shaders */ @@ -6697,6 +9246,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADERS_ENABLE, "Shaders de Vídeo" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADERS_ENABLE, + "Activa el procés de shaders de vídeo." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHADER_WATCH_FOR_CHANGES, + "Comprova els canvis en els shaders" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, + "Aplica els canvis al fitxer de shaders en el disc de manera automàtica." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, + "Recorda l'última carpeta de shaders que s'ha fet servir" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_REMEMBER_LAST_DIR, + "Obre l'explorador de fitxers en l'última carpeta que es va obrir per carregar ajustaments i shaders." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, "Carregar ajust predeterminat" @@ -6705,10 +9274,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, "Carrega un shader predefinit. El pipeline de shaders es configurarà automàticament." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_PREPEND, + "Anteposar el preajust" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PREPEND, + "Anteposa el preajust actual al preajust carregat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_APPEND, "Afegeix el preajust" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_APPEND, + "Annexa l'ajustament actual en carregar-lo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE, "Desar ajust predeterminat" @@ -6729,6 +9310,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, "Aplica els canvis" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, + "Paràmetres del shader" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, + "Modifica el shader actual directament. Els canvis no es desaran en el fitxer d'ajustament." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, "Nombre de passades del shader" @@ -6770,10 +9359,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GLOBAL, "Desa com a predefinició global" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GLOBAL, + "Desa la configuració actual de shaders com a configuració global predeterminada." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, "Desa com a predefinició del nucli" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, + "Desa la configuració actual del shader com a predeterminada per aquest nucli." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT, "Desa com a predefinició del directori de contingut" @@ -6782,6 +9379,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, "Desa com a predefinició del joc" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, + "Desa la configuració actual de shaders per aquest contingut." + ) /* Quick Menu > Shaders > Remove */ @@ -6824,9 +9425,53 @@ MSG_HASH( /* Quick Menu > Shaders > Shader Parameters */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, + "No hi ha configuració pels shaders" + ) /* Quick Menu > Overrides */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERRIDE_FILE_INFO, + "Fitxer de personalització activat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERRIDE_FILE_INFO, + "El fitxer de trucs està en ús actualment." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERRIDE_FILE_LOAD, + "Carrega un fitxer personalitzat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERRIDE_FILE_LOAD, + "Carrega i substitueix la configuració actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERRIDE_FILE_SAVE_AS, + "Anomena i desa les personalitzacions" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERRIDE_FILE_SAVE_AS, + "Desa la configuració actual en un nou fitxer de personalització." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Desa les excepcions del nucli" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMOVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Elimina les personalitzacions del nucli" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Desa la personalització de directori de continguts" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMOVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Elimina la personalització de les carpetes de contingut" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, "Desa les excepcions del joc" @@ -6835,6 +9480,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, "Desa un fitxer de configuració d’excepcions que s’aplicarà només al contingut actual. Tindrà prioritat sobre la configuració principal." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMOVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Elimina les personalitzacions del joc" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REMOVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Elimina el fitxer de configuració personalitzada que s'aplicarà només al contingut actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERRIDE_UNLOAD, + "Descarrega la personalització" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERRIDE_UNLOAD, + "Reinicia totes les opcions als valors de la configuració global." + ) /* Quick Menu > Achievements */ @@ -6866,6 +9527,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME, "Reprèn el mode expert d’assoliments" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_SERVER_UNREACHABLE, + "El servidor de RetroAchievements no està disponible" +) +MSG_HASH( + MENU_ENUM_LABEL_CHEEVOS_SERVER_DISCONNECTED, + "El servidor de RetroAchievements no està disponible. Es seguirà intentant la connexió fins que es confirmi la comunicació o fins que es tanqui l'aplicació." +) +MSG_HASH( + MENU_ENUM_LABEL_CHEEVOS_SERVER_RECONNECTED, + "Totes les sol·licituds pendents han sigut sincronitzades amb el servidor de RetroAchievements." +) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_IDENTIFYING_GAME, + "S'està identificant el joc" +) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_FETCHING_GAME_DATA, + "S'estan obtenint les dades del joc" +) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_STARTING_SESSION, + "S'està iniciant la sessió" +) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN, "No s'ha iniciat la sessió" @@ -6878,20 +9563,88 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_UNKNOWN_GAME, "Joc desconegut" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE, + "No es pot activar els assoliments amb aquest nucli" +) /* Quick Menu > Information */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_INFO_CHEEVOS_HASH, + "Hash de RetroAchievements" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DETAIL, "Element de la base de dades" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RDB_ENTRY_DETAIL, + "Mostra informació de la base de dades pel contingut actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, + "No hi ha elements disponibles" + ) /* Miscellaneous UI Items */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, + "No hi ha nuclis disponibles" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, + "No hi ha opcions del nucli disponibles" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, + "No hi ha informació del nucli disponible" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_CORE_BACKUPS_AVAILABLE, + "No hi ha còpies de seguretat del nucli disponibles" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE, + "No hi ha preferits disponibles" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, + "No hi ha historial disponible" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_IMAGES_AVAILABLE, + "No hi ha imatges disponibles" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_MUSIC_AVAILABLE, "No hi ha música disponible" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_VIDEOS_AVAILABLE, + "No hi ha vídeos disponibles" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, + "No hi ha informació disponible" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, + "No hi ha elements disponibles a la llista de reproducció" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, + "No s'ha trobat cap configuració" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_BT_DEVICES_FOUND, + "No s'han trobat dispositius amb Bluetooth" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, + "No s'ha trocat cap xarxa" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_CORE, "Cap nucli" @@ -6900,6 +9653,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SEARCH, "Cerca" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, + "Intercanvia les miniatures" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Selecció aleatòria" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Enrere" @@ -6912,6 +9673,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, "Directori pare" ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_PARENT_DIRECTORY, + "Torna al directori superior." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, + "No s'ha trobat la carpeta" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_ITEMS, "No hi ha elements" @@ -6947,6 +9716,10 @@ MSG_HASH( /* Settings Options */ +MSG_HASH( /* FIXME Should be MENU_LABEL_VALUE */ + MSG_UNKNOWN_COMPILER, + "Compilador desconegut" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_OR, "Compartit" @@ -6959,6 +9732,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_DIGITAL_VOTE, "Majoria" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG, + "Compartir l'entrada analògica" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_ANALOG_MAX, "Màxim" @@ -6975,6 +9752,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NO_PREFERENCE, "Sense preferències" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_TICKER_TYPE_BOUNCE, + "Rebota a esquerra i dreta" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_TICKER_TYPE_LOOP, "Desplaçar cap a l'esquerra" @@ -6991,6 +9772,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_NARRATOR_MODE, "Mode narrador" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE_ENABLE_HIST_FAV, + "Historial i Preferits" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE_ENABLE_ALL, "Totes les llistes de reproducció" @@ -6999,6 +9784,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE_ENABLE_NONE, "No" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_INLINE_CORE_DISPLAY_HIST_FAV, + "Historial i Preferits" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_INLINE_CORE_DISPLAY_ALWAYS, "Sempre" @@ -7031,6 +9820,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE, "No hi ha font" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_USE_THIS_DIRECTORY, + "Selecciona aquesta opció per establir aquesta carpeta." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, "" @@ -7127,10 +9924,58 @@ MSG_HASH( MENU_ENUM_LABEL_CHEAT_TYPE_SET_TO_VALUE, "Assigna valor" ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_INCREASE_VALUE, + "Augmenta en Valor" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_DECREASE_VALUE, + "Disminueix en Valor" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_EQ, + "Executa el següent truc si el valor és idèntic al de la memòria" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_NEQ, + "Executa el següent truc si el valor és diferent del de la memòria" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_LT, + "Executa el següent truc si el valor és inferior al de la memòria" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_TYPE_RUN_NEXT_IF_GT, + "Executa el següent truc si el valor és superior al de la memòria" + ) MSG_HASH( MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_EMU, "Emulador" ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_1, + "1-Bit, Valor màxim = 0x01" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_2, + "2-Bit, Valor màxim = 0x03" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_4, + "4-Bit, Valor màxim = 0x0F" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_8, + "8-Bit, Valor màxim = 0xFF" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_16, + "16 Bits, valor màxim = 0xFFFF" + ) +MSG_HASH( + MENU_ENUM_LABEL_CHEAT_MEMORY_SIZE_32, + "32 bits, Valor màxim = 0xFFFFFFFF" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_SORT_MODE_DEFAULT, "Configuració predeterminada" @@ -7143,10 +9988,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_SORT_MODE_OFF, "Cap" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_DEFAULT, + "Mostra les etiquetes completes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_REMOVE_PARENS, + "Elimina el contingut entre parèntesis ( )" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_REMOVE_BRACKETS, + "Elimina el contingut entre claudàtors [ ]" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_REMOVE_PARENS_AND_BRACKETS, + "Elimina el contingut entre ( ) i [ ]" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_KEEP_REGION, "Preservar la regió" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_KEEP_DISC_INDEX, + "Preserva l'índex del disc" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_KEEP_REGION_AND_DISC_INDEX, + "Manté la regió i l'índex del disc" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_THUMBNAIL_MODE_DEFAULT, "Configuració predeterminada" @@ -7223,14 +10092,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY, "No compatible" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_RECENTLY_UNLOCKED_ENTRY, + "Desblocat recentment" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_ALMOST_THERE_ENTRY, "Gairebé allà" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_ACTIVE_CHALLENGES_ENTRY, + "Desafiaments actius" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_TRACKERS_ONLY, "Només rastrejadors" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_NOTIFICATIONS_ONLY, + "Només notificacions" +) MSG_HASH( MENU_ENUM_LABEL_VALUE_DONT_CARE, "Per defecte" @@ -7398,14 +10279,46 @@ MSG_HASH( /* RGUI: Settings > User Interface > Appearance */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, + "Gruix del fons" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, + "Augmenta les dimensions de la quadrícula de fons del menú." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_ENABLE, "Filtre de vores" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, + "Bruix de la vora" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, + "Augmenta les dimensions de la quadrïcula de la vora del menú." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_BORDER_FILLER_ENABLE, + "Mostra la vora del menú." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_FULL_WIDTH_LAYOUT, + "Utilitzar l'amplada completa" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Filtre lineal" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_LINEAR_FILTER, + "Suavitza lleugerament el menú per no es notin les vores pixelades." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_INTERNAL_UPSCALE_LEVEL, + "Reescalat intern" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_ASPECT_RATIO, "Relació d'aspecte" @@ -7414,6 +10327,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_ASPECT_RATIO, "Seleccioneu la relació d’aspecte del menú. Les relacions de pantalla panoràmica incrementen la resolució horitzontal de la interfície del menú. (Pot caldre reiniciar si l’opció «Bloqueja la relació d’aspecte del menú» està desactivada)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_ASPECT_RATIO_LOCK, + "Bloca la relació d'aspecte" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_ASPECT_RATIO_LOCK, "Assegura que el menú es vegi sempre amb la relació d’aspecte correcta. Si es desactiva, el menú ràpid s’estirarà per coincidir amb el contingut carregat." @@ -7422,6 +10339,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_MENU_COLOR_THEME, "Color del tema" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_MENU_THEME_PRESET, + "Tema predefinit predeterminat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_MENU_THEME_PRESET, + "Selecciona un ajustament del tema del menú en l'explorador de fitxers." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_TRANSPARENCY, "Transparència" @@ -7430,10 +10355,74 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, "Efectes d'ombra" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_SHADOWS, + "Mostra ombres en el text, vores i miniatures del menú. No afecta gaire el rendiment." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_PARTICLE_EFFECT, + "Animació de fons" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_PARTICLE_EFFECT, + "Activa un efecte d'animació de partícules en el fons. Té un impacte en el rendiment." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_PARTICLE_EFFECT_SPEED, + "Velocitat de l'animació de fons" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_PARTICLE_EFFECT_SPEED, + "Ajusta la velocitat dels efectes d'animació de les partícules de fons." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_PARTICLE_EFFECT_SCREENSAVER, + "Animació d'estalvi de pantalla" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_PARTICLE_EFFECT_SCREENSAVER, + "Mostra un efecte d'animació de partícules en el fons mentre l'estalvi de pantalla del menú estigui actiu." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_INLINE_THUMBNAILS, + "Mostra miniatures de les llistes de reproducció" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAILS_RGUI, "Miniatura superior" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_RGUI, + "Miniatura inferior" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_RGUI, + "Tipus de miniatura a mostrar a la part superior dreta de la llista de reproducció." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_SWAP_THUMBNAILS, + "Intercanvia miniatures" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_SWAP_THUMBNAILS, + "Intercanvia la posició de les miniatures superior e inferior." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_THUMBNAIL_DOWNSCALER, + "Mètode d'escalat de miniatures" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER, + "Selecciona el mètode de redimensionat perquè les miniatures entrin a la pantalla." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_THUMBNAIL_DELAY, + "Retard en les miniatures (ms)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_EXTENDED_ASCII, + "Suport per ASCII ampliat" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_EXTENDED_ASCII, "Habilita la visualització de caràcters ASCII no estàndards. És necessari per compatibilitat amb certes llengües occidentals no angleses. Afecta moderadament al rendiment." @@ -7442,13 +10431,25 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SWITCH_ICONS, "Icones d'interruptors" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_SWITCH_ICONS, + "Mostra icones en comptes de text per representar aquella configuració del menú que tingui aquestes opcions." + ) /* RGUI: Settings Options */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_POINT, + "Píxel més proper (Ràpid)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_BILINEAR, "Bilineal" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_SINC, + "Sinc/Lanczos3 (Lent)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_UPSCALE_NONE, "Cap" @@ -7465,6 +10466,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_ASPECT_RATIO_16_10_CENTRE, "16:10 (centrat)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_ASPECT_RATIO_21_9_CENTRE, + "21:9 (Centrat)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_ASPECT_RATIO_3_2_CENTRE, "3:2 (centrat)" @@ -7628,10 +10633,22 @@ MSG_HASH( /* XMB: Settings > User Interface > Appearance */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS, + "Segona miniatura" + ) MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Tipus de miniatura que es mostrarà a l’esquerra." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Miniatura de icona" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "El tipus de miniatura que es mostrarà com a icona en les llistes de reproducció." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Fons dinàmic" @@ -7648,6 +10665,34 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_HORIZONTAL_ANIMATION, "Activa l’animació horitzontal pel menú. Això afectarà el rendiment." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_XMB_ANIMATION_HORIZONTAL_HIGHLIGHT, + "Ressalta les icones horitzontals en fer animacions" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_XMB_ANIMATION_HORIZONTAL_HIGHLIGHT, + "Indica l'animació que apareix en moure's entre pestanyes." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_XMB_ANIMATION_MOVE_UP_DOWN, + "Animació de pujada/baixada" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_XMB_ANIMATION_MOVE_UP_DOWN, + "Indica l'animació que apareix en el desplaçament vertical." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_XMB_ANIMATION_OPENING_MAIN_MENU, + "Animació d'obertura i tancament del menú principal" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_XMB_ANIMATION_OPENING_MAIN_MENU, + "Indica l'animació que apareix en obrir un submenú." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, + "Transparència del tema de colors" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_FONT, "Tipografia" @@ -7656,26 +10701,66 @@ MSG_HASH( MENU_ENUM_SUBLABEL_XMB_FONT, "Seleccioneu un altre tipus de lletra principal pel menú." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_RED, + "Color del text (vermell)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_GREEN, + "Color del text (verd)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_BLUE, + "Color del text (blau)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_LAYOUT, "Disposició" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_LAYOUT, + "Selecciona la disposició de la interfície XMB." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_THEME, "Tema d'icones" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_THEME, + "Selecciona un tema d'icones per RetroArch." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_SWITCH_ICONS, "Icones d'interruptors" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_SWITCH_ICONS, + "Mostra icones en comptes de text per representar aquella configuració del menú que tingui aquestes opcions." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, "Efectes d'ombra" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, + "Mostra ombres en totes les icones, miniatures i texts. Afecta lleugerament al rendiment." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, + "Canal de shaders" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, "Color del tema" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, + "Selecciona un tema de colors de fons diferent." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_VERTICAL_THUMBNAILS, + "Disposició vertical de miniatures" + ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_VERTICAL_THUMBNAILS, "Mostra la minatura de l’esquerra a sota de la de la dreta, al costat dret de la pantalla." @@ -7692,10 +10777,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_XMB_VERTICAL_FADE_FACTOR, "Factor d’esvaïment vertical" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_XMB_SHOW_TITLE_HEADER, + "Mostra la capçalera del títol" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_XMB_TITLE_MARGIN, "Marge del títol" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_XMB_TITLE_MARGIN_HORIZONTAL_OFFSET, + "Desplaçament horitzontal del marge del títol" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MAIN_MENU_ENABLE_SETTINGS, + "Mostra la selecció d'ajustaments (Es requereix reiniciar)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, "Mostra la pestanya de configuració que conté els paràmetres del programa." @@ -7791,6 +10888,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDNIGHT_BLUE, "Blau de mitjanit" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_PLAIN, + "Imatge de fons" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, "Submarí" @@ -7823,6 +10924,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Glaçat" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Gris fosc" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Gris clar" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -7834,10 +10943,43 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_COLLAPSE_SIDEBAR, "Manté la barra lateral sempre replegada." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_TRUNCATE_PLAYLIST_NAME, + "Parteix els noms de la llista de reproducció (Es requereix reiniciar)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, + "Endreça les llistes de reproducció després de truncar els noms (Cal reiniciar)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Segona miniatura" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Substitueix el plafó de metadades per una altra miniatura." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Mostra metadades de continguts en moviment" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Factor d’escala de les miniatures" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Ajusta la mida de la barra de miniatures." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Color del tema" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, + "Selecciona un tema de colors diferent." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_WHITE, "Blanc bàsic" @@ -7882,18 +11024,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_PURPLE_RAIN, "Pluja lila" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Substitueix el plafó de metadades per una altra miniatura." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Factor d’escala de les miniatures" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Ajusta la mida de la barra de miniatures." - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -7909,10 +11040,78 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_SWITCH_ICONS, "Icones d'interruptors" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_SWITCH_ICONS, + "Mostra icones en comptes de text per representar aquella configuració del menú que tingui aquestes opcions." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_PLAYLIST_ICONS_ENABLE, + "Icones de les llistes de reproducció (Es requereix reinici)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_PLAYLIST_ICONS_ENABLE, + "Mostra icones del sistema a les llistes de reproducció." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_LANDSCAPE_LAYOUT_OPTIMIZATION, + "Optimitza la disposició en mode horitzontal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_SHOW_NAV_BAR, + "Mostra la barra de navegació" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_AUTO_ROTATE_NAV_BAR, + "Gira automàticament la barra de navegació" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, "Color del tema" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, + "Selecciona un tema de colors de fons diferent." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_TRANSITION_ANIMATION, + "Animació de transició" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_TRANSITION_ANIMATION, + "Permet navegar per les diferents opcions del menú amb una animació fluida." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_THUMBNAIL_VIEW_PORTRAIT, + "Visualització de les miniatures en mode vertical" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_THUMBNAIL_VIEW_PORTRAIT, + "Especifica la forma de mostra les miniatures de les llistes de reproducció amb l'orientació vertical." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_THUMBNAIL_VIEW_LANDSCAPE, + "Miniatures en mode horitzontal" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_THUMBNAIL_VIEW_LANDSCAPE, + "Especifica la forma de mostra les miniatures de les llistes de reproducció amb l'orientació horitzontal." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_DUAL_THUMBNAIL_LIST_VIEW_ENABLE, + "Mostra les miniatures secundàries en les llistes" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_THUMBNAIL_BACKGROUND_ENABLE, + "Genera fons de les miniatures" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAILS_MATERIALUI, + "Miniatura principal" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_MATERIALUI, + "Segona miniatura" + ) /* MaterialUI: Settings Options */ @@ -7936,6 +11135,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, "Groc" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_MATERIALUI_DARK, + "Material UI Fosc" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GRUVBOX_DARK, "Grubvox Fosc" @@ -8024,6 +11227,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_LANDSCAPE_LAYOUT_OPTIMIZATION_ALWAYS, "Activa" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_LANDSCAPE_LAYOUT_OPTIMIZATION_EXCLUDE_THUMBNAIL_VIEWS, + "Exclou les imatges en miniatura" + ) /* Qt (Desktop Menu) */ @@ -8063,14 +11270,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_CLOSED_DOCKS, "Finestres tancades" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_SHADER_PARAMS, + "Paràmetres del shader" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS, "Configuració" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS, + "Recorda la posició de les finestres acoblades:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, + "Recorda la geometria de la finestra:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB, + "Recorda l'última pestanya de l'explorador de continguts:" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME, "Tema:" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT, + "" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK, "Fosc" @@ -8091,14 +11318,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_HELP, "&Ajuda" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_ABOUT, + "Sobre RetroArch" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_HELP_DOCUMENTATION, "Documentació" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOAD_CUSTOM_CORE, + "Carrega el nucli personalitzat..." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_LOAD_CORE, "Carregar Nucli" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_LOADING_CORE, + "Carregant el nucli..." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_NAME, "Nom" @@ -8123,6 +11362,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER_UP, "Amunt" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER, + "Explorador de continguts" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_BOXART, "Caràtula" @@ -8167,6 +11410,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_NETWORK_ERROR, "Error de xarxa" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESTART_TO_TAKE_EFFECT, + "Cal reiniciar el programa per a què els canvis tinguin efecte." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_LOG, "Registre" @@ -8175,6 +11422,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ITEMS_COUNT, "%1 elements" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DROP_IMAGE_HERE, + "Arrossega aquí una imatge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, + "No mostris una altra vegada" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_STOP, "Atura" @@ -8183,10 +11438,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ASSOCIATE_CORE, "Nucli associat" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_HIDDEN_PLAYLISTS, + "Llistes de reproducció ocultes" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_HIDE, "Amagar" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR, + "Color destacat:" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_CHOOSE, "Escollir..." @@ -8203,10 +11466,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_CUSTOM_THEME, "Tema personalitzat" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_PATH_IS_BLANK, + "L'adreça del fitxer està buida." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_FILE_IS_EMPTY, "L'arxiu està buit." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED, + "No es pot obrir el fitxer per llegir-lo." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_WRITE_OPEN_FAILED, + "No es pot obrir el fitxer per escriure-hi." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST, + "El fitxer no existeix." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST, + "Suggereix el nucli carregat com a primera opció:" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ZOOM, "Ampliar" @@ -8231,14 +11514,58 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_PROGRESS, "Progrés:" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT, + "Nombre màxim d'entrades a 'Totes les llistes de reproducció':" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT, + "Nombre màxim d'entrades a 'Totes les llistes de reproducció':" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES, + "Mostra fitxers i carpetes ocults:" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_NEW_PLAYLIST, "Nova llista de reproducció" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ENTER_NEW_PLAYLIST_NAME, + "Introdueix el nom d'una llista nova:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DELETE_PLAYLIST, + "Esborrar llista de reproducció" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RENAME_PLAYLIST, + "Reanomena la llista de reproducció" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST, + "Estàs segur que vols esborrar la llista de reproducció \"%1\"?" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_QUESTION, "Qüestió" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_DELETE_FILE, + "No es pot esborrar aquest fitxer." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_RENAME_FILE, + "No es pot canviar el nom a aquest fitxer." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES, + "Creant llista de fitxers..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, + "Afegint fitxers a la llista de reproducció..." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, "Element de la llista de reproducció" @@ -8411,6 +11738,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THUMBNAIL_CACHE_LIMIT, "Límit de la memòria cau de miniatures:" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THUMBNAIL_DROP_SIZE_LIMIT, + "Límit de la mida de miniatures arrosegades:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS, + "Descarrega totes les miniatures" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_ENTIRE_SYSTEM, "Sistema sencer" @@ -8419,6 +11754,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALL_THUMBNAILS_THIS_PLAYLIST, "Aquesta llista de reproducció" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_PACK_DOWNLOADED_SUCCESSFULLY, + "Les miniatures s'han descarregat correctament." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_PLAYLIST_THUMBNAIL_PROGRESS, + "Obtingudes: %1 Fallades: %2" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_CORE_OPTIONS, "Opcions del nucli" @@ -8434,6 +11777,18 @@ MSG_HASH( /* Unsorted */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, + "Opcions de l'actualitzador de nuclis" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, + "Comptes Cheevos" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, + "Punt de connexió amb la llista de comptes" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, "Turbo/zona morta" @@ -8446,10 +11801,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_DISK, "No heu seleccionat cap disc" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, + "Comptadors de la interfície" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, "Menú horitzontal" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND, + "Amaga les descripcions de nuclis" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, + "Mostrar etiquetes amb descripcions d'entrada" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, "Superposició en Pantalla" @@ -8458,6 +11825,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, "Historial" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOAD_CONTENT_HISTORY, + "Selecciona el contingut des d'una llista de reproducció recent." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS, "Multimèdia" @@ -8466,6 +11837,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SUBSYSTEM_SETTINGS, "Subsistemes" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SUBSYSTEM_SETTINGS, + "Accedeix a la configuració dels subsistemes pel contingut actual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SUBSYSTEM_CONTENT_INFO, + "Contingut actual: %s" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, + "No s'han trobat servidors del joc en xarxa." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_NETPLAY_CLIENTS_FOUND, + "No s'han trobat clients del joc en xarxa." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, + "No hi ha comptadors de rendiment." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, "No hi ha llistes de reproducció." @@ -8478,6 +11869,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ONLINE, "En línia" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PORT_DEVICE_NAME, + "Port %d Nom dispositiu: %s (#%d)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PORT_DEVICE_INFO, + "Nom per mostrar del dispositiu: %s\nNom de configuració del dispositiu: %s\n VID/PID del dispositiu: %d/%d" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SETTINGS, "Configuració dels trucs" @@ -8486,6 +11885,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_SETTINGS, "Comença o continua la cerca de trucs" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_MUSIC, + "Reprodueix en el reproductor de mèdia" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SECONDS, "segons" @@ -8515,8 +11918,16 @@ MSG_HASH( "Teclat" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Fes servir el visualitzador d’imatges integrat" + MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Nombre màxim d'imatges en la cadena d'intercanvi" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Avisa al controlador de vídeo que faci servir un mode de búfer concret." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WAITABLE_SWAPCHAINS, + "Cadenes d'intercanvi en espera" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WAITABLE_SWAPCHAINS, @@ -8526,6 +11937,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_FRAME_LATENCY, "Latència de fotograma màxima" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MAX_FRAME_LATENCY, + "Avisa al controlador de vídeo que faci servir un mode de búfer concret." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, + "Modifica el preajust de shaders que utilitza el menú actualment." + ) MSG_HASH( MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, "Shader predefinit" @@ -8554,10 +11973,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, "Sobrenom: %s" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_LOOK, + "Cercant per contingut compatible..." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_NO_CORE, "No s’ha trobat cap nucli" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_NO_PLAYLISTS, + "No s'han trobat llistes de reproducció" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, + "S'ha trobat contingut compatible" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_NOT_FOUND, + "Error en localitzar el contingut corresponent segons el seu CRC o el nom del fitxer" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_START_GONG, "Iniciar gong" @@ -8569,6 +12004,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, "Relació d’aspecte automàtica" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, + "Sobrenom (LAN): %s" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STATUS, "Estat" @@ -8581,22 +12020,62 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, "Relació personalitzada" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, + "Compatibilitat amb l'enregistrament" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_PATH, + "Desa la gravació com a..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, + "Desa les gravacions a la carpeta assignada" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_MATCH_IDX, "Veure coincidència #" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_MATCH_IDX, + "Selecciona la coincidència que vols veure." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, "Força la relació d’aspecte" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Continua" + MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, + "Selecciona des d'una llista de reproducció" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, + "Mostra la llista de coincidències" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_CREATE_OPTION, + "Crea un truc a partir d'aquesta coincidència" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, + "Elimina aquesta coincidència" ) MSG_HASH( /* FIXME Still exists in a comment about being removed */ MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, "Opacitat del peu de pàgina" ) +MSG_HASH( /* FIXME Still exists in a comment about being removed */ + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, + "Modifica l'opacitat del peu de pàgina." + ) +MSG_HASH( /* FIXME Still exists in a comment about being removed */ + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, + "Opacitat de l'encapçalament" + ) +MSG_HASH( /* FIXME Still exists in a comment about being removed */ + MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, + "Modifica l'opacitat de la capçalera de la pàgina." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, "Joc en línia" @@ -8605,6 +12084,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, "Iniciar contingut" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_PATH, + "Ruta de l'historial de continguts" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_OUTPUT_DISPLAY_ID, + "ID de la pantalla de sortida" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_OUTPUT_DISPLAY_ID, + "Selecciona el port de sortida connectat a la pantalla CRT." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HELP, "Ajuda" @@ -8613,6 +12104,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CLEAR_SETTING, "Netejar" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, + "Solució de problemes d'àudio/vídeo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, + "Canvia el controlador virtual superposat" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, "S’està carregant el contingut" @@ -8637,6 +12136,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MANAGEMENT, "Configuració de la base de dades" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, + "Retardar fotogrames durant el joc en xarxa" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, "Explora la xarxa local" @@ -8645,6 +12148,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, "Cerca amfitrions de joc a la xarxa local i s’hi connecta." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, + "Client de joc en xarxa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, + "Espectador al joc en línia" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, "Descripció" @@ -8878,6 +12389,10 @@ MSG_HASH( /* FIXME Should be MSG_ */ MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, "El joc en línia començarà quan s’hagi carregat el contingut." ) +MSG_HASH( + MSG_NETPLAY_NEED_CONTENT_LOADED, + "El contingut s'ha de carregar abans d'iniciar el joc en xarxa." + ) MSG_HASH( /* FIXME Should be MSG_ */ MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, "No s’ha pogut trobar cap nucli o fitxer de contingut adequats, carregueu-los manualment." @@ -8930,6 +12445,10 @@ MSG_HASH( MSG_NETPLAY_LAN_SCAN_COMPLETE, "S’ha completat la cerca de partides en línia." ) +MSG_HASH( + MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, + "Ho sentim, aquest sistema no està implementat: els nuclis que no requereixen continguts, no poden fer servir. el joc en xarxa." + ) MSG_HASH( MSG_NATIVE, "Nativa" @@ -8938,6 +12457,10 @@ MSG_HASH( MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, "S’ha rebut una ordre de joc en línia desconeguda" ) +MSG_HASH( + MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, + "Aquest fitxer ja existeix. Desant-lo a la memòria cau de còpia de seguretat" + ) MSG_HASH( MSG_GOT_CONNECTION_FROM, "S’ha rebut una connexió de: «%s»" @@ -8946,10 +12469,142 @@ MSG_HASH( MSG_GOT_CONNECTION_FROM_NAME, "S’ha rebut una connexió de: «%s (%s)»" ) +MSG_HASH( + MSG_PUBLIC_ADDRESS, + "L'assignació de ports pel joc en xarxa s'ha completat" + ) +MSG_HASH( + MSG_PRIVATE_OR_SHARED_ADDRESS, + "La xarxa externa té una adreça privada o compartida. Podries utilitzar un servidor intermedi." + ) +MSG_HASH( + MSG_UPNP_FAILED, + "Error en assignar ports UPnP pel joc en xarxa" + ) +MSG_HASH( + MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, + "No s'ha introduït arguments i no hi ha menú integrant, mostrant ajuda..." + ) +MSG_HASH( + MSG_SETTING_DISK_IN_TRAY, + "Introduint disc a la safata" + ) MSG_HASH( MSG_WAITING_FOR_CLIENT, "Esperant al client..." ) +MSG_HASH( + MSG_ROOM_NOT_CONNECTABLE, + "No es pot connectar a la teva sala des d'internet." + ) +MSG_HASH( + MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, + "Has deixat el joc" + ) +MSG_HASH( + MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, + "T'has unit com a jugador %u" + ) +MSG_HASH( + MSG_NETPLAY_YOU_HAVE_JOINED_WITH_INPUT_DEVICES_S, + "Has accedit amb el dispositiu d'entrada %.*s" + ) +MSG_HASH( + MSG_NETPLAY_PLAYER_S_LEFT, + "El jugador %.*s ha deixat el joc" + ) +MSG_HASH( + MSG_NETPLAY_S_HAS_JOINED_AS_PLAYER_N, + "%.*s s'ha unit com el jugador %u" + ) +MSG_HASH( + MSG_NETPLAY_S_HAS_JOINED_WITH_INPUT_DEVICES_S, + "%.*s ha accedit amb el dispositiu %.*s" + ) +MSG_HASH( + MSG_NETPLAY_OUT_OF_DATE, + "Un client del joc en xarxa fa servir una versió antiga de RetroArch. No es pot connectar amb el client." + ) +MSG_HASH( + MSG_NETPLAY_DIFFERENT_CORES, + "Un client del joc en xarxa està fent servir un nucli diferent. No es pot connectar amb el client." + ) +MSG_HASH( + MSG_NETPLAY_ENDIAN_DEPENDENT, + "Aquest nucli no suporta el joc en xarxa entre aquestes plataformes" + ) +MSG_HASH( + MSG_NETPLAY_PLATFORM_DEPENDENT, + "Aquest nucli no és compatible amb el joc en xarxa entre diferents plataformes" + ) +MSG_HASH( + MSG_NETPLAY_ENTER_PASSWORD, + "Introdueix la contrasenya del servidor de joc:" + ) +MSG_HASH( + MSG_NETPLAY_ENTER_CHAT, + "Escriu el missatge per iniciar la sessió:" + ) +MSG_HASH( + MSG_DISCORD_CONNECTION_REQUEST, + "Vols permetre la connexió de l'usuari:" + ) +MSG_HASH( + MSG_NETPLAY_INCORRECT_PASSWORD, + "Contrasenya incorrecta" + ) +MSG_HASH( + MSG_NETPLAY_SERVER_NAMED_HANGUP, + "\"%s\" s'ha desconnectat" + ) +MSG_HASH( + MSG_NETPLAY_SERVER_HANGUP, + "Un client de joc de xarxa s'ha desconnectat" + ) +MSG_HASH( + MSG_NETPLAY_CLIENT_HANGUP, + "Joc en xarxa desconnectat" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, + "No tens permís per jugar" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, + "No hi ha lloc per més jugadors" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY_NOT_AVAILABLE, + "Els dispositius d'entrada sol·licitats no estan disponibles" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY, + "No es pot canviar el mode de joc" + ) +MSG_HASH( + MSG_NETPLAY_PEER_PAUSED, + "El client del joc en xarxa \"%s\" està en pausa" + ) +MSG_HASH( + MSG_NETPLAY_CHANGED_NICK, + "El teu sobrenom ha canviat a \"%s\"" + ) +MSG_HASH( + MSG_NETPLAY_KICKED_CLIENT_S, + "Client expulsat: \"%s\"" + ) +MSG_HASH( + MSG_NETPLAY_FAILED_TO_KICK_CLIENT_S, + "Error en expulsar al client: \"%s\"" + ) +MSG_HASH( + MSG_NETPLAY_BANNED_CLIENT_S, + "Client prohibit: \"%s\"" + ) +MSG_HASH( + MSG_NETPLAY_FAILED_TO_BAN_CLIENT_S, + "Error en vetar el client: \"%s\"" + ) MSG_HASH( MSG_NETPLAY_STATUS_PLAYING, "Jugant" @@ -8962,6 +12617,14 @@ MSG_HASH( MSG_NETPLAY_CLIENT_DEVICES, "Dispositius" ) +MSG_HASH( + MSG_NETPLAY_CHAT_SUPPORTED, + "Compatibilitat amb el xat" + ) +MSG_HASH( + MSG_NETPLAY_SLOWDOWNS_CAUSED, + "Alentiments provocats" + ) MSG_HASH( MSG_AUDIO_VOLUME, @@ -8975,6 +12638,10 @@ MSG_HASH( MSG_CAPABILITIES, "Capacitats" ) +MSG_HASH( + MSG_CONNECTING_TO_NETPLAY_HOST, + "Connectant al servidor de joc en xarxa" + ) MSG_HASH( MSG_CONNECTING_TO_PORT, "S’està connectant al port" @@ -9083,14 +12750,38 @@ MSG_HASH( MSG_PLAYLIST_MANAGER_REFRESH_DAT_FILE_TOO_LARGE, "Ha fallat l’actualització. El fitxer DAT d’arcade és massa gran (no hi ha prou memòria): " ) +MSG_HASH( + MSG_ADDED_TO_FAVORITES, + "S'ha afegit als favorits" + ) +MSG_HASH( + MSG_ADD_TO_FAVORITES_FAILED, + "Error en afegir preferits: la llista de reproducció està plena" + ) +MSG_HASH( + MSG_ADDED_TO_PLAYLIST, + "S'ha afegit a la llista de reproducció" + ) +MSG_HASH( + MSG_ADD_TO_PLAYLIST_FAILED, + "Error en afegir a la llista de reproducció: la llista de reproducció està plena" + ) MSG_HASH( MSG_SET_CORE_ASSOCIATION, "Nucli definit: " ) +MSG_HASH( + MSG_RESET_CORE_ASSOCIATION, + "S'ha restablert l'associació del nucli amb l'element de la llista." + ) MSG_HASH( MSG_APPENDED_DISK, "Disc afegit" ) +MSG_HASH( + MSG_FAILED_TO_APPEND_DISK, + "Error en afegir el disc" + ) MSG_HASH( MSG_APPLICATION_DIR, "Directori de l’aplicació" @@ -9123,6 +12814,10 @@ MSG_HASH( MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, "S’ha desat correctament el perfil del controlador." ) +MSG_HASH( + MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY_NAMED, + "El perfil de controlador s'ha desat a la carpeta corresponent com:\n\"%s\"" + ) MSG_HASH( MSG_AUTOSAVE_FAILED, "No s’ha pogut inicialitzar el desament automàtic." @@ -9159,6 +12854,10 @@ MSG_HASH( MSG_CONTENT_CRC32S_DIFFER, "Els CRC32 dels continguts són diferents. No es poden usar jocs diferents." ) +MSG_HASH( + MSG_CONTENT_NETPACKET_CRC32S_DIFFER, + "El servidor està executant un joc diferent." + ) MSG_HASH( MSG_PING_TOO_HIGH, "El vostre ping és massa alt per aquest amfitrió." @@ -9191,6 +12890,34 @@ MSG_HASH( MSG_CORE_OPTIONS_FLUSH_FAILED, "No s’han pogut desar les opcions del nucli a:" ) +MSG_HASH( + MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, + "No s'ha trobat un altre controlador" + ) +MSG_HASH( + MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, + "No s'ha pogut trobar un sistema compatible." + ) +MSG_HASH( + MSG_COULD_NOT_FIND_VALID_DATA_TRACK, + "No s'ha trobat una pista de dades vàlida" + ) +MSG_HASH( + MSG_COULD_NOT_OPEN_DATA_TRACK, + "No es pot obrir la pista de dades" + ) +MSG_HASH( + MSG_COULD_NOT_READ_CONTENT_FILE, + "No es pot llegir el contingut" + ) +MSG_HASH( + MSG_COULD_NOT_READ_MOVIE_HEADER, + "No es pot llegir la capçalera de la repetició." + ) +MSG_HASH( + MSG_COULD_NOT_READ_STATE_FROM_MOVIE, + "No es pot llegir l'estat des de la repetició." + ) MSG_HASH( MSG_CUSTOM_TIMING_GIVEN, "Temps personalitzat donat" @@ -9259,10 +12986,38 @@ MSG_HASH( MSG_ERROR_REMOVING_CORE_OPTIONS_FILE, "S’ha produït un error en suprimir el fitxer d’opcions del nucli." ) +MSG_HASH( + MSG_ERROR_SAVING_REMAP_FILE, + "Error en desar el fitxer de reassignació." + ) +MSG_HASH( + MSG_ERROR_REMOVING_REMAP_FILE, + "Error en eliminar el fitxer d'assignació." + ) +MSG_HASH( + MSG_ERROR_SAVING_SHADER_PRESET, + "Error en desar el preajust de shaders." + ) +MSG_HASH( + MSG_EXTERNAL_APPLICATION_DIR, + "Directori extern de l'aplicació" + ) MSG_HASH( MSG_EXTRACTING, "Extraient" ) +MSG_HASH( + MSG_EXTRACTING_FILE, + "Extraient el fitxer" + ) +MSG_HASH( + MSG_FAILED_SAVING_CONFIG_TO, + "Error desant la configuració a" + ) +MSG_HASH( + MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, + "Error en acceptar a l'espectador." + ) MSG_HASH( MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, "No s’ha pogut assignar memòria pel contingut apedaçat..." @@ -9307,6 +13062,10 @@ MSG_HASH( MSG_FAILED_TO_LOAD_OVERLAY, "No s’ha pogut carregar la superposició." ) +MSG_HASH( + MSG_OSK_OVERLAY_NOT_SET, + "No s'ha configurat la superposició de teclat." + ) MSG_HASH( MSG_FAILED_TO_LOAD_STATE, "No s’ha pogut carregar l’estat de" @@ -9431,6 +13190,18 @@ MSG_HASH( MSG_FOUND_LAST_STATE_SLOT, "S'ha trobat el darrer espai d'estat" ) +MSG_HASH( + MSG_FOUND_LAST_REPLAY_SLOT, + "S'ha trobat l'última posició de repetició" + ) +MSG_HASH( + MSG_REPLAY_LOAD_STATE_FAILED_INCOMPAT, + "No prové de la gravació actual" + ) +MSG_HASH( + MSG_REPLAY_LOAD_STATE_HALT_INCOMPAT, + "No és compatible amb les repiticions" + ) MSG_HASH( MSG_FOUND_SHADER, "S'ha trobat el shader" @@ -9463,6 +13234,10 @@ MSG_HASH( MSG_GAME_FOCUS_OFF, "Focus al joc desactivat" ) +MSG_HASH( + MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, + "La renderització d'aquest nucli es fa per maquinari. Els enregistraments han de tenir shaders aplicats." + ) MSG_HASH( MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, "La suma de verificació inflada no coincideix amb el CRC32." @@ -9471,6 +13246,22 @@ MSG_HASH( MSG_INPUT_CHEAT, "Introduir truc" ) +MSG_HASH( + MSG_INPUT_CHEAT_FILENAME, + "Introdueix el nom del fitxer de trucs" + ) +MSG_HASH( + MSG_INPUT_PRESET_FILENAME, + "Introdueix el nom del fitxer" + ) +MSG_HASH( + MSG_INPUT_OVERRIDE_FILENAME, + "Introdueix el nom del fitxer de personalització" + ) +MSG_HASH( + MSG_INPUT_REMAP_FILENAME, + "Introdueix el nom del fitxer de reassignació" + ) MSG_HASH( MSG_INPUT_RENAME_ENTRY, "Reanomenar títol" @@ -9479,6 +13270,18 @@ MSG_HASH( MSG_INTERFACE, "Interfície" ) +MSG_HASH( + MSG_INTERNAL_STORAGE, + "Emmagatzematge intern" + ) +MSG_HASH( + MSG_REMOVABLE_STORAGE, + "Emmagatzematge extraïble" + ) +MSG_HASH( + MSG_INVALID_NICKNAME_SIZE, + "La mida del sobrenom no és vàlida." + ) MSG_HASH( MSG_IN_BYTES, "en bytes" @@ -9491,10 +13294,42 @@ MSG_HASH( MSG_IN_GIGABYTES, "en gigabytes" ) +MSG_HASH( + MSG_LIBRETRO_ABI_BREAK, + "està compilat per una versió diferent de libretro que aquesta compilació de libretro." + ) +MSG_HASH( + MSG_LIBRETRO_FRONTEND, + "Interfície d'usuari per Libretro" + ) +MSG_HASH( + MSG_LOADED_STATE_FROM_SLOT, + "Carrega el desat ràpid %d." + ) +MSG_HASH( + MSG_LOADED_STATE_FROM_SLOT_AUTO, + "Carrega l'estat des de la ranura #-1 (Automàticament)." + ) MSG_HASH( MSG_LOADING, "Carregant" ) +MSG_HASH( + MSG_FIRMWARE, + "Falten diversos fitxers de firmware" + ) +MSG_HASH( + MSG_LOADING_CONTENT_FILE, + "Carregant el contingut del fitxer" + ) +MSG_HASH( + MSG_LOADING_HISTORY_FILE, + "Carregant el fitxer de l'historial" + ) +MSG_HASH( + MSG_LOADING_FAVORITES_FILE, + "Carregant el fitxer de preferits" + ) MSG_HASH( MSG_LOADING_STATE, "Carregant l'estat" @@ -9503,18 +13338,138 @@ MSG_HASH( MSG_MEMORY, "Memòria" ) +MSG_HASH( + MSG_MOVIE_FILE_IS_NOT_A_VALID_REPLAY_FILE, + "El fitxer de repetició d'entrada no és un fitxer vàlid." + ) +MSG_HASH( + MSG_MOVIE_PLAYBACK_ENDED, + "La reproducció s'ha acabat." + ) +MSG_HASH( + MSG_MOVIE_RECORD_STOPPED, + "Aturant la gravació de la partida." + ) +MSG_HASH( + MSG_NETPLAY_FAILED, + "Error en iniciar el joc en xarxa." + ) +MSG_HASH( + MSG_NETPLAY_UNSUPPORTED, + "El nucli no admet joc en xarxa." + ) +MSG_HASH( + MSG_NO_CONTENT_STARTING_DUMMY_CORE, + "No hi ha contingut, iniciant un nucli buit." + ) +MSG_HASH( + MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, + "No s'ha sobreescrit cap desat ràpid." + ) +MSG_HASH( + MSG_NO_STATE_HAS_BEEN_LOADED_YET, + "No s'ha carregat encara el desat ràpid." + ) +MSG_HASH( + MSG_OVERRIDES_ERROR_SAVING, + "Error en desar la personalització." + ) +MSG_HASH( + MSG_OVERRIDES_ERROR_REMOVING, + "Error en eliminar les personalitzacions." + ) +MSG_HASH( + MSG_OVERRIDES_SAVED_SUCCESSFULLY, + "S'ha desat la personalització correctament." + ) +MSG_HASH( + MSG_OVERRIDES_REMOVED_SUCCESSFULLY, + "S'han eliminat les personalitzacions." + ) +MSG_HASH( + MSG_OVERRIDES_UNLOADED_SUCCESSFULLY, + "S'han descarregat les personalitzacions correctament." + ) +MSG_HASH( + MSG_OVERRIDES_NOT_SAVED, + "No hi ha res a desar. No s'han desat les personalitzacions." + ) +MSG_HASH( + MSG_OVERRIDES_ACTIVE_NOT_SAVING, + "La funció desat està bloquejada. Les personalitzacions estan actives." + ) MSG_HASH( MSG_PAUSED, "En pausa." ) +MSG_HASH( + MSG_READING_FIRST_DATA_TRACK, + "Llegint la primera pista de dades..." + ) +MSG_HASH( + MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, + "Gravació acabada pel canvi de mida de la finestra." + ) MSG_HASH( MSG_RECORDING_TO, "Enregistrant a" ) +MSG_HASH( + MSG_REDIRECTING_CHEATFILE_TO, + "Redirigint el fitxer de trucs a" + ) +MSG_HASH( + MSG_REDIRECTING_SAVEFILE_TO, + "Redirigint fitxer de desat a" + ) +MSG_HASH( + MSG_REDIRECTING_SAVESTATE_TO, + "Redirigint el fitxer d'estats desats a" + ) +MSG_HASH( + MSG_REMAP_FILE_SAVED_SUCCESSFULLY, + "El fitxer de personalització s'ha desat correctament." + ) +MSG_HASH( + MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, + "S'ha eliminat el fitxer d'assignació." + ) +MSG_HASH( + MSG_REMAP_FILE_RESET, + "Totes les opcions d'entrada han sigut restablertes." + ) +MSG_HASH( + MSG_REMOVED_DISK_FROM_TRAY, + "Disc eliminat de la safata." + ) +MSG_HASH( + MSG_REMOVING_TEMPORARY_CONTENT_FILE, + "Eliminant el contingut temporal" + ) MSG_HASH( MSG_RESET, "Reiniciar" ) +MSG_HASH( + MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, + "Reiniciant la gravació a causa del reinici del controlador." + ) +MSG_HASH( + MSG_RESTORED_OLD_SAVE_STATE, + "Restaurant un estat desat anterior." + ) +MSG_HASH( + MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, + "Shaders: Restaurant l'ajust predeterminat a" + ) +MSG_HASH( + MSG_REVERTING_SAVEFILE_DIRECTORY_TO, + "Revertint la carpeta de fitxers de desat a" + ) +MSG_HASH( + MSG_REVERTING_SAVESTATE_DIRECTORY_TO, + "Revertint la carpeta de fitxers de desats a" + ) MSG_HASH( MSG_REWINDING, "Retrocedint." @@ -9523,6 +13478,42 @@ MSG_HASH( MSG_REWIND_UNSUPPORTED, "No està disponible el rebobinat perquè aquest nucli no té suport d'estat desats serialitzats." ) +MSG_HASH( + MSG_REWIND_INIT, + "Inicialitzant la memòria cau de rebobinat amb la mida" + ) +MSG_HASH( + MSG_REWIND_INIT_FAILED, + "Error en iniciar la memòria intermèdia de rebobinat. La funció de rebobinat es desactivarà." + ) +MSG_HASH( + MSG_REWIND_INIT_FAILED_THREADED_AUDIO, + "La implementació de l'àudio fa servir multifil. No es pot rebobinar." + ) +MSG_HASH( + MSG_REWIND_REACHED_END, + "S'ha arribat al final de la memòria intermèdia de rebobinat." + ) +MSG_HASH( + MSG_SAVED_NEW_CONFIG_TO, + "Desa la nova configuració a" + ) +MSG_HASH( + MSG_SAVED_STATE_TO_SLOT, + "Estat desat a la ranura #%d." + ) +MSG_HASH( + MSG_SAVED_STATE_TO_SLOT_AUTO, + "Desat l'estat a la ranura #-1 (Automàtic)." + ) +MSG_HASH( + MSG_SAVED_SUCCESSFULLY_TO, + "Desat correctament a" + ) +MSG_HASH( + MSG_SAVING_RAM_TYPE, + "Desant el tipus de memòria RAM" + ) MSG_HASH( MSG_SAVING_STATE, "Desant estat" @@ -9531,6 +13522,22 @@ MSG_HASH( MSG_SCANNING, "Escanejant" ) +MSG_HASH( + MSG_SCANNING_OF_DIRECTORY_FINISHED, + "S'ha acabat l'escaneig del directori." + ) +MSG_HASH( + MSG_SENDING_COMMAND, + "Enviant comanda" + ) +MSG_HASH( + MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, + "Hi ha diversos trucs definits explícitament, ignorant-los tots..." + ) +MSG_HASH( + MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, + "S'ha desat la personalització de shaders correctament." + ) MSG_HASH( MSG_SLOW_MOTION, "A càmera lenta." @@ -9539,10 +13546,30 @@ MSG_HASH( MSG_FAST_FORWARD, "Avançament ràpid." ) +MSG_HASH( + MSG_SLOW_MOTION_REWIND, + "Repetició a càmera lenta." + ) +MSG_HASH( + MSG_SKIPPING_SRAM_LOAD, + "Ignora la càrrega de SRAM." + ) +MSG_HASH( + MSG_SRAM_WILL_NOT_BE_SAVED, + "No es desarà la SRAM." + ) MSG_HASH( MSG_BLOCKING_SRAM_OVERWRITE, "S’està blocant la sobreescriptura de SRAM" ) +MSG_HASH( + MSG_STARTING_MOVIE_PLAYBACK, + "Reproduint la repetició." + ) +MSG_HASH( + MSG_STARTING_MOVIE_RECORD_TO, + "Iniciant gravació de la repetició a" + ) MSG_HASH( MSG_STATE_SIZE, "Mida de l'estat" @@ -9555,6 +13582,34 @@ MSG_HASH( MSG_REPLAY_SLOT, "Posició de repitició" ) +MSG_HASH( + MSG_TAKING_SCREENSHOT, + "S'està fent una captura de pantalla." + ) +MSG_HASH( + MSG_SCREENSHOT_SAVED, + "S'ha desat la captura de pantalla" + ) +MSG_HASH( + MSG_ACHIEVEMENT_UNLOCKED, + "Assoliment desbloquejat" + ) +MSG_HASH( + MSG_RARE_ACHIEVEMENT_UNLOCKED, + "Assoliment poc freqüent assolit" + ) +MSG_HASH( + MSG_LEADERBOARD_STARTED, + "Intent d'entrar a la taula de classificació iniciat" + ) +MSG_HASH( + MSG_LEADERBOARD_FAILED, + "Error en l'intent d'accedir a la taula de classificacions" + ) +MSG_HASH( + MSG_LEADERBOARD_SUBMISSION, + "Enviat %s per %s" /* Submitted [value] for [leaderboard name] */ + ) MSG_HASH( MSG_LEADERBOARD_RANK, "Rang: %d" /* Rank: [leaderboard rank] */ @@ -9563,6 +13618,26 @@ MSG_HASH( MSG_LEADERBOARD_BEST, "Millor: %s" /* Best: [value] */ ) +MSG_HASH( + MSG_CHANGE_THUMBNAIL_TYPE, + "Canvia tipus miniatura" + ) +MSG_HASH( + MSG_TOGGLE_FULLSCREEN_THUMBNAILS, + "Miniatures a pantalla complerta" + ) +MSG_HASH( + MSG_TOGGLE_CONTENT_METADATA, + "Mostra metadates" + ) +MSG_HASH( + MSG_NO_THUMBNAIL_AVAILABLE, + "No hi ha miniatures disponibles" + ) +MSG_HASH( + MSG_NO_THUMBNAIL_DOWNLOAD_POSSIBLE, + "Ja s'han cercat totes les possibles caràtules descarregables per aquest element de la llista de reproducció." + ) MSG_HASH( MSG_PRESS_AGAIN_TO_QUIT, "Premeu una altra vegada per sortir..." @@ -9571,6 +13646,14 @@ MSG_HASH( MSG_TO, "a" ) +MSG_HASH( + MSG_UNDID_LOAD_STATE, + "S'ha desfet la càrrega del desat ràpid." + ) +MSG_HASH( + MSG_UNDOING_SAVE_STATE, + "Desfer desat ràpid" + ) MSG_HASH( MSG_UNKNOWN, "Desconegut" @@ -9579,10 +13662,58 @@ MSG_HASH( MSG_UNPAUSED, "Fi de la pausa." ) +MSG_HASH( + MSG_UNRECOGNIZED_COMMAND, + "S'ha rebut una comanda no reconeguda: \"%s\". \n" + ) +MSG_HASH( + MSG_USING_CORE_NAME_FOR_NEW_CONFIG, + "Fes servir el nom del nucli per la nova configuració." + ) +MSG_HASH( + MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, + "Fent servir un nucli buit. Ometent la gravació." + ) +MSG_HASH( + MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, + "Connecta el dispositiu a un port vàlid." + ) +MSG_HASH( + MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, + "Desconnecta el dispositiu del port" + ) MSG_HASH( MSG_VALUE_REBOOTING, "Reiniciant..." ) +MSG_HASH( + MSG_VALUE_SHUTTING_DOWN, + "S'està apagant..." + ) +MSG_HASH( + MSG_VERSION_OF_LIBRETRO_API, + "Versió de la API de Libretro" + ) +MSG_HASH( + MSG_VIRTUAL_DISK_TRAY_EJECT, + "Error en obrir la safata de discs virtual." + ) +MSG_HASH( + MSG_VIRTUAL_DISK_TRAY_CLOSE, + "Error en tancar la safata de discs virtual." + ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Carrega automàticament el desat ràpid des de" + ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FAILED, + "Error en carregar automàticament l'estat desat des de \"%s\"." + ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_SUCCEEDED, + "S'ha carregat correctament l'estat desat des de \"%s\"." + ) MSG_HASH( MSG_DEVICE_CONFIGURED_IN_PORT, "configurat al port" @@ -9591,6 +13722,10 @@ MSG_HASH( MSG_DEVICE_CONFIGURED_IN_PORT_NR, "Configurat %s al port %u" ) +MSG_HASH( + MSG_DEVICE_DISCONNECTED_FROM_PORT, + "desconnectat del port" + ) MSG_HASH( MSG_DEVICE_DISCONNECTED_FROM_PORT_NR, "Desconnectat %s del port %u" @@ -9603,6 +13738,10 @@ MSG_HASH( MSG_DEVICE_NOT_CONFIGURED_NR, "No ha sigut configurat %s (%u/%u)" ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "no està configurat, es fa servir l'opció secundària" + ) MSG_HASH( MSG_DEVICE_NOT_CONFIGURED_FALLBACK_NR, "No ha sigut configurat %s (%u/%u) usant l'opció secundària" @@ -9671,6 +13810,126 @@ MSG_HASH( MSG_INPUT_KIOSK_MODE_PASSWORD_NOK, "Contrasenya incorrecta." ) +MSG_HASH( + MSG_CONFIG_OVERRIDE_LOADED, + "S'ha carregat la configuració personalitzada." + ) +MSG_HASH( + MSG_GAME_REMAP_FILE_LOADED, + "S'ha carregat el fitxer d'assignacions del joc." + ) +MSG_HASH( + MSG_DIRECTORY_REMAP_FILE_LOADED, + "Carregat el fitxer d'assignació de la carpeta de continguts." + ) +MSG_HASH( + MSG_CORE_REMAP_FILE_LOADED, + "S'ha carregat el fitxer d'assignacions del nucli." + ) +MSG_HASH( + MSG_REMAP_FILE_FLUSHED, + "Les opcions d'assignació d'entrada s'han desat a:" + ) +MSG_HASH( + MSG_REMAP_FILE_FLUSH_FAILED, + "Error en desar les opcions d'assignació d'entrada a:" + ) +MSG_HASH( + MSG_RUNAHEAD_ENABLED, + "Reducció predictiva de latència activada. Fotogrames de latència eliminats: %u." + ) +MSG_HASH( + MSG_RUNAHEAD_ENABLED_WITH_SECOND_INSTANCE, + "La reducció predictiva de latència predictiva s'ha activat mitjançant una segona instància. Fotogrames de latència eliminats: %u." + ) +MSG_HASH( + MSG_RUNAHEAD_DISABLED, + "Desactiva l'execució anticipada." + ) +MSG_HASH( + MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, + "La reducció predictiva de latència ha sigut desactivada perquè aquest nucli no és compatible amb els desats ràpids." + ) +MSG_HASH( + MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_RUNAHEAD, + "La reducció predictiva de latència no està disponible perquè el nucli no suporta els desats ràpids." + ) +MSG_HASH( + MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, + "Error en desar l'estat. La reducció predictiva de latència ha sigut desactivada." + ) +MSG_HASH( + MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, + "Error en carregar l'estat. La reducció predictiva de latència ha sigut desactivada." + ) +MSG_HASH( + MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE, + "Error en carregar la segona instància. La reducció predictiva de latència només farà servir una instància a partir d'ara." + ) +MSG_HASH( + MSG_PREEMPT_ENABLED, + "Sistema de fotogrames preventiu activat. Fotogrames de latència eliminats: %u." + ) +MSG_HASH( + MSG_PREEMPT_DISABLED, + "Sistemes de fotogrames preventiu desactivat." + ) +MSG_HASH( + MSG_PREEMPT_CORE_DOES_NOT_SUPPORT_SAVESTATES, + "El sistema de fotogrames preventiu ha sigut desactivat perquè aquest nucli no és compatible amb els desats ràpids." + ) +MSG_HASH( + MSG_PREEMPT_CORE_DOES_NOT_SUPPORT_PREEMPT, + "No està disponible el sistema de fotogrames preventius perquè aquest nucli no suporta els desats ràpids." + ) +MSG_HASH( + MSG_PREEMPT_FAILED_TO_ALLOCATE, + "Error en assignar memòria pel sistema de fotogrames preventius." + ) +MSG_HASH( + MSG_PREEMPT_FAILED_TO_SAVE_STATE, + "Error en desar estat. El sistema de fotogrames preventius s'ha desactivat." + ) +MSG_HASH( + MSG_PREEMPT_FAILED_TO_LOAD_STATE, + "Error en carregar estat. El sistema de fotogrames preventius s'ha desactivat." + ) +MSG_HASH( + MSG_SCANNING_OF_FILE_FINISHED, + "Cerca de fitxers finalitzada." + ) +MSG_HASH( + MSG_CHEAT_INIT_SUCCESS, + "S'ha iniciat correctament la cerca de trucs." + ) +MSG_HASH( + MSG_CHEAT_INIT_FAIL, + "No és possible iniciar la cerca de trucs." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_NOT_INITIALIZED, + "No s'ha iniciat la cerca." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_FOUND_MATCHES, + "Nou nombre de coincidències = %u" + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, + "S'han afegit %u coincidències." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL, + "No s'han pogut afegir coincidències." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS, + "S'ha creat un truc a partir de la coincidència." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, + "No s’ha pogut crear el codi." + ) MSG_HASH( MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS, "Coincidència suprimida." @@ -9711,6 +13970,38 @@ MSG_HASH( MSG_CHEAT_DELETE_SUCCESS, "S’ha suprimit el truc." ) +MSG_HASH( + MSG_FAILED_TO_SET_DISK, + "Error en seleccionar el disc." + ) +MSG_HASH( + MSG_FAILED_TO_SET_INITIAL_DISK, + "Error en establi l'últim disc que s'ha fet servir." + ) +MSG_HASH( + MSG_FAILED_TO_CONNECT_TO_CLIENT, + "Error en connectar amb el client." + ) +MSG_HASH( + MSG_FAILED_TO_CONNECT_TO_HOST, + "Error en connectar al servidor." + ) +MSG_HASH( + MSG_NETPLAY_HOST_FULL, + "El servidor de joc està ple." + ) +MSG_HASH( + MSG_NETPLAY_BANNED, + "No se't permet entrar en aquest servidor." + ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_HEADER_FROM_HOST, + "Error en rebre l'encapçalament del servidor." + ) +MSG_HASH( + MSG_CHEEVOS_LOGGED_IN_AS_USER, + "Assoliments: Has iniciat sessió com a \"%s\"." + ) MSG_HASH( MSG_CHEEVOS_LOAD_STATE_PREVENTED_BY_HARDCORE_MODE, "Heu de posar en pausa o desactivar el mode expert d’assoliments per carregar desats ràpids." @@ -9723,6 +14014,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "S’ha activat un truc. S’ha desactivat el mode expert d’assoliments per la sessió actual." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Assoliments Hardcore canviats pel servidor." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "El servidor de joc en xarxa necessita una actualització. Els assoliments Hardcore han sigut desactivats per aquesta sessió." + ) MSG_HASH( MSG_CHEEVOS_COMPLETED_GAME, "Completat %s" @@ -9731,10 +14030,62 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_ENABLE, "S’ha activat el mode expert d’assoliments; s’han desactivat els desats ràpids i el rebobinat." ) +MSG_HASH( + MSG_CHEEVOS_GAME_HAS_NO_ACHIEVEMENTS, + "Aquest joc no té assoliments." + ) +MSG_HASH( + MSG_CHEEVOS_ALL_ACHIEVEMENTS_ACTIVATED, + "S'han activat tots els assoliments %d en aquesta sessió" +) +MSG_HASH( + MSG_CHEEVOS_UNOFFICIAL_ACHIEVEMENTS_ACTIVATED, + "S'han activat els %d assoliments no oficials" +) +MSG_HASH( + MSG_CHEEVOS_NUMBER_ACHIEVEMENTS_UNLOCKED, + "Has desbloquejat %d de %d assoliments" +) +MSG_HASH( + MSG_CHEEVOS_UNSUPPORTED_COUNT, + "%d no compatible" +) MSG_HASH( MSG_CHEEVOS_RICH_PRESENCE_SPECTATING, "Expectant %s" ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_MANUAL_FRAME_DELAY, + "Mode Hardcore en pausa. No es pot ajustar manualment el retard entre fotogrames de vídeo." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_VSYNC_SWAP_INTERVAL, + "Mode Hardcore en pausa. No es permet un valor d'intercanvi de sincronització vertical superior a 1." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_BLACK_FRAME_INSERTION, + "Mode Hardcore en pausa. No es poden inserir fotogrames negres." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_SETTING_NOT_ALLOWED, + "Mode Hardcore pausat. No es pot canviar: %s=%s" + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_SYSTEM_NOT_FOR_CORE, + "Mode Hardcore en pausa. No pots desbloquejar assoliments Hardcore de %s amb %s" + ) +MSG_HASH( + MSG_CHEEVOS_GAME_NOT_IDENTIFIED, + "RetroAchievements: No es pot identificar el joc." + ) +MSG_HASH( + MSG_CHEEVOS_GAME_LOAD_FAILED, + "Error en carregar el joc a Assoliments: %s" + ) +MSG_HASH( + MSG_CHEEVOS_CHANGE_MEDIA_FAILED, + "Error en canviar els medis a RetroAchievements: %s" + ) MSG_HASH( MSG_RESAMPLER_QUALITY_LOWEST, "Més baix" @@ -9751,18 +14102,166 @@ MSG_HASH( MSG_RESAMPLER_QUALITY_HIGHEST, "Més alt" ) +MSG_HASH( + MSG_MISSING_ASSETS, + "Avís: falten recursos, fes servir l'actualitzador en línia si està disponible." + ) +MSG_HASH( + MSG_RGUI_MISSING_FONTS, + "Atenció: falten tipografies per la llengua seleccionada, useu l’actualitzador en línia si està disponible." + ) +MSG_HASH( + MSG_RGUI_INVALID_LANGUAGE, + "Avís: Llengua no suportada - Canviant a anglès." + ) +MSG_HASH( + MSG_DUMPING_DISC, + "Abocant el disc..." + ) MSG_HASH( MSG_DRIVE_NUMBER, "Unitat %d" ) +MSG_HASH( + MSG_LOAD_CORE_FIRST, + "Carrega un nucli en primer lloc, si us plau." + ) +MSG_HASH( + MSG_DISC_DUMP_FAILED_TO_READ_FROM_DRIVE, + "Error en llegir des de la unitat. S'ha avortat el procés." + ) +MSG_HASH( + MSG_DISC_DUMP_FAILED_TO_WRITE_TO_DISK, + "Error en escriure al disc. S'ha avortat el procés." + ) +MSG_HASH( + MSG_NO_DISC_INSERTED, + "No hi ha un disc dins del lector." + ) +MSG_HASH( + MSG_SHADER_PRESET_REMOVED_SUCCESSFULLY, + "S'ha eliminat la configuració de shaders." + ) +MSG_HASH( + MSG_ERROR_REMOVING_SHADER_PRESET, + "Error en eliminar la configuració de shaders." + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_DAT_FILE_INVALID, + "Has seleccionat un fitxer DAT de arcade no vàlid." + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_DAT_FILE_TOO_LARGE, + "El fitxer de dades DAT seleccionat és massa gran (memòria lliure insuficient)." + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_DAT_FILE_LOAD_ERROR, + "Error en carregar el fitxer DAT (format invàlid?)" + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_INVALID_CONFIG, + "Configuració de cerca manual no vàlida." + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_INVALID_CONTENT, + "No s'ha detectat contingut vàlid." + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_START, + "Escanejant contingut: " + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_PLAYLIST_CLEANUP, + "Comprovant els elements actuals: " + ) MSG_HASH( MSG_MANUAL_CONTENT_SCAN_IN_PROGRESS, "Escanejant: " ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_M3U_CLEANUP, + "Netejant les etiquetes M3U: " + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_END, + "Cerca finalitzada: " + ) +MSG_HASH( + MSG_CORE_BACKUP_SCANNING_CORE, + "Cercant al nucli: " + ) +MSG_HASH( + MSG_CORE_BACKUP_ALREADY_EXISTS, + "Ja existeix una còpia de seguretat del nucli instal·lat: " + ) +MSG_HASH( + MSG_BACKING_UP_CORE, + "Còpia de seguretat del nucli: " + ) +MSG_HASH( + MSG_PRUNING_CORE_BACKUP_HISTORY, + "Eliminant còpies de seguretat obsoletes: " + ) +MSG_HASH( + MSG_CORE_BACKUP_COMPLETE, + "Còpia de seguretat del nucli completada: " + ) +MSG_HASH( + MSG_CORE_RESTORATION_ALREADY_INSTALLED, + "La còpia de seguretat del nucli seleccionat ja està instal·lada: " + ) +MSG_HASH( + MSG_RESTORING_CORE, + "Restaurant els nuclis: " + ) +MSG_HASH( + MSG_CORE_RESTORATION_COMPLETE, + "S'ha restaurat el nucli: " + ) +MSG_HASH( + MSG_CORE_INSTALLATION_ALREADY_INSTALLED, + "El nucli seleccionat ja està instal·lat: " + ) +MSG_HASH( + MSG_INSTALLING_CORE, + "Instal·lant el nucli: " + ) +MSG_HASH( + MSG_CORE_INSTALLATION_COMPLETE, + "Instal·lació completa del nucli: " + ) +MSG_HASH( + MSG_CORE_RESTORATION_INVALID_CONTENT, + "El nucli seleccionat no és vàlid: " + ) +MSG_HASH( + MSG_CORE_BACKUP_FAILED, + "Error en crear la còpia de seguretat del nucli: " + ) +MSG_HASH( + MSG_CORE_RESTORATION_FAILED, + "Error en restaurar el nucli: " + ) MSG_HASH( MSG_CORE_INSTALLATION_FAILED, "Ha fallat la instal·lació del nucli: " ) +MSG_HASH( + MSG_CORE_RESTORATION_DISABLED, + "Restauració de nucli desactivada, el nucli està protegit: " + ) +MSG_HASH( + MSG_CORE_INSTALLATION_DISABLED, + "S’ha inhabilitat la instal·lació del nucli. El nucli està bloquejat: " + ) +MSG_HASH( + MSG_CORE_LOCK_FAILED, + "Error en bloquejar el nucli: " + ) +MSG_HASH( + MSG_CORE_UNLOCK_FAILED, + "Error en desbloquejar el nucli: " + ) MSG_HASH( MSG_CORE_SET_STANDALONE_EXEMPT_FAILED, "No s'ha pogut eliminar el nucli de la llista «Nuclis sense continguts»: " @@ -9771,6 +14270,34 @@ MSG_HASH( MSG_CORE_UNSET_STANDALONE_EXEMPT_FAILED, "No s'ha pogut afegir el nucli a la llista «Nuclis sense continguts»: " ) +MSG_HASH( + MSG_CORE_DELETE_DISABLED, + "S’ha inhabilitat l’eliminació del nucli. El nucli està bloquejat: " + ) +MSG_HASH( + MSG_UNSUPPORTED_VIDEO_MODE, + "El mode de vídeo no és compatible" + ) +MSG_HASH( + MSG_CORE_INFO_CACHE_UNSUPPORTED, + "No es pot escriure a la carpeta d'informació del nucli: es desactivarà la memòria intermèdia d'informació del nucli" + ) +MSG_HASH( + MSG_FOUND_ENTRY_STATE_IN, + "S'ha trobat un desat ràpid a" + ) +MSG_HASH( + MSG_LOADING_ENTRY_STATE_FROM, + "Carregant un desat ràpid des de" + ) +MSG_HASH( + MSG_FAILED_TO_ENTER_GAMEMODE, + "Error en entrar al GameMode" + ) +MSG_HASH( + MSG_FAILED_TO_ENTER_GAMEMODE_LINUX, + "Error en entrar a GameMode - comprova que el servei de GameMode està instal·lat i en funcionament" + ) MSG_HASH( MSG_VRR_RUNLOOP_ENABLED, "S'ha activat la sincronització a la velocitat de fotogrames del contingut exacta." @@ -9809,6 +14336,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SPLIT_JOYCON, "Separa els Joy-Con" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_WIDGET_SCALE_FACTOR, + "Personalitza l'escala de widgets gràfics" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WIDGET_SCALE_FACTOR, + "Força un factor d’escalat manual quan es dibuixen ginys de visualització en mode de finestra. Només s’aplica quan l’opció «Escala automàticament els ginys gràfics» està desactivada. Es pot fer servir per augmentar o disminuir la mida de les notificacions decorades, indicadors i controls independentment del menú." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, + "Resolució de pantalla" + ) MSG_HASH( MSG_SCREEN_RESOLUTION_FORMAT_NO_DESC, "%u×%u" @@ -9817,14 +14356,74 @@ MSG_HASH( MSG_SCREEN_RESOLUTION_FORMAT_DESC, "%u×%u - %s" ) +MSG_HASH( + MSG_SCREEN_RESOLUTION_DEFAULT, + "Resolució de la pantalla: Per defecte" + ) +MSG_HASH( + MSG_SCREEN_RESOLUTION_NO_DESC, + "Resolució de pantalla: %d x %d" + ) +MSG_HASH( + MSG_SCREEN_RESOLUTION_DESC, + "Resolució de la pantalla: %dx%d - %s" + ) +MSG_HASH( + MSG_SCREEN_RESOLUTION_APPLYING_DEFAULT, + "Aplicant: predefinit" + ) +MSG_HASH( + MSG_SCREEN_RESOLUTION_APPLYING_NO_DESC, + "Aplicant: %dx%d\nINICI per reiniciar" + ) +MSG_HASH( + MSG_SCREEN_RESOLUTION_APPLYING_DESC, + "Aplicant: %dx%d - %s\nSTART per reiniciar" + ) +MSG_HASH( + MSG_SCREEN_RESOLUTION_RESETTING_DEFAULT, + "Reiniciant a: Predeterminat" + ) +MSG_HASH( + MSG_SCREEN_RESOLUTION_RESETTING_NO_DESC, + "Reiniciant a: %dx%d" + ) +MSG_HASH( + MSG_SCREEN_RESOLUTION_RESETTING_DESC, + "Restablint a: %dx%d - %s" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCREEN_RESOLUTION, + "Selecciona el mode de vídeo (Es requereix reiniciar)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SHUTDOWN, "Apagar" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILE_BROWSER_OPEN_UWP_PERMISSIONS, + "Permet l'accés a fitxers externs" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILE_BROWSER_OPEN_UWP_PERMISSIONS, + "Obre la configuració de permisos d'accés de fitxers a Windows" + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_OPEN_UWP_PERMISSIONS, + "Obre la finestra de configuració de permisos de Windows per activar el permís a broadFileSystemAccess." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILE_BROWSER_OPEN_PICKER, "Obrir..." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILE_BROWSER_OPEN_PICKER, + "Obre una altra carpeta mitjançant l'explorador de fitxers del sistema" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, + "Filtre de parpelleig" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, "Gamma del vídeo" @@ -9833,10 +14432,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, "Filtre suau" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS, + "Escaneja dispositius bluetooth i connecta-hi." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_WIFI_SETTINGS, + "Escaneja per xarxes wifi i estableix la connexió." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_WIFI_ENABLED, "Activant la WIFI" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_WIFI_NETWORK_SCAN, + "Connecta a una xarxa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_WIFI_NETWORKS, + "Connecta a una xarxa" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_WIFI_DISCONNECT, "Desconnecta" @@ -9965,18 +14580,70 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, "Bloquejant fotogrames" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_PREFER_FRONT_TOUCH, + "Preferència a l'entrada tàctil frontal" + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_INPUT_PREFER_FRONT_TOUCH, + "Fes servir el toc frontal en comptes del toc posterior." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_ENABLE, "Tàctil" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, + "Configuració del mode teclat del controlador" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, + "Tipus de configuració del mode teclat del controlador" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, + "Teclat petit" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_BLOCK_TIMEOUT, + "Temps límit pel bloqueig d'entrada" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_REBOOT, "Mostrar Reiniciar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_REBOOT, + "Mostra l'opció 'Reiniciar'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_SHUTDOWN, + "Mostra 'Apagar'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_SHUTDOWN, + "Mostra l'opció 'Apagar'." + ) MSG_HASH( MSG_ROOM_PASSWORDED, "Amb contrasenya" ) +MSG_HASH( + MSG_INTERNET_RELAY, + "Internet (servidor intermediari)" + ) +MSG_HASH( + MSG_INTERNET_NOT_CONNECTABLE, + "Internet (No hi ha connexió)" + ) +MSG_HASH( + MSG_READ_WRITE, + "Estat de l'emmagatzematge intern: Lectura/Escriptura" + ) +MSG_HASH( + MSG_READ_ONLY, + "Estat de l'emmagatzematge intern: Només lectura" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BRIGHTNESS_CONTROL, "Brillantor de la pantalla" @@ -10033,14 +14700,38 @@ MSG_HASH( "Seleccioneu la zona horària per ajustar la data i l’hora a la vostra ubicació." ) #ifdef HAVE_LAKKA_SWITCH +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LAKKA_SWITCH_OPTIONS, + "Opcions per a Nintendo Switch" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LAKKA_SWITCH_OPTIONS, + "Administra les opcions específiques per la Nintendo Switch." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_OC_ENABLE, "Força la CPU" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SWITCH_OC_ENABLE, + "Permet que es facin servir altres freqüències de rellotge amb la CPU" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_CEC_ENABLE, "Suport CEC" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SWITCH_CEC_ENABLE, + "Habilita el protocol de senyals CEC amb el televisor en el mode televisor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BLUETOOTH_ERTM_DISABLE, + "Deshabilitar bluetooth ERTM" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE, + "Desactiva el ERTM del senyal Bluetooth per corregir l'emparellament d'alguns dispositius" + ) #endif MSG_HASH( MSG_LOCALAP_SWITCHING_OFF, @@ -10100,35 +14791,238 @@ MSG_HASH( "Ajusta l’escala x/y de les coordenades de la pantalla tàctil per adaptar-les a l’escala de visualització del sistema operatiu." ) #ifdef UDEV_TOUCH_SUPPORT +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_VMOUSE_POINTER, + "Fes servir el ratolí virtual (VMouse) com a punter" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TOUCH_VMOUSE_POINTER, + "Activa aquesta opció per enviar els tocs a la pantalla tàctil." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_VMOUSE_MOUSE, + "Empra el ratolí virtual (VMouse) com a ratolí" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TOUCH_VMOUSE_MOUSE, + "Activa l'emulació de ratolí virtual fent servir els tocs a la pantalla tàctil." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_VMOUSE_TOUCHPAD, + "Mode 'Touchpad' pel ratolí virtual" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TOUCH_VMOUSE_TOUCHPAD, + "Activa aquesta opció juntament amb el ratolí per utilitzar la pantalla tàctil com a panell tàctil." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_VMOUSE_TRACKBALL, + "Mode 'Trackball' del ratolí virtual" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_VMOUSE_GESTURE, + "Empra els gestos pel ratolí virtual" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TOUCH_VMOUSE_GESTURE, + "Activa els gestos a la pantalla tàctil, incloent-hi clicar, arrossegar i combinacions de dits." + ) #endif #ifdef HAVE_ODROIDGO2 MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_RGA_SCALING, "Escalat RGA" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_RGA_SCALING, + "Escalat d'imatge que fa servir RGA i filtratge bicúbic. Pot fer malbé els widgets." + ) #else +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_CTX_SCALING, + "Escalat segons el context" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_CTX_SCALING, + "Escalat segons el context de maquinari (si està disponible)." + ) #endif #ifdef _3DS +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NEW3DS_SPEEDUP_ENABLE, + "Activa l'acceleració de CPU de New3DS i memòria intermèdia L2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NEW3DS_SPEEDUP_ENABLE, + "Activa la velocitat màxima de la CPU de New3DS (804 MHz) i la memòria intermèdia L2." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_3DS_LCD_BOTTOM, + "Pantalla inferior de la 3DS" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_3DS_DISPLAY_MODE, + "Mode de pantalla 3DS" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CTR_VIDEO_MODE_2D_400X240, + "2D (Efecte de graella de píxels)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CTR_VIDEO_MODE_2D_800X240, + "2D (Alta resolució)" + ) +MSG_HASH( + MSG_3DS_BOTTOM_MENU_DEFAULT, + "Toca aquí per anar al menú de RetroArch" + ) +MSG_HASH( + MSG_3DS_BOTTOM_MENU_ASSET_NOT_FOUND, + "No s'han trobat els recursos" + ) MSG_HASH( MSG_3DS_BOTTOM_MENU_NO_STATE_DATA, "Sense\nDades" ) +MSG_HASH( + MSG_3DS_BOTTOM_MENU_NO_STATE_THUMBNAIL, + "No hi ha captures de pantalla" + ) MSG_HASH( MSG_3DS_BOTTOM_MENU_RESUME, "Continuar la partida" ) +MSG_HASH( + MSG_3DS_BOTTOM_MENU_SAVE_STATE, + "Crea un punt de restauració" + ) +MSG_HASH( + MSG_3DS_BOTTOM_MENU_LOAD_STATE, + "Carrega el punt de restauració" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BOTTOM_ASSETS_DIRECTORY, + "Directori de recursos de la pantalla inferior" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY, + "Indica la carpeta de recursos de la pantalla inferior. La carpeta ha de tenir un fitxer \"bottom_menu.png\"." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Habilitar la font" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, + "Color vermell de la font" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_RED, + "Ajustant el color vermell de la font de la pantalla inferior." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_GREEN, + "Color de text verd" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_GREEN, + "Ajusta el color verd de la font de la pantalla inferior." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_BLUE, + "Color blau de la font" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE, + "Ajusta el color blau de la font de la pantalla inferior." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_OPACITY, + "Opacitat del color de text" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_OPACITY, + "Ajusta l'opacitat de la font de la pantalla inferior." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_SCALE, "Mida de la font" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_FONT_SCALE, + "Ajusta l'escala de la font a la pantalla inferior." + ) #endif #ifdef HAVE_QT #endif +MSG_HASH( + MSG_IOS_TOUCH_MOUSE_ENABLED, + "L'ús del ratolí amb la pantalla tàctil està activat" + ) +MSG_HASH( + MSG_IOS_TOUCH_MOUSE_DISABLED, + "Ús del ratolí amb la pantalla tàctil desactivat" + ) +MSG_HASH( + MSG_SDL2_MIC_NEEDS_SDL2_AUDIO, + "El micròfon sdl2 necessita un controlador d'àudio sdl2" + ) +MSG_HASH( + MSG_ACCESSIBILITY_STARTUP, + "L'accessibilitat de RetroArch està activada. Menú principal, carregar nucli." + ) MSG_HASH( MSG_AI_SERVICE_STOPPED, "aturat." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "Anul·lar el jugador de IA" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "Descripció d'anul·lació del jugador de IA" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "IA del joc" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Sobreescriu el p1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Anul·la el jugador 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Sobreescriu el p2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Anul·la el jugador 02" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Mostra la depuració" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Mostra la depuració" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Mostrar «IA del joc»" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Mostra l'opció 'IA del joc'." + ) +#endif diff --git a/intl/msg_hash_chs.h b/intl/msg_hash_chs.h index 56ea51ef5c..240d4eb98e 100644 --- a/intl/msg_hash_chs.h +++ b/intl/msg_hash_chs.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "选择使用的模拟器核心。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "卸载核心" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "释放已加载核心。" + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "浏览 libretro 核心实现。浏览器的起始位置取决于你的「核心目录」路径。若空,则从根目录开始。\n如果「核心目录」是一个目录,菜单会将其作为顶级文件夹使用。如果「核心目录」是一个完整路径,它将从路径所指文件所在的文件夹开始。" @@ -730,6 +738,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "SDL 2 支持" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Direct3D 8 支持" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Direct3D 9 支持" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Direct3D 10 支持" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Direct3D 11 支持" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Direct3D 12 支持" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "GDI 支持" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Vulkan 支持" @@ -810,6 +842,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "PulseAudio 支持" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "PipeWire 支持" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "CoreAudio 支持" @@ -890,6 +926,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 支持" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL 支持" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb 支持" @@ -1749,6 +1789,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PULSE, "PulseAudio 音频驱动。如果系统有 PulseAudio,请不要使用其他驱动,比如 ALSA。" ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PIPEWIRE, + "PipeWire 驱动。如果系统使用 PipeWire,请确保使用此驱动程序而不是 PulseAudio。" + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_JACK, "Jack 音频驱动。" @@ -1944,7 +1988,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "在帧之间插入黑帧。可以通过仿真CRT扫描来大幅降低运动模糊,但以损失亮度为代价。 不要与 Swap Interval > 1, sub-frames, Frame Delay, 或者 Sync to Exact Content Framerate功能同时使用。" + "警告:快速闪烁可能在某些显示器上造成图像持续。使用风险//在帧之间插入黑帧。 可以通过模拟CRT扫描来大幅降低移动侦测模糊,但以亮度为代价。" ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2026,10 +2070,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES, "着色器子帧" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "在帧之间插入额外的着色器帧。允许着色器执行特效提升原生游戏的帧率。 应当设置为当前屏幕的刷新率。不要与“交换间隔 > 1”, “BFI”, “帧延迟”, 或“精确同步游戏帧率“功能同时使用。" - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, "设计用来在任何可能的着色器特效上提升游戏本身的帧率,在帧之间插入额外的着色器帧。仅可以使用为您当前显示器刷新率指定的选项。 不要在非60赫兹倍数的屏幕刷新率使用,例如144赫兹,165赫兹等。 不要与“Swap 间隔 > 1”, “BFI”, “帧延迟”, 或者 “精确同步游戏帧率”功能同时使用. 可以保持系统的 VRR 功能打开,仅仅不是那个设置。" @@ -2102,10 +2142,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCAN_SUBFRAMES, "滚动扫描线模拟" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "在多个子帧上模拟基本的滚动扫描线,方法是垂直分割屏幕,并根据子帧的数量渲染屏幕的每个部分。" - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, "在多个子帧上模拟基本的滚动扫描线,方法是垂直分割屏幕,并根据从屏幕顶部向下的子帧数量渲染屏幕的每个部分。" @@ -2529,10 +2565,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "整数缩放轴" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "仅缩放高度,或同时缩放高度和宽度。半步适用于高分辨率信号源。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_SMART, "智能" @@ -2836,18 +2868,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE, "静音模式下静音所有音频。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "快进时静音" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "快进时自动静音。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "快进时的加速声音" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "快进时加快音频速度。防止噼啪声,但会改变音调。" @@ -3365,22 +3389,15 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "长按" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "连发" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "连发周期" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "触发连发键所需的按压时间 (帧)。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "连发周期" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "连击速率。如果此数值大于或等于连击时长,则按键将永远不会松开。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "连发模式" @@ -3405,46 +3422,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, "单个按钮 (长按)" ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "经典模式,2个按键的操作。\n先按住需要使用连发的按键, 再按一下[连发键] 开启连发, 当连发中的按键放开時失效。\n[连发键] 可在[设置/输入/端口 1 控制] 中设定。" - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "经典切换键模式,2个按键的操作,保持按住一个按键并且按下“连发键”来开启该按键连发,关闭连发:保持按住该按键并且再次按下“连发键”。\n“连发键”可以在设置/输入/端口 1 控制内设定。" - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "翻转模式。按一下Turbo按钮来激活选中默认按钮的按下和弹起事件,再次按它来关闭它。\nTurbo按钮可以在 Settings/Input/port 1 Control中分配。" - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "按住模式。只要Turbo按钮被按住,选中的默认按钮的按下和弹起事件将处于活动状态。\nTurbo按钮可以在 Settings/Input/port 1 Control中分配。\n要模拟主计算机时代的自动开火功能,请设置Turbo和默认按钮与游戏杆开火按钮相同。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "连发默认按钮" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "默认的「单一按钮」连发模式激活按钮。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "允许 D-Pad 方向键连发" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "如果启用,数字方向输入(也称为dpad或“hatswitch”) 也可以连发。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "连发" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "更改连发设定.\n注意:连发功能需要在您的输入设备相对应的“端口 X 控制”菜单内映射一个“连发键”。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, "触觉反馈/振动" @@ -3622,10 +3603,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, "菜单开关" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "在菜单和游戏之间切换显示。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, "退出 (控制器组合)" @@ -3702,10 +3679,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "暂停" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "切换暂停游戏/继续游戏状态。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, "框架进度" @@ -4295,10 +4268,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, "光枪十字键右" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "连发" - ) /* Settings > Latency */ @@ -4403,10 +4372,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "绕过核心信息保存状态功能" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "指定是否忽略核心信息保护功能,允许尝试相关的功能 (超前运行,回溯等)。" - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4647,10 +4612,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "自动保存状态" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "关闭游戏时自动保存状态。如果启用了「自动加载状态」,下次打开游戏时,全能模拟器将自动加载此状态。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "自动加载存档" @@ -4829,10 +4790,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "按支持的扩展名过滤文件管理器中显示的文件。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "使用内建媒体播放器" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "过滤当前核心支持文件" @@ -4845,6 +4802,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "在起始目录加载游戏时,于最后打开的位置开启文件浏览器。注:重启全能模拟器后,此位置将重置。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "使用内建媒体播放器" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "使用内建图像查看器" + ) /* Settings > Frame Throttle */ @@ -5797,10 +5762,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "通知大小" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "设置字体大小磅数。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, "通知位置 (水平)" @@ -5954,10 +5915,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, "菜单激活时暂停游戏" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "激活菜单后暂停当前运行的游戏。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, "使用保存存档后继续游戏" @@ -6315,10 +6272,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, "显示「游戏列表」" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "显示「游戏列表」。(在 Ozone/XMB 中需要重启)" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, "显示「探索」页" @@ -6797,14 +6750,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "显示「用户」" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "游戏列表图标" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "要显示的游戏列表图标缩略图类型。" - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "显示「用户」设置。" @@ -7767,10 +7712,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_WITHOUT_CORE_MATCH, "允许扫描还没有安装游戏核心的游戏文件并将其添加到游戏列表中。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "扫描CRC 是否可能重复" - ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, "ISO有时重复序列,特别是使用 PSP/PSN 标题。仅仅依靠序列有时会导致扫描器将内容放入错误的系统。 这里增加了一个 CRC 检查,虽然大大减慢了扫描速度,但是扫描会更加准确。" @@ -8036,7 +7977,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "文件浏览器" + "开始文件夹" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8279,10 +8220,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT, "Steam个人状态格式" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "决定与运行内容相关的信息将共享。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT_CONTENT, @@ -8879,10 +8816,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "继续" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "退出快捷菜单并继续游戏。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, "重启" @@ -8895,10 +8828,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, "关闭游戏" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "关闭当前游戏。未保存的进度可能会丢失。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, "截屏" @@ -9031,18 +8960,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "核心选项" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "更改当前游戏的核心选项设置。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "控制" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "更改当前游戏的键位设置。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "金手指" @@ -9137,14 +9058,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTION_OVERRIDE_INFO, "当前选项文件正在使用。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "重置设置" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "将所有核心设置重置为默认值。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, "更新选项到磁盘" @@ -9673,10 +9586,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, "自动对磁盘上的着色器文件进行更改。" ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "着色器文件进行新的更改。在磁盘上保存更改后,它将自动重新编译并应用到运行的内容。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, "记住上次使用的着色器文件夹" @@ -10814,10 +10723,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_TRANSPARENCY, "透明度" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "当点击“快捷菜单”上的按钮,允许正在运行中的游戏在后台显示。 禁用透明度可能会改变主题的颜色。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, "阴影效果" @@ -11439,6 +11344,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDGAR, "米德加" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "暗灰" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "亮灰" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11466,6 +11379,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "移除主机生产厂商名字之后,播放列表会重新排序。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "次要缩略图" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "用另一个缩略图替换元数据面板。" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "使用滚动字幕显示内容元数据" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "启用后,列表的游戏元数据项 (绑定核心,游戏时间) 只占用一行文字;超出宽度的文字会滚动显示。禁用后,游戏元数据项静态显示,在到达最大宽度后换行。" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "缩略图缩放倍数" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "缩放缩略图栏的大小。" + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "色彩主题" @@ -11522,30 +11460,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRAY_LIGHT, "亮灰" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "次要缩略图" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "用另一个缩略图替换元数据面板。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "使用滚动字幕显示内容元数据" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "启用后,列表的游戏元数据项 (绑定核心,游戏时间) 只占用一行文字;超出宽度的文字会滚动显示。禁用后,游戏元数据项静态显示,在到达最大宽度后换行。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "缩略图缩放倍数" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "缩放缩略图栏的大小。" - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -12506,10 +12421,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "键盘" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "使用内建图像查看器" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "最大的交换链图像" @@ -12645,14 +12556,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "从列表中选择" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "继续" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "退出菜单并继续游戏。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "查看匹配的 %u 个列表" @@ -13251,10 +13154,6 @@ MSG_HASH( MSG_AUTODETECT, "自动检测" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "自动加载状态存储于" - ) MSG_HASH( MSG_CAPABILITIES, "容量" @@ -14351,6 +14250,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "收回虚拟光驱托盘失败。" ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "自动加载状态存储于" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "从 \"%s\" 自动加载状态存档失败。" @@ -15569,10 +15472,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "启用字体" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "显示底部菜单字体。启用以在底部屏幕上显示按钮描述。这不包括保存日期。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "字体颜色红色通道" @@ -15636,3 +15535,10 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "已停止." ) +#ifdef HAVE_GAME_AI + + + + + +#endif diff --git a/intl/msg_hash_cht.h b/intl/msg_hash_cht.h index fa934ddc81..506a4d7591 100644 --- a/intl/msg_hash_cht.h +++ b/intl/msg_hash_cht.h @@ -1922,10 +1922,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, "插入黑幀" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "在每幀之間插入黑幀, 以降低亮度為代價, 透過模擬映像管螢幕掃描方式減少動態模糊。\n請勿與「垂直同步切換間隔」設定大於<1> 「著色器補幀」 「幀數延遲」 「準確同步執行幀率」同時使用。" - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, "設定值必須與螢幕預設更新率相同, 在每幀之間插入黑幀以增強動態清晰度。\n請勿與「垂直同步切換間隔」設定大於<1> 「著色器補幀」 「幀數延遲」 「準確同步執行幀率」同時使用。\n不適用於非60Hz倍數的更新率, 例如144Hz、165Hz等。\n允許系統可變更新率開啟, 但不是那個設定。\n 如果發現任何影像殘留, 請在120hz測試後關閉此選項, 至於更高的更新率可調整下方暗幀設定。" @@ -1998,10 +1994,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES, "著色器補幀" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "設定值必須與螢幕預設更新率相同, 在每幀之間插入著色器補幀, 提高每秒顯示影格數符合螢幕更新率。\n請勿與「垂直同步切換間隔」設定大於<1> 「插入黑幀」 「幀數延遲」 「準確同步執行幀率」同時使用。" - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, "設定值必須與螢幕預設更新率相同, 在每幀之間插入著色器補幀, 提高每秒顯示影格數符合螢幕更新率。\n請勿與「垂直同步切換間隔」設定大於<1> 「插入黑幀」 「幀數延遲」 「準確同步執行幀率」同時使用。\n不適用於非60Hz倍數的更新率, 例如144Hz、165Hz等。\n允許系統可變更新率開啟, 但不是那個設定。" @@ -2489,10 +2481,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "整數縮放方式" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "設定可以使用高度或同時使用高度和寬度, 高度加半高或寬度加半寬適用於高解析度。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "整數縮放模式" @@ -2591,14 +2579,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_Y, "影像垂直位置" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "設定影像水平位置(如果影像寬於螢幕), 設定<0.0>表示最左邊<1.0>表示最右邊。" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "設定影像垂直位置(如果影像高於螢幕), 設定<0.0>表示最頂端<1.0>表示最底部。" - ) #if defined(RARCH_MOBILE) MSG_HASH( MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, @@ -2616,14 +2596,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, "影像垂直位置" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "設定影像水平位置(如果影像寬於螢幕), 設定<0.0>表示最左邊<1.0>表示最右邊。" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "設定影像垂直位置(如果影像高於螢幕), 設定<0.0>表示最頂端<1.0>表示最底部。" - ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, @@ -2868,18 +2840,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE, "靜音模式下靜音所有音源" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "快轉時靜音" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "開啟快轉模式時音量自動設定為靜音。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "快轉時變調" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "開啟快轉模式時音訊變調並加速播放。" @@ -3405,22 +3369,15 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "保留" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "連發設定" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "連發週期" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "設定連發的週期(幀數), 設定值小於二無法作用。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "連發工作週期" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "設定連發的工作週期, 設定值必須小於連發週期。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "連發鍵模式" @@ -3445,46 +3402,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, "單鍵 (按住)" ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "組合單次模式。\n先按住需要使用連發的按鍵, 再按一下[連發鍵]開啟連發, 當連發中的按鍵放開時失效。\n[連發鍵]可在「設定/輸入/控制器/連接埠#控制器」 選項中個別設定。" - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "組合開關模式。\n先按住需要使用連發的按鍵, 再按一下[連發鍵]開啟連發, 需要關閉連發時重新操作一次。\n[連發鍵]可在「設定/輸入/控制器/連接埠#控制器」 選項中個別設定。" - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "單鍵開關模式。\n按一下[連發鍵]開啟連發預設單鍵, 預設的單鍵會持續連發, 直到再按一下[連發鍵]關閉。\n[連發鍵]可在「設定/輸入/控制器/連接埠#控制器」 選項中個別設定。" - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "單鍵按住模式。\n按住[連發鍵]時開啟連發預設單鍵, 預設的單鍵會持續連發, 直到放開[連發鍵]時關閉。\n[連發鍵]可在「設定/輸入/控制器/連接埠#控制器」 選項中個別設定。\n用於模擬個人電腦時代的按住自動射擊功能, 請將連發鍵與預設單鍵設定為射擊的按鍵。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "連發預設單鍵" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "設定[連發鍵]要持續連發的單鍵, 僅限模式為<單鍵(按住/開關)>時使用。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "允許十字鍵連發" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "開啟時十字鍵(方向鍵)支援連發功能, 僅限模式為<組合(單次/開關)>時使用。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "連發設定" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "變更連發的設定。\n注意: 需要在「設定/輸入/控制器/連接埠#控制器」選項中, 設定輸入裝置對應的「連發鍵」按鍵。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, "觸覺回饋和震動" @@ -3666,10 +3587,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, "快捷選單" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "執行項目時選單的開關。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, "結束應用程式 (控制器組合鍵)" @@ -3746,10 +3663,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "暫停" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "暫停模式和繼續遊戲的切換開關。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, "逐格播放" @@ -4295,10 +4208,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, "光線槍 十字鍵 右" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "連發鍵" - ) /* Settings > Latency */ @@ -4423,10 +4332,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "忽略其他支援" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "開啟時執行核心忽略儲存狀態功能, 可用於開啟倒帶、超前執行和搶占幀數等相關功能。" - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4667,10 +4572,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "自動儲存即時存檔" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "「關閉」和「結束復古電玩」時, 自動儲存即時存檔, 儲存的編號為自動(.state.auto)。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "自動載入即時存檔" @@ -4849,10 +4750,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "在檔案瀏覽器中只顯示支援的檔案。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "使用內建的媒體播放器" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "只顯示目前核心支援格式" @@ -4865,6 +4762,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "記住本次執行「開始資料夾」最後載入的檔案位置。 注意: 重新啟動後會還原為預設位置。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "使用內建的媒體播放器" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "使用內建的圖像瀏覽器" + ) /* Settings > Frame Throttle */ @@ -5733,10 +5638,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "設定字體大小" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "設定通知訊息使用的字體大小(點值)。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, "通知位置 (水平)" @@ -5882,10 +5783,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, "當開啟選單時暫停核心" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "當開啟快捷選單操作時暫停執行中的項目。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, "操作即時存檔後關閉" @@ -6243,10 +6140,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, "顯示「列表」" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "顯示一般列表。 (Ozone和XMB主題需要重新啟動)" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, "顯示「搜尋」" @@ -6725,14 +6618,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "顯示「使用者」" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "列表圖示" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "設定列表圖示顯示的類型。" - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "顯示「使用者」選項。" @@ -7695,10 +7580,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_WITHOUT_CORE_MATCH, "開啟時「匯入遊戲」忽略支援核心的資訊, 允許未安裝核心時掃描檔案並建立列表。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "掃描校驗避免重複" - ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, "ISO映像檔有時會使用重複產品序號, 尤其是PSP和PSN的作品, 僅依靠產品序號掃描檔案, 可能會導致將項目加入到錯誤的系統中。\n開啟時增加了循環冗餘校驗(CRC), 會嚴重降低掃描速度, 但可能會更準確。" @@ -8219,10 +8100,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT, "Steam個人狀態格式" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "設定分享執行中相關的訊息。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT_CONTENT, @@ -8815,10 +8692,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "繼續" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "繼續執行。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, "重開" @@ -8831,10 +8704,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, "關閉" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "關閉目前執行的項目。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, "螢幕截圖" @@ -8967,18 +8836,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "核心選項" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "變更核心相關的設定。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "控制器 (核心預設)" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "變更遊戲控制器相關的設定。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "金手指" @@ -9073,14 +8934,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTION_OVERRIDE_INFO, "目前使用的核心選項設定檔。\n載入優先順序: 項目>路徑>核心。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "重置核心選項" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "重置全部核心選項為預設值。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, "取代目前存檔" @@ -9609,10 +9462,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, "著色器設定變更時, 自動應用變化, 儲存配置檔到儲存空間。" ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "著色器設定變更時, 自動應用變化, 儲存配置檔到儲存空間。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, "記住最後載入著色器的位置" @@ -10850,10 +10699,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_TRANSPARENCY, "透明度" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "開啟時選單可顯示執行的內容。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, "陰影效果" @@ -11535,6 +11380,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDGAR, "三原色" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "暗灰色" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "亮灰色" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11562,6 +11415,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "截斷列表名稱開啟時, 連接號之後的文字依字母順序重新排序。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "次要的預覽縮圖" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "設定次要的預覽縮圖顯示類型, 開啟時覆蓋列表資訊欄並且支援按鍵切換。" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "套用滾動文字到列表資訊欄" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "開啟時列表的資訊欄每個項目只占用一行, 超出欄位的文字使用滾動效果顯示, 關閉時則自動換行顯示。" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "預覽縮圖欄位大小" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "設定預覽縮圖的欄位大小。" + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "自訂選單色彩主題" @@ -11602,10 +11480,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_DRACULA, "德古拉紫" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, - "硒元素灰" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, "暗青色" @@ -11627,30 +11501,11 @@ MSG_HASH( "紫雨紫" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "次要的預覽縮圖" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "設定次要的預覽縮圖顯示類型, 開啟時覆蓋列表資訊欄並且支援按鍵切換。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "套用滾動文字到列表資訊欄" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "開啟時列表的資訊欄每個項目只占用一行, 超出欄位的文字使用滾動效果顯示, 關閉時則自動換行顯示。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "預覽縮圖欄位大小" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "設定預覽縮圖的欄位大小。" + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "硒元素灰" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -12626,10 +12481,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "鍵盤" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "使用內建的圖像瀏覽器" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "最大交換鏈結圖像" @@ -12765,14 +12616,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "從列表中選擇" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "繼續" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "繼續執行。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "查看 %u個 搜尋結果列表" @@ -13371,10 +13214,6 @@ MSG_HASH( MSG_AUTODETECT, "自動偵測" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "自動載入即時存檔從" - ) MSG_HASH( MSG_CAPABILITIES, "容量" @@ -14459,6 +14298,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "虛擬光碟機托盤無法進入。" ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "自動載入即時存檔從" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "無法自動載入即時存檔, 位置: %s。" @@ -15521,10 +15364,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "顯示文字" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "在下螢幕上顯示按鍵說明, 不包括儲存即時存檔的日期。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "字體顏色 (紅)" @@ -15580,3 +15419,10 @@ MSG_HASH( MSG_IOS_TOUCH_MOUSE_DISABLED, "觸控滑鼠已關閉" ) +#ifdef HAVE_GAME_AI + + + + + +#endif diff --git a/intl/msg_hash_cs.h b/intl/msg_hash_cs.h index 1f97f4d64d..48ae495554 100644 --- a/intl/msg_hash_cs.h +++ b/intl/msg_hash_cs.h @@ -10,7 +10,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MAIN_MENU, - "Hlavní Menu" + "Hlavní menu" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, @@ -73,7 +73,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, - "Načíst Obsah" + "Načíst obsah" ) MSG_HASH( MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, @@ -151,7 +151,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY, - "Netplay - Hrát online" + "Netplay (Online hraní)" ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY, @@ -195,7 +195,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESTART_RETROARCH, - "Restartovat RetroArchovou aplikaci." + "Restartovat RetroArch." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, @@ -315,11 +315,11 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST, - "Stahovač Jádra" + "Stahovač jádra" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_INSTALLED_CORES, - "Aktualizovat Nainstalované Jádra" + "Aktualizovat nainstalované jádra" ) MSG_HASH( MENU_ENUM_SUBLABEL_UPDATE_INSTALLED_CORES, @@ -327,7 +327,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_INSTALLED_CORES_PFD, - "Přepnout Jádra do Verzí Obchodu Play" + "Přepnout jádra do verzí Obchodu Play" ) MSG_HASH( MENU_ENUM_SUBLABEL_SWITCH_INSTALLED_CORES_PFD, @@ -335,7 +335,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, - "Aktualizátor Miniatur" + "Aktualizátor náhledu" ) MSG_HASH( MENU_ENUM_SUBLABEL_THUMBNAILS_UPDATER_LIST, @@ -343,7 +343,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PL_THUMBNAILS_UPDATER_LIST, - "Aktualizátor Miniatur Playlistů" + "Aktualizátor náhledů playlistu" ) MSG_HASH( MENU_ENUM_SUBLABEL_PL_THUMBNAILS_UPDATER_LIST, @@ -351,7 +351,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, - "Stahování Obsahu" + "Stahování obsahu" ) MSG_HASH( MENU_ENUM_SUBLABEL_DOWNLOAD_CORE_CONTENT, @@ -359,7 +359,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_SYSTEM_FILES, - "Stažení Jádra Systémových Dat" + "Stažení jádra systémových dat" ) MSG_HASH( MENU_ENUM_SUBLABEL_DOWNLOAD_CORE_SYSTEM_FILES, @@ -371,11 +371,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, - "Aktualizovat Položky" + "Aktualizovat zdroje" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "Aktualizovat Profily Ovladače" + "Aktualizovat profily ovladače" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, @@ -387,7 +387,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, - "Aktualizace překryvů" + "Aktualizovat Overlay" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, @@ -430,7 +430,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, - "Systémové Informace" + "Systémové informace" ) MSG_HASH( MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, @@ -710,6 +710,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "Podpora SDL 2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Podpora Direct3D 8" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Podpora Direct3D 9" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Podpora Direct3D 10" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Podpora Direct3D 11" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Podpora Direct3D 12" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "Podpora GDI" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Podpora Vulkan" @@ -790,6 +814,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "Podpora PulseAudio" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "Podpora PipeWire" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "Podpora CoreAudio" @@ -870,6 +898,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Podpora Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Podpora SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb Podpora" @@ -1202,7 +1234,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_SAVES, - "Synchronizace: Uložené hry/Stavy" + "Synchronizace: Uložení/Stavy" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_CONFIGS, @@ -1713,6 +1745,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PULSE, "Ovladač PulseAudio. Pokud systém používá PulseAudio, ujistěte se, že používáte tento ovladač místo např. ALSA." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PIPEWIRE, + "Ovladač PipeWire. Pokud systém používá PipeWire, ujistěte se, že používáte tento ovladač místo např. PulseAudio." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_JACK, "Ovladač sady pro připojení zvuku Jack." @@ -1900,7 +1936,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Vkládá mezi snímky černý rámeček (rámečky). Může výrazně snížit rozmazání pohybu napodobením vnějšího skenu CRT, ale za cenu snížení jasu. Nekombinujte s intervalem výměny > 1, dílčími snímky, zpožděním snímků nebo synchronizací s přesnou snímkovou frekvencí obsahu." + "UPOZORNĚNÍ: Rychlé blikání může na některých displejích způsobit přetrvávání obrazu. Používejte na vlastní nebezpečí // Mezi snímky vložte černý rámeček (rámečky). Může výrazně snížit rozmazání pohybu napodobením CRT scan out, ale za cenu snížení jasu." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -1984,7 +2020,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Vložení dalších snímků shaderu mezi snímky. Umožňuje shaderům provádět efekty, které běží při vyšší rychlosti snímků za sekundu, než je skutečná rychlost obsahu. Mělo by být nastaveno na aktuální Hz obrazovky. Nekombinujte s funkcemi Interval výměny > 1, BFI, zpoždění snímku nebo Sync do přesné snímkové frekvence obsahu." + "UPOZORNĚNÍ: Rychlé blikání může na některých displejích způsobit přetrvávání obrazu. Používejte na vlastní nebezpečí // Simuluje základní klouzavý skenovací řádek v několika dílčích snímcích vertikálním rozdělením obrazovky a vykreslením každé části obrazovky podle toho, kolik dílčích snímků existuje." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2060,7 +2096,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Simuluje základní klouzavý skenovací řádek ve více dílčích snímcích vertikálním rozdělením obrazovky a vykreslením každé části obrazovky podle počtu dílčích snímků." + "UPOZORNĚNÍ: Rychlé blikání může na některých displejích způsobit přetrvávání obrazu. Používejte na vlastní nebezpečí // Simuluje základní klouzavý skenovací řádek v několika dílčích snímcích vertikálním rozdělením obrazovky a vykreslením každé části obrazovky podle toho, kolik dílčích snímků existuje." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2483,7 +2519,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Měřítko pouze výška, nebo jak výška, tak šířka. Poloviční kroky platí pro zdroje vysokého rozlišení." + "Škálujte buď výšku, nebo šířku, nebo výšku i šířku. Poloviční kroky platí pouze pro zdroje s vysokým rozlišením." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, + "Celočíselné škálování" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_SCALING, + "Zaokrouhlujte dolů nebo nahoru na celé číslo. Při příliš velkém oříznutí obrázku se hodnota 'Smart' sníží na podměrečné." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_SMART, @@ -2535,11 +2579,67 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, "Vlastní poměr stran (poloha X)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, + "Vlastní posunutí zobrazení, které se používá k určení polohy zobrazení v ose X." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, "Vlastní poměr stran (poloha Y)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, + "Vlastní posunutí zobrazení, které se používá k definování polohy zobrazení v ose Y." + ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_X, + "Předsazení kotvy pohledu X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_X, + "Předsazení kotvy pohledu X" + ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_Y, + "Předsazení kotvy pohledu Y" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_Y, + "Předsazení kotvy pohledu Y" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, + "Vodorovná poloha obsahu, když je zobrazovací plocha širší než šířka obsahu. 0,0 je zcela vlevo, 0,5 je uprostřed, 1,0 je zcela vpravo." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, + "Svislá poloha obsahu, když je zobrazovací plocha vyšší než výška obsahu. 0,0 je nahoře, 0,5 je uprostřed, 1,0 je dole." + ) #if defined(RARCH_MOBILE) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, + "Předsazení kotvy panelu zobrazení X (orientace na výšku)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, + "Předsazení kotvy panelu zobrazení X (orientace na výšku)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, + "Předsazení kotvy panelu zobrazení Y (orientace na výšku)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, + "Předsazení kotvy panelu zobrazení Y (orientace na výšku)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, + "Vodorovná poloha obsahu, když je zobrazovací plocha širší než šířka obsahu. 0,0 je zcela vlevo, 0,5 je uprostřed, 1,0 je zcela vpravo. (Orientace na výšku)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, + "Svislá poloha obsahu, když je zobrazovací plocha vyšší než výška obsahu. 0,0 je nahoře, 0,5 je uprostřed, 1,0 je dole (orientace na výšku)" + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, @@ -2635,10 +2735,30 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_ADAPTIVE_VSYNC, "Funkce VSync je povolena, dokud výkon neklesne pod cílovou obnovovací frekvenci. Může minimalizovat zadrhávání při poklesu výkonu pod reálný čas a být energeticky úspornější." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, + "Zpoždění snímku" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, + "Snižuje latenci za cenu vyššího rizika zadrhávání videa." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_FRAME_DELAY, + "Nastavuje, kolik milisekund se má uspat před spuštěním jádra po prezentaci videa. Snižuje latenci za cenu vyššího rizika zadrhávání.\nHodnoty 20 a vyšší jsou považovány za procenta času snímku." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTO, "Automatické zpoždění snímků" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY_AUTO, + "Dynamické nastavení efektivního zpoždění snímků." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_FRAME_DELAY_AUTO, + "Snažte se udržet požadovaný cíl „Zpoždění snímků“ a minimalizovat poklesy snímků. Výchozím bodem je čas 3/4 snímku, pokud je hodnota „Frame Delay“ 0 (Auto)." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_EFFECTIVE, "účinný" @@ -2758,7 +2878,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Ztlumení při rychlém převíjení" + "Ztlumení zvuku při rychlém posunu vpřed" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2766,12 +2886,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Zrychlení při rychlém přeposílání" + "Zrychlení zvuku při rychlém posunu vpřed" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Zrychlení zvuku při rychlém převíjení vpřed. Zabraňuje praskání, ale mění výšku tónu." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Ztlumení zvuku při zpětném přetáčení" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Automatické ztlumení zvuku při použití zpětného přetáčení." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Zesílení hlasitosti (dB)" @@ -2871,6 +2999,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, "Zpoždění zvuku (ms)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_LATENCY, + "Maximální zpoždění zvuku v milisekundách. Ovladač se snaží udržet skutečnou latenci na 50 % této hodnoty. Nemusí být dodržena, pokud ovladač zvuku nemůže danou latenci zajistit." + ) #ifdef HAVE_MICROPHONE /* Settings > Audio > Input */ @@ -3083,6 +3215,26 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, "Upravte hlasitost zvukového proudu." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_NONE, + "Stav: N/A" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_STOPPED, + "Stav: Zastaveno" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING, + "Stav: Přehrávání" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_LOOPED, + "Stav: Přehrávání (ve smyčce)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL, + "Stav: Hraní (sekvenční)" + ) /* Settings > Audio > Menu Sounds */ @@ -3145,6 +3297,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, "Přepsat vstupní vazby přemapovanými vazbami nastavenými pro aktuální jádro." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_REMAP_SORT_BY_CONTROLLER_ENABLE, + "Seřadit přemapování podle Gamepadu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_REMAP_SORT_BY_CONTROLLER_ENABLE, + "Přemapování se použije pouze pro aktivní gamepad, do kterého bylo uloženo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, "Autokonfigurace" @@ -3277,22 +3437,35 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Držet" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo střelba" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Vypnutí zastaví všechny operace turbo střelby." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbo období" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Doba (ve snímcích), po kterou jsou stisknuta tlačítka s funkcí turbo." + "Doba ve snímcích, kdy jsou stisknuta tlačítka s funkcí turbo." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Turbo pracovní cyklus" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, + "Pracovní cyklus turba" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, "Počet snímků z období Turbo, po které jsou tlačítka držena stisknutá. Pokud je toto číslo rovno nebo větší než perioda Turbo, tlačítka se nikdy neuvolní." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Polovina období" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Režim turba" @@ -3319,35 +3492,43 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Klasický režim, ovládání dvěma tlačítky. Podržením tlačítka a klepnutím na tlačítko Turbo aktivujete sekvenci stisknutí a uvolnění.\nTlačítko Turbo lze přiřadit v nabídce Nastavení/Vstup/Port 1 Ovládání." + "Klasický režim, ovládání dvěma tlačítky. Podržením tlačítka a klepnutím na tlačítko Turbo aktivujete sekvenci stisknutí a uvolnění.\nPřiřazení turba lze přiřadit v Nastavení/Vstup/Ovládání portu X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Klasický přepínací režim, ovládání dvěma tlačítky. Podržením tlačítka a klepnutím na tlačítko Turbo aktivujete turbo pro dané tlačítko. Chcete-li turbo vypnout: podržte tlačítko a znovu stiskněte tlačítko Turbo.\nTlačítko Turbo lze přiřadit v menu Nastavení/Vstup/Ovládače Port1." + "Klasický přepínací režim, ovládání dvěma tlačítky. Podržením tlačítka a klepnutím na tlačítko Turbo aktivujete turbo pro dané tlačítko. Vypnutí turba: podržte tlačítko a znovu stiskněte tlačítko Turbo.\nPřiřazení turba lze přiřadit v menu Nastavení/Vstup/Ovládání portu X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Režim přepínání. Jedním stisknutím tlačítka Turbo aktivujete sekvenci stisknutí a uvolnění vybraného výchozího tlačítka, dalším stisknutím tlačítka Turbo jej vypnete.\nTlačítko Turbo lze přiřadit v nabídce Nastavení/Vstup/Port 1 Ovládání." + "Režim přepínání. Jedním stisknutím tlačítka Turbo aktivujete sekvenci stisknutí a uvolnění vybraného výchozího tlačítka, dalším stisknutím jej vypnete.\nTurbo přiřazení lze přiřadit v Nastavení/Vstup/Ovládání portu X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Režim podržení. Sekvence stisknutí a uvolnění vybraného výchozího tlačítka je aktivní, dokud je tlačítko Turbo stisknuté.\nTlačítko Turbo lze přiřadit v nabídce Nastavení/Vstup/Port 1 Ovládání.\nChcete-li napodobit funkci automatického střelby v éře domácího počítače, nastavte tlačítka Turbo a výchozí tlačítko jako tlačítko střelby joysticku." + "Režim podržení. Sekvence stisknutí a uvolnění vybraného výchozího tlačítka je aktivní, dokud je tlačítko Turbo stisknuté.\nTurbo bind lze přiřadit v Nastavení/Vstup/Ovládání portu X.\nChcete-li napodobit funkci automatického střelby v éře domácího počítače, nastavte Bind a Tlačítko na stejné tlačítko střelby joysticku." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Výchozí tlačítko turba" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Turbo přiřazení" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Výchozí aktivní tlačítko pro režim Turbo 'Jedno Tlačítko'." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "Turbo aktivace přiřazení RetroPadu. Prázdný používá přiřazení na konkrétní port." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Povolit Turbo D-Pad směry" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Tlačítko Turba" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "Jsou-li povoleny, mohou být digitální směrové vstupy (známé také jako d-pad nebo \"hatswitch\") turbo." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "Cílové turbo tlačítko v režimu „Jedno tlačítko“." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Povolit Turbo pro směry D-Padu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, + "Pokud je povoleno, mohou být digitální směrové vstupy (známé také jako d-pad nebo „hatswitch“) turbo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -3355,7 +3536,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Změňte nastavení funkce turbo.\nPoznámka: funkce turbo vyžaduje namapování tlačítka turbo na vstupní zařízení v příslušné nabídce \"Ovládání portu X\"." + "Změna nastavení turbo střelby." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3463,6 +3644,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_DISABLE_SEARCH_BUTTON, "Pokud je povoleno, budou stisknutí tlačítka Hledat ignorována." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DISABLE_LEFT_ANALOG_IN_MENU, + "Zakázat levý analog v menu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DISABLE_LEFT_ANALOG_IN_MENU, + "Zabránění navigaci levou analogovou páčkou v menu." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DISABLE_RIGHT_ANALOG_IN_MENU, + "Zakázat pravý analog v menu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DISABLE_RIGHT_ANALOG_IN_MENU, + "Zabránění navigaci pravou analogovou páčkou v menu." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, "Menu pro nahrazení tlačítek OK a Storno" @@ -3514,6 +3711,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_DEVICE_MERGE, "Sloučení typů zařízení s klávesovou zkratkou" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_HOTKEY_DEVICE_MERGE, + "Zablokovat všechny klávesové zkratky z obou typů zařízení - klávesnice i ovladače, pokud je u některého z nich nastavena možnost „Povolit klávesové zkratky“." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, "Přepínač menu (kombo ovladač)" @@ -3528,7 +3729,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Přepíná aktuální zobrazení mezi nabídkou a běžícím obsahem." + "Přepíná aktuální zobrazení mezi menu a obsahem." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3608,7 +3809,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Přepíná spuštěný obsah mezi pozastavenými a nepozastavenými stavy." + "Přepíná obsah mezi pozastavenými a nepozastavenými pozicemi." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -3816,6 +4017,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Sníží index aktuálně vybraného slotu pro záznam." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Turbo střelba (přepínání)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Zapíná a vypíná turbo střelbu." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Podržení myši (přepínání)" @@ -3947,6 +4156,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_NETPLAY_PLAYER_CHAT, "Odešle zprávu chatu do aktuální relace síťové hry." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FADE_CHAT_TOGGLE, + "Netplay Fade Chat (Přepínání)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_NETPLAY_FADE_CHAT_TOGGLE, "Přepínání mezi blednoucími a statickými zprávami chatu při hraní po síti." @@ -3987,6 +4200,38 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, "Index zařízení" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DEVICE_INDEX, + "Fyzický ovladač rozpoznaný aplikací RetroArch." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_RESERVED_DEVICE_NAME, + "Rezervované zařízení pro tento přehrávač" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DEVICE_RESERVED_DEVICE_NAME, + "Tento ovladač bude tomuto hráči přidělen podle režimu rezervace." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_NONE, + "Bez rezervace" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_PREFERRED, + "Preferováno" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_RESERVED, + "Rezervováno" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_RESERVATION_TYPE, + "Typ rezervace zařízení" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DEVICE_RESERVATION_TYPE, + "Přednostní: pokud je zadané zařízení k dispozici, bude přiděleno tomuto přehrávači. Rezervováno: pro tento přehrávač nebude přidělen žádný jiný ovladač." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_REMAP_PORT, "Mapovaný Port" @@ -3999,18 +4244,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, "Nastavení všech ovládačů" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_ALL, + "Přiřaďte všechny směry a tlačítka postupně v pořadí, v jakém se zobrazují v tomto menu." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, "Obnovit Výchozí Nastavení Ovládačů" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_DEFAULTS, + "Vymazání nastavení vazby vstupu na výchozí hodnoty." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, "Uložit profil ovladače" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_SAVE_AUTOCONFIG, + "Uložení souboru automatické konfigurace, který se automaticky použije, kdykoli je tento řadič znovu detekován." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, "Index myši" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_MOUSE_INDEX, + "Fyzická myš rozpoznaná aplikací RetroArch." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, "B Tlačítko (Dolů)" @@ -4170,8 +4431,28 @@ MSG_HASH( MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES, "Počet snímků, které se mají spustit dopředu. Způsobuje problémy s hraním, například trhání, pokud je překročen počet interních zpožděných snímků." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUNAHEAD_MODE, + "Spuštění další logiky jádra pro snížení latence. Jednotlivá instance se spustí do budoucího rámce a poté znovu načte aktuální stav. Druhá instance udržuje instanci jádra pouze pro video na budoucím snímku, aby se předešlo problémům se stavem zvuku. Preemptivní snímky spouští minulé snímky s novým vstupem, když je to potřeba, kvůli efektivitě." + ) #if !(defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUNAHEAD_MODE_NO_SECOND_INSTANCE, + "Spuštění další logiky jádra pro snížení latence. Jednotlivá instance se spustí do budoucího rámce a poté znovu načte aktuální stav. Preemptivní snímky spouští minulé snímky s novým vstupem, když je to potřeba, kvůli efektivitě." + ) #endif +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUNAHEAD_MODE_SINGLE_INSTANCE, + "Režim jedné instance" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUNAHEAD_MODE_SECOND_INSTANCE, + "Režim druhé instance" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUNAHEAD_MODE_PREEMPTIVE_FRAMES, + "Režim preemptivních snímků" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RUN_AHEAD_HIDE_WARNINGS, "Skryt varování Run-Ahead" @@ -4257,7 +4538,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Určuje, zda se mají ignorovat základní možnosti ukládání informací, což umožňuje experimentovat se souvisejícími funkcemi (běh dopředu, přetáčení atd.)." + "Určuje, zda se mají ignorovat možnosti ukládání základních informací, což umožňuje experimentovat s příslušnými funkcemi (běh dopředu, přetáčení atd.)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4376,6 +4657,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, "Načtení vlastních ovladačů při startu." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INITIAL_DISK_CHANGE_ENABLE, + "Automatické načtení počátečních souborů indexu disku" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INITIAL_DISK_CHANGE_ENABLE, + "Změna na poslední použitý disk při spuštění obsahu s více disky." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, "Automatické načítání předvoleb shaderu" @@ -4425,7 +4714,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, - "Nepřepisovat uloženíRAM při načítání uložené pozice" + "Nepřepisovat uloženou Ram při načítání uložené pozice" ) MSG_HASH( MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, @@ -4493,7 +4782,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatické vytvoření pozice uložení při zavření obsahu. Pokud je povolena volba 'Automaticky načíst pozici', RetroArch tuto pozici uložení automaticky načte." + "Automatické vytvoření stavu uložení při zavření obsahu. Tento stav uložení se načte při spuštění, pokud je povolena volba „Automatické načítání pozice“." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -4505,11 +4794,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, - "Miniatury uložené pozice" + "Náhledy uložené pozice" ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, - "Zobrazení miniatur stavů uložení v nabídce." + "Zobrazení náhledu stavů uložení v menu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_FILE_COMPRESSION, @@ -4555,6 +4844,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, "Systémové soubory jsou v adresáři obsahu" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "Použijte adresář s obsahem jako adresář System/BIOS." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, "Zapsat snímky obrazovky do adresáře obsahu" @@ -4653,22 +4946,42 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, "Zobrazit skryté soubory a adresáře" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, + "Zobrazení skrytých souborů a adresářů v Průzkumníku souborů." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtrování neznámých rozšíření" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Použití vestavěného mediálního přehrávače" + MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Filtrování souborů zobrazených v Průzkumníku souborů podle podporovaných přípon." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrování podle aktuálního jádra" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtrování souborů zobrazených v Průzkumníku souborů podle aktuálního jádra." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Zapamatovat si naposledy použitý úvodní adresář" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, + "Otevření Průzkumníka souborů v posledním použitém umístění při načítání obsahu z úvodního adresáře. Poznámka: Po restartu aplikace RetroArch bude umístění obnoveno na výchozí." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Použití vestavěného mediálního přehrávače" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Použít vestavěný prohlížeč obrázků" + ) /* Settings > Frame Throttle */ @@ -5038,6 +5351,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "Upravte velikost zón překrytí v kosočtverci tlačítka tváře. Pro osmisměrnou symetrii nastavte hodnotu 100 %." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analogová zóna opětovného centrování" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Vstup analogové páčky bude vztažen k prvnímu dotyku, pokud je stisknuta v této zóně." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Překrytí" @@ -5046,6 +5367,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, "Preferované Auto-Překrytí" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_AUTOLOAD_PREFERRED, + "Přednostní načítání překryvných prvků na základě názvu systému před návratem k výchozí předvolbě. Bude ignorováno, pokud je pro předvolbu překrytí nastaveno přepsání." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, "Neprůhlednost překrytí" @@ -5058,6 +5383,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, "Předvolba překrytí" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_PRESET, + "Vyberte překrytí v Průzkumníku souborů." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE_LANDSCAPE, "Měřítko překrytí (krajina)" @@ -5162,6 +5491,30 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OSK_OVERLAY_SETTINGS, "Výběr a nastavení překryvu klávesnice." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_POINTER_ENABLE, + "Povolení překrytí světelné pistole, myši a ukazatele" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_POINTER_ENABLE, + "K vytvoření vstupu ukazovacího zařízení pro jádro použijte všechny dotykové vstupy, které nejsou ovládacími prvky překryvu." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_LIGHTGUN_SETTINGS, + "Překrytí Lightgunu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_LIGHTGUN_SETTINGS, + "Konfigurace vstupu světelné pistole odesílaného z překryvné vrstvy." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_MOUSE_SETTINGS, + "Překrytí myší" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_MOUSE_SETTINGS, + "Konfigurace vstupu myši odesílaného z překryvné vrstvy. Poznámka: Klepnutí 1, 2 a 3 prsty odesílají kliknutí levým, pravým a prostředním tlačítkem." + ) /* Settings > On-Screen Display > On-Screen Overlay > Keyboard Overlay */ @@ -5169,6 +5522,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_PRESET, "Předvolba překrytí klávesnice" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OSK_OVERLAY_PRESET, + "V Průzkumníku souborů vyberte překrytí klávesnice." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OSK_OVERLAY_AUTO_SCALE, "Překrytí klávesnice v automatickém měřítku" @@ -5188,9 +5545,81 @@ MSG_HASH( /* Settings > On-Screen Display > On-Screen Overlay > Overlay Lightgun */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_PORT, + "Port Lightgunu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_PORT, + "Nastavení hlavního portu pro příjem vstupu z překryvné světelné pistole." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_PORT_ANY, + "Jakékoliv" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_TRIGGER_ON_TOUCH, + "Spoušť při dotyku" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_TRIGGER_ON_TOUCH, + "Odeslání spouštěcího vstupu se vstupem ukazatele." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_TRIGGER_DELAY, + "Zpoždění spouště (snímky)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_TRIGGER_DELAY, + "Zpožděný vstup spouště, aby měl kurzor čas na pohyb. Toto zpoždění se také používá k čekání na správné počítání vícedotykových tlačítek." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_TWO_TOUCH_INPUT, + "2-Dotykový vstup" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_TWO_TOUCH_INPUT, + "Vyberte vstup, který se má odeslat, když jsou na obrazovce dva ukazatele. Zpoždění spouštěče by mělo být nenulové, aby se odlišilo od ostatních vstupů." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_THREE_TOUCH_INPUT, + "3-Dotykový vstup" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_THREE_TOUCH_INPUT, + "Vyberte vstup, který se má odeslat, když jsou na obrazovce tři ukazatele. Zpoždění spouštěče by mělo být nenulové, aby se odlišilo od ostatních vstupů." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_FOUR_TOUCH_INPUT, + "4-Dotykový vstup" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_FOUR_TOUCH_INPUT, + "Vyberte vstup, který se má odeslat, když jsou na obrazovce čtyři ukazatele. Zpoždění spouštěče by mělo být nenulové, aby se odlišilo od ostatních vstupů." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_ALLOW_OFFSCREEN, + "Povolit mimo obrazovku" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_ALLOW_OFFSCREEN, + "Povolení míření mimo hranice. Zakázat, aby se míření mimo obrazovku upnulo na hranu v záběru." + ) /* Settings > On-Screen Display > On-Screen Overlay > Overlay Mouse */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_SPEED, + "Rychlost myši" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_SPEED, + "Nastavení rychlosti pohybu kurzoru." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_HOLD_TO_DRAG, + "Dlouhým stisknutím přetáhnout" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_HOLD_TO_DRAG, "Dlouhým stisknutím obrazovky začnete držet tlačítko." @@ -5365,6 +5794,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Vstupní (autokonfigurace) oznámení o připojení" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Oznámení o selhání vstupu (automatická konfigurace)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Oznámení cheat kódu" @@ -5385,6 +5818,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Zobrazení zprávy na obrazovce při připojování/odpojování vstupních zařízení." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Zobrazení zprávy na obrazovce, pokud se nepodařilo nakonfigurovat vstupní zařízení." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Vstupní přemapování načtených oznámení" @@ -5519,7 +5956,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Zadejte velikost písma v bodech." + "Zadejte velikost písma v bodech. Při použití widgetů má tato velikost vliv pouze na zobrazení statistik na obrazovce." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -5676,7 +6113,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Pozastavení aktuálně spuštěného obsahu, pokud je nabídka aktivní." + "Pozastavení obsahu, pokud je menu aktivní." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -5893,7 +6330,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_LEGACY_THUMBNAIL_UPDATER, - "Zobrazit starší verze 'Aktualizátor miniatur'" + "Zobrazit starší 'Aktualizátor náhledů'" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SHOW_LEGACY_THUMBNAIL_UPDATER, @@ -5967,26 +6404,50 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, "Zobrazit 'Obrázky'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, + "Zobrazit menu „Obrázky“. (V systému Ozone/XMB je nutný restart)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, "Zobrazit 'Hudbu'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, + "Zobrazení menu „Hudba“. (V systému Ozone/XMB je nutný restart)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, "Zobrazit 'Videa'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, + "Zobrazit menu „Videa“. (V systému Ozone/XMB je nutný restart)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, "Zobrazit 'Netplay'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, + "Zobrazení menu „Netplay“. (V zařízení Ozone/XMB je nutný restart)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, "Zobrazení 'Historie'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_HISTORY, + "Zobrazení menu nedávné historie. (V systému Ozone/XMB je nutný restart)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, "Zobrazit 'Importovat obsah'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, + "Zobrazení menu „Importovat obsah“. (V systému Ozone/XMB je nutný restart)" + ) MSG_HASH( /* FIXME can now be replaced with MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD */ MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD_ENTRY, "Zobrazit 'Importovat obsah'" @@ -6007,14 +6468,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, "Zobrazit 'Seznamy skladeb'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, + "Zobrazení seznamů skladeb v hlavní nabídce. Ignorováno v GLUI, pokud jsou povoleny karty playlistů a navigační panel." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Zobrazit karty Playlistu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Zobrazení karet seznamu skladeb. Nemá vliv na rozhraní RGUI. Navigační panel musí být povolen v rozhraní GLUI. (V systému Ozone/XMB je nutný restart)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, "Zobrazit 'Prozkoumat'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_EXPLORE, + "Zobrazit možnost průzkumníka obsahu. (V systému Ozone/XMB je nutný restart)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_CONTENTLESS_CORES, "Zobrazit 'Jádra bez obsahu'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_CONTENTLESS_CORES, + "Zadejte typ jádra (pokud existuje), které se má zobrazit v nabídce „Bezobsažná jádra“. Pokud je nastavena hodnota „Vlastní“, lze viditelnost jednotlivých jader přepínat prostřednictvím nabídky „Spravovat jádra“. (V systému Ozone/XMB je nutný restart)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_CONTENTLESS_CORES_ALL, "Vše" @@ -6270,6 +6751,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, "Zobrazit možnost \"Přidat k oblíbeným\"." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_PLAYLIST, + "Zobrazit 'Přidat do Playlistu'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_PLAYLIST, + "Zobrazit možnost 'Přidat do Playlistu'." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SET_CORE_ASSOCIATION, "Zobrazit 'Nastavit sdružení jádra'" @@ -6600,6 +7089,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_MODE, "AI výstup služby" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AI_SERVICE_MODE, + "Zobrazte překlad jako překryvný text (režim obrazu), přehrávejte jej jako převod textu na řeč (řeč) nebo použijte systémového vypravěče, jako je NVDA (vypravěč)." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_URL, "AI služba URL" @@ -6957,6 +7450,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_4, "Jihovýchodní Asie" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_5, + "Východní Asie (Chuncheon, Jižní Korea)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_CUSTOM, "Vlastní" @@ -7415,6 +7912,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_WITHOUT_CORE_MATCH, "Umožnit skenování obsahu a jeho přidání do seznamu skladeb bez nainstalovaného jádra, které to podporuje." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, + "Kontrola CRC na možné duplicity" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, + "Někdy se ISO duplikují, zejména u titulů pro PSP/PSN. Spoléhání se pouze na sériové číslo může někdy způsobit, že skener vloží obsah do nesprávného systému. Tento postup přidává kontrolu CRC, což značně zpomaluje skenování, ale může být přesnější." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LIST, "Správa playlistů" @@ -7439,6 +7944,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_USE_FILENAME, "Je-li tato funkce povolena, vyhledá náhledy podle názvu souboru, nikoli podle jeho popisku." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ALLOW_NON_PNG, + "Povolit všechny podporované typy obrázků pro miniatury" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ALLOW_NON_PNG, + "Pokud je tato funkce povolena, lze přidávat místní náhledy do všech typů obrázků podporovaných aplikací RetroArch (například jpeg). Může mít menší dopad na výkon." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MANAGE, "Správa" @@ -7668,12 +8181,20 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Správce souborů" + "Startovací adresář" + ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, + "Nastavení počátečního adresáře pro Průzkumníka souborů." ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, "Konfigurační soubory" ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, + "V tomto adresáři je uložen výchozí konfigurační soubor." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, "Jádra" @@ -7901,7 +8422,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Rozhodněte, jaké informace týkající se běžícího obsahu budou sdíleny." + "Rozhodněte, jaké informace související s obsahem budou sdíleny." ) MSG_HASH( @@ -8402,6 +8923,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES_PLAYLIST, "Přidejte obsah do 'Oblíbené'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TO_PLAYLIST, + "Přidat do Playlistu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_PLAYLIST, + "Přidejte obsah do seznamu skladeb." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CREATE_NEW_PLAYLIST, + "Vytvořit nový Playlist" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CREATE_NEW_PLAYLIST, + "Vytvořte nový seznam skladeb a přidejte do něj aktuální položku." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SET_CORE_ASSOCIATION, "Nastavení asociace jádra" @@ -8481,7 +9018,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Pokračujte v aktuálně spuštěném obsahu a opusťte rychlou nabídku." + "Obnovte obsah a opusťte rychlé menu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -8497,7 +9034,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Zavřít aktuální obsah. Všechny neuložené změny mohou být ztraceny." + "Zavřít obsah. Všechny neuložené změny mohou být ztraceny." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -8509,7 +9046,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STATE_SLOT, - "Uložené pozice" + "Uložení/Načtení pozic" ) MSG_HASH( MENU_ENUM_SUBLABEL_STATE_SLOT, @@ -8633,7 +9170,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Změna možností aktuálně spuštěného obsahu." + "Změňte možnosti obsahu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -8641,7 +9178,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Změna ovládacích prvků aktuálně spuštěného obsahu." + "Změňte ovládací prvky obsahu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -8737,14 +9274,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTION_OVERRIDE_INFO, "Aktuální používaný soubor možností." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Resetovat možnosti" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Nastavte všechny základní možnosti na výchozí hodnoty." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, "Zápis možnosti na disk" @@ -9259,12 +9788,16 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Sledujte soubory shaderů, zda v nich nedošlo k novým změnám. Po uložení změn v shaderu na disk se automaticky překompilují a použijí na spuštěný obsah." + "Sledujte soubory shaderů, zda v nich nedošlo k novým změnám. Po uložení změn v shaderu na disk se automaticky překompilují a použijí na obsah." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, "Zapamatování naposledy použitého adresáře shaderů" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_REMEMBER_LAST_DIR, + "Otevření Průzkumníka souborů v posledním použitém adresáři při načítání předvoleb a průchodů shaderů." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, "Načtení předvolby" @@ -9594,6 +10127,22 @@ MSG_HASH( MENU_ENUM_LABEL_CHEEVOS_SERVER_DISCONNECTED, "Server Retroúspěchů je nedostupný. Pokusy se opakují, dokud nejsou úspěšné nebo dokud není aplikace ukončena." ) +MSG_HASH( + MENU_ENUM_LABEL_CHEEVOS_SERVER_RECONNECTED, + "Všechny nevyřízené žádosti byly úspěšně synchronizovány se serverem RetroÚspěchy." +) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_IDENTIFYING_GAME, + "Identifikace hry" +) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_FETCHING_GAME_DATA, + "Získávání herních dat" +) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_STARTING_SESSION, + "Zahájení relace" +) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN, "Nepřihášen" @@ -9700,6 +10249,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Cyklus miniatur" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Náhodný výběr" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Zpět" @@ -10075,6 +10628,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, "Úvodní obrazovka" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_LOGOS, + "Logo obsahu" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCROLL_NORMAL, "Normální" @@ -10398,13 +10955,17 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_MENU_THEME_PRESET, "Vlastní předvolba motivu" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_MENU_THEME_PRESET, + "V Průzkumníku souborů vyberte předvolbu motivu menu." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_TRANSPARENCY, "Průhlednost" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Povolení zobrazení spuštěného obsahu na pozadí, když je aktivní rychlá nabídka. Zakázání průhlednosti může změnit barvy motivu." + "Povolit zobrazení obsahu na pozadí, když je aktivní rychlé menu. Zakázání průhlednosti může změnit barvy motivu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -10728,6 +11289,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Typ miniatury, která se zobrazí vlevo." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Ikona miniatury" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Typ miniatury ikony seznamu skladeb, která se má zobrazit." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Dynamické pozadí" @@ -10872,6 +11441,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_XMB_TITLE_MARGIN_HORIZONTAL_OFFSET, "Vodorovný posun okraje názvu" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MAIN_MENU_ENABLE_SETTINGS, + "Povolení karty Nastavení (nutný restart)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, "Zobrazí tabulku nastavení obsahující nastavení programu." @@ -11003,6 +11576,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Studená ledová" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Tmavě šedá" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Světle šedá" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11014,14 +11595,47 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_COLLAPSE_SIDEBAR, "Levý postranní panel je vždy sbalený." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_TRUNCATE_PLAYLIST_NAME, + "Zkracování názvů Playlistu (nutný restart)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_TRUNCATE_PLAYLIST_NAME, "Odstranění názvů výrobců z playlistu. Například z 'Sony - PlayStation' se stane 'PlayStation'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, + "Řazení Playlistu po zkrácení názvu (nutný restart)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Playlisty budou po odstranění složky výrobce z jejich názvu seřazeny podle abecedy." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Sekundární miniatura" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Nahraďte panel metadat obsahu jinou miniaturou." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Použít text oznámení pro metadata obsahu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Je-li tato funkce povolena, každá položka metadat obsahu zobrazená na pravém postranním panelu playlistu (přidružené jádro, čas přehrávání) zabere jeden řádek; řetězce přesahující šířku postranního panelu se zobrazí jako rolovací text. Je-li vypnuta, bude každá položka metadat obsahu zobrazena staticky, zabalená tak, aby zabírala tolik řádků, kolik je potřeba." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Faktor měřítka miniatur" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Měřítko velikosti panelu miniatur." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Barevný motiv" @@ -11078,30 +11692,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_PURPLE_RAIN, "Fialový déšť" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Sekundární miniatura" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Nahraďte panel metadat obsahu jinou miniaturou." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Použít text oznámení pro metadata obsahu" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Je-li tato funkce povolena, každá položka metadat obsahu zobrazená na pravém postranním panelu playlistu (přidružené jádro, čas přehrávání) zabere jeden řádek; řetězce přesahující šířku postranního panelu se zobrazí jako rolovací text. Je-li vypnuta, bude každá položka metadat obsahu zobrazena staticky, zabalená tak, aby zabírala tolik řádků, kolik je potřeba." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Faktor měřítka miniatur" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Měřítko velikosti panelu miniatur." - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -11121,6 +11712,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_SWITCH_ICONS, "Použít ikony namísto zapnutého/vypnutého textu pro zobrazení položek v menu 'Přepnout přepínač'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_PLAYLIST_ICONS_ENABLE, + "Ikony Playlistu (nutný restart)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_PLAYLIST_ICONS_ENABLE, "Zobrazení ikon specifických pro systém v playlistu." @@ -12058,10 +12653,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Uživatel" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Použít vestavěný prohlížeč obrázků" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Max. stabilizace snímku" @@ -12193,14 +12784,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Vybrat z playlistu" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Pokračovat" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Pokračujte v aktuálně spuštěném obsahu a opusťte rychlou nabídku." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Zobrazit seznam %u shod" @@ -12795,10 +13378,6 @@ MSG_HASH( MSG_AUTODETECT, "Autodetekovat" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Automaticky načíst pozici uložení z" - ) MSG_HASH( MSG_CAPABILITIES, "Schopnosti" @@ -12923,6 +13502,14 @@ MSG_HASH( MSG_ADD_TO_FAVORITES_FAILED, "Přidání oblíbených se nezdařilo: playlist je plný" ) +MSG_HASH( + MSG_ADDED_TO_PLAYLIST, + "Přidáno do playlistu" + ) +MSG_HASH( + MSG_ADD_TO_PLAYLIST_FAILED, + "Nepodařilo se přidat do Playlistu: Playlist je plný" + ) MSG_HASH( MSG_SET_CORE_ASSOCIATION, "Nastavení jádra: " @@ -12971,6 +13558,10 @@ MSG_HASH( MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, "Profil ovladače byl úspěšně uložen." ) +MSG_HASH( + MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY_NAMED, + "Profil řadiče uložený v adresáři Ovladač profilu as\n\"%s“" + ) MSG_HASH( MSG_AUTOSAVE_FAILED, "Automatické ukládání nelze inicializovat." @@ -13687,6 +14278,10 @@ MSG_HASH( MSG_SCANNING, "Vyhledávání" ) +MSG_HASH( + MSG_SCANNING_OF_DIRECTORY_FINISHED, + "Skenování adresáře dokončeno." + ) MSG_HASH( MSG_SENDING_COMMAND, "Odesílání příkazu" @@ -13755,6 +14350,10 @@ MSG_HASH( MSG_ACHIEVEMENT_UNLOCKED, "Úspěch odemknut" ) +MSG_HASH( + MSG_RARE_ACHIEVEMENT_UNLOCKED, + "Odemčen vzácný úspěch" + ) MSG_HASH( MSG_LEADERBOARD_STARTED, "Pokus o sestavení žebříčku zahájen" @@ -13767,6 +14366,14 @@ MSG_HASH( MSG_LEADERBOARD_SUBMISSION, "Odesláno %s pro %s" /* Submitted [value] for [leaderboard name] */ ) +MSG_HASH( + MSG_LEADERBOARD_RANK, + "Hodnocení: %d" /* Rank: [leaderboard rank] */ + ) +MSG_HASH( + MSG_LEADERBOARD_BEST, + "Nejlepší: %s" /* Best: [value] */ + ) MSG_HASH( MSG_CHANGE_THUMBNAIL_TYPE, "Změna typu miniatury" @@ -13783,6 +14390,10 @@ MSG_HASH( MSG_NO_THUMBNAIL_AVAILABLE, "Není k dispozici žádná miniatura" ) +MSG_HASH( + MSG_NO_THUMBNAIL_DOWNLOAD_POSSIBLE, + "Pro tuto položku Playlist již byly vyzkoušeny všechny možné náhledy ke stažení." + ) MSG_HASH( MSG_PRESS_AGAIN_TO_QUIT, "Stiskněte znovu pro ukončení..." @@ -13851,6 +14462,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Nepodařilo se zavřít zásobník virtuálních disků." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Automaticky načíst pozici uložení z" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Automatické načtení uložené pozice z \"%s\"se nezdařilo." @@ -14039,10 +14654,46 @@ MSG_HASH( MSG_PREEMPT_FAILED_TO_LOAD_STATE, "Nepodařilo se načíst stav. Preemptivní rámce byly zakázány." ) +MSG_HASH( + MSG_SCANNING_OF_FILE_FINISHED, + "Skenování souboru dokončeno." + ) +MSG_HASH( + MSG_CHEAT_INIT_SUCCESS, + "Úspěšně jste zahájili vyhledávání cheatu." + ) +MSG_HASH( + MSG_CHEAT_INIT_FAIL, + "Nepodařilo se spustit vyhledávání cheatu." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_NOT_INITIALIZED, + "Vyhledávání nebylo inicializováno/spuštěno." + ) MSG_HASH( MSG_CHEAT_SEARCH_FOUND_MATCHES, "Počet nových shod = %u" ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, + "Přidány shody %u." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL, + "Nepodařilo se přidat zápasy." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS, + "Vytvořený kód ze zápasu." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, + "Nepodařilo se vytvořit kód." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS, + "Odstraněný zápas." + ) MSG_HASH( MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY, "Nedostatek místnosti. Maximální počet současných cheatů je 100." @@ -14107,6 +14758,10 @@ MSG_HASH( MSG_FAILED_TO_RECEIVE_HEADER_FROM_HOST, "Nepodařilo se přijmout hlavičku od hostitele." ) +MSG_HASH( + MSG_CHEEVOS_LOGGED_IN_AS_USER, + "RetroÚspěchy: Přihlášen jako „%s“." + ) MSG_HASH( MSG_CHEEVOS_LOAD_STATE_PREVENTED_BY_HARDCORE_MODE, "Pro nahrání stavů je nutné pozastavit nebo vypnout Úspěchy hardcore režimu." @@ -14119,6 +14774,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Cheat byl aktivován. Úspěchy hardcore režimu jsou pro aktuální relaci vypnuty." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Úspěchy Hardcore Modu změnil hostitel." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "Je třeba aktualizovat hostitele Netplay. Úspěchy Hardcore Modu jsou pro aktuální relaci vypnuty." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Zvládnuto %s" @@ -14131,6 +14794,62 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_ENABLE, "Úspěchy hardcore módu povoleny, ukládání a přetáčení bylo zakázáno." ) +MSG_HASH( + MSG_CHEEVOS_GAME_HAS_NO_ACHIEVEMENTS, + "Tato hra nemá žádné úspěchy." + ) +MSG_HASH( + MSG_CHEEVOS_ALL_ACHIEVEMENTS_ACTIVATED, + "Všechny %d úspěchy aktivovány pro tuto relaci" +) +MSG_HASH( + MSG_CHEEVOS_UNOFFICIAL_ACHIEVEMENTS_ACTIVATED, + "Aktivováno %d neoficiálních úspěchů" +) +MSG_HASH( + MSG_CHEEVOS_NUMBER_ACHIEVEMENTS_UNLOCKED, + "Máte odemčeno %d z %d úspěchů" +) +MSG_HASH( + MSG_CHEEVOS_UNSUPPORTED_COUNT, + "%d nepodporováno" +) +MSG_HASH( + MSG_CHEEVOS_RICH_PRESENCE_SPECTATING, + "Sledování %s" + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_MANUAL_FRAME_DELAY, + "Hardcore se zastavil. Ruční nastavení zpoždění snímků videa není povoleno." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_VSYNC_SWAP_INTERVAL, + "Hardcore pozastaven. Vsync swap interval nad 1 není povolen." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_BLACK_FRAME_INSERTION, + "Hardcore pozastaven. Vkládání černých rámečků není povoleno." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_SETTING_NOT_ALLOWED, + "Hardcore pozastaven. Nastavení není povoleno: %s=%s" + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_SYSTEM_NOT_FOR_CORE, + "Hardcore pozastaven. Nemůžete získat hardcore úspěchy pro %s pomocí %s" + ) +MSG_HASH( + MSG_CHEEVOS_GAME_NOT_IDENTIFIED, + "RetroÚspěchy: Hru se nepodařilo identifikovat." + ) +MSG_HASH( + MSG_CHEEVOS_GAME_LOAD_FAILED, + "Načtení herních RetroÚspěchů se nezdařilo: %s" + ) +MSG_HASH( + MSG_CHEEVOS_CHANGE_MEDIA_FAILED, + "Změna média RetroÚspěchů se nezdařila: %s" + ) MSG_HASH( MSG_RESAMPLER_QUALITY_LOWEST, "Nejnižší" @@ -14987,7 +15706,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Zobrazení písma spodního menu. Povolit zobrazení popisů tlačítek na spodní obrazovce. To se netýká data uložení." + "Zobrazení písma spodního menu. Povolte zobrazení popisů tlačítek na spodní obrazovce. To nezahrnuje datum uložení stavu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, @@ -15044,6 +15763,10 @@ MSG_HASH( MSG_IOS_TOUCH_MOUSE_DISABLED, "Dotyková myš je zakázána" ) +MSG_HASH( + MSG_SDL2_MIC_NEEDS_SDL2_AUDIO, + "mikrofon sdl2 vyžaduje zvukový ovladač sdl2" + ) MSG_HASH( MSG_ACCESSIBILITY_STARTUP, "Aktivována přístupnost RetroArch. Hlavní menu načtení jádra." @@ -15052,3 +15775,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "zastaveno." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "Přepsání hráče AI" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "Přepis podnálepky přehrávače AI" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "Herní AI" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Přepsat p1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Přepsat hráče 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Přepsat p2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Přepsat hráče 02" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Zobrazit ladění" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Zobrazit ladění" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Zobrazit 'Herní AI'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Zobrazit možnost „Herní AI“." + ) +#endif diff --git a/intl/msg_hash_cy.h b/intl/msg_hash_cy.h index fbc5e0c442..dd56170da8 100644 --- a/intl/msg_hash_cy.h +++ b/intl/msg_hash_cy.h @@ -1082,6 +1082,7 @@ MSG_HASH( "ARNO" ) + /* Settings > Input > Haptic Feedback/Vibration */ @@ -1286,6 +1287,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, "Lawrlwythiadau" ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, + "Cyfeiriadur Cychwynnol" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, "Rhestri Chwarae" @@ -1519,6 +1524,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -1743,4 +1750,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_da.h b/intl/msg_hash_da.h index b48c2bb145..e69a5cb863 100644 --- a/intl/msg_hash_da.h +++ b/intl/msg_hash_da.h @@ -1022,6 +1022,7 @@ MSG_HASH( #ifdef ANDROID #endif + /* Settings > Input > Haptic Feedback/Vibration */ @@ -1216,7 +1217,7 @@ MSG_HASH( MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Filhåndtering" + "Start Mappe" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, @@ -1355,6 +1356,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -1463,4 +1466,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index 43c2b69562..117631bd56 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -67,6 +67,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Den zu verwendenden Core wählen." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Core entladen" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Den geladenen Core freigeben." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Nach einer Libretro-Core-Implementierung suchen. In welchem Verzeichnis der Browser beginnt, hängt von dem Core-Verzeichnispfad ab.\nIst als Core-Verzeichnis ein Ordner ausgewählt, wird dieser als Startverzeichnis genutzt. Ist das Core-Verzeichnis ein vollständiger Pfad, wird in dem Ordner begonnen, in dem sich die Datei befindet." @@ -890,6 +898,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2-Unterstützung" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL-Unterstützung" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb-Unterstützung" @@ -1892,7 +1904,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Fügt Schwarzbild(er) zwischen Frames ein. Kann Bewegungsunschärfe durch Emulation von CRT-Abtast-Ausgabe erheblich reduzieren, aber auf Kosten der Helligkeit. Nicht kombinieren mit Swap-Intervall > 1, Unterbilder, Bildverzögerung oder mit exakter Inhaltssignalfrequenz synchronisieren." + "WARNUNG: Schnelles Flackern kann auf manchen Bildschirmen zu einem Nachleuchten des Bildes führen. Verwendung auf eigene Gefahr // Schwarze(n) Rahmen zwischen den Bildern einfügen. Kann die Bewegungsunschärfe durch Emulation der CRT-Abtastung stark reduzieren, allerdings auf Kosten der Helligkeit." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -1976,7 +1988,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Fügt zusätzlich Shader-Bild(er) zwischen Frames ein. Ermöglicht Shadern den Einsatz von Effekten, die mit einer höheren Bildrate ausgeführt werden als die tatsächliche Inhaltsrate. Sollte auf die aktuelle Bildschirm-Hz gesetzt werden. Nicht kombinieren mit Swap-Intervall > 1, Schwarzbilder, Bildverzögerung oder mit exakter Inhaltssignalfrequenz synchronisieren." + "WARNUNG: Schnelles Flackern kann auf manchen Bildschirmen zu einem Nachleuchten des Bildes führen. Verwendung auf eigene Gefahr // Simuliert eine einfache rollende Scanline über mehrere Unterbilder, indem der Bildschirm vertikal aufgeteilt wird und jeder Teil des Bildschirms entsprechend der Anzahl der Unterbilder dargestellt wird." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2052,7 +2064,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Simuliert eine einfache rollende Scanline über mehrere Unterbilder, indem der Bildschirm vertikal aufgeteilt wird und jeder Teil des Bildschirms entsprechend der Anzahl der Unterbilder dargestellt wird." + "WARNUNG: Schnelles Flackern kann auf manchen Bildschirmen zu einem Nachleuchten des Bildes führen. Verwendung auf eigene Gefahr // Simuliert eine einfache rollende Scanline über mehrere Unterbilder, indem der Bildschirm vertikal aufgeteilt wird und jeder Teil des Bildschirms entsprechend der Anzahl der Unterbilder dargestellt wird." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2471,7 +2483,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Nur Höhe oder Höhe und Breite skalieren. Halbschritte beziehen sich auf die Auflösung der Quellen." + "Skaliert entweder Höhe oder Breite oder sowohl Höhe als auch Breite. Halbschritte gelten nur für hochauflösende Quellen." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2569,11 +2581,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Benutzerdefinierte Ausrichtung des Ansichtsfensters wird verwendet, um das Ansichtsfenster horizontal zu versetzen (wenn es breiter als die Inhaltshöhe ist). 0.0 bedeutet ganz links und 1.0 bedeutet ganz rechts." + "Horizontale Position des Inhalts, wenn das Ansichtsfenster breiter als die Inhaltsbreite ist. 0.0 ist ganz links, 0.5 ist Mitte, 1.0 ist ganz rechts." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Benutzerdefinierte Ausrichtung des Ansichtsfensters wird verwendet, um das Ansichtsfenster vertikal zu versetzen (wenn es höher als die Inhaltshöhe ist). 0.0 bedeutet oben und 1.0 bedeutet unten." + "Vertikale Position des Inhalts, wenn das Ansichtsfenster höher als die Inhaltshöhe ist. 0.0 ist oben, 0.5 ist Mitte, 1.0 ist unten." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2594,11 +2606,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Benutzerdefinierte Ausrichtung des Ansichtsfensters wird verwendet, um das Ansichtsfenster horizontal zu versetzen (wenn es breiter als die Inhaltshöhe ist). 0.0 bedeutet ganz links und 1.0 bedeutet ganz rechts. (Hochformat)" + "Horizontale Position des Inhalts, wenn das Ansichtsfenster breiter als die Inhaltsbreite ist. 0.0 ist ganz links, 0.5 ist Mitte, 1.0 ist ganz rechts. (Hochformat)" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Benutzerdefinierte Ausrichtung des Ansichtsfensters wird verwendet, um das Ansichtsfenster vertikal zu versetzen (wenn es höher als die Inhaltshöhe ist). 0.0 bedeutet oben und 1.0 bedeutet unten. (Hochformat)" + "Vertikale Position des Inhalts, wenn das Ansichtsfenster höher als die Inhaltshöhe ist. 0.0 ist oben, 0.5 ist Mitte, 1.0 ist unten. (Hochformat)" ) #endif MSG_HASH( @@ -2834,7 +2846,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Beim Vorspulen stummschalten" + "Auto-stumm bei schnellem Vorspulen" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2842,12 +2854,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Beim Vorspulen beschleunigen" + "Audiobeschleunigung bei schnellem Vorspulen" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Audio beim schnellen Vorlauf beschleunigen. Verhindert Knackgeräusche, verändert aber die Tonhöhe." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Auto-stumm bei Rückspulen" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Audio beim Zurückspulen automatisch stumm stellen." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Lautstärkeanpassung (dB)" @@ -3385,21 +3405,34 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Halten" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Deaktiviert stoppt alle Turbofeuer-Vorgänge." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbo-Periode" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Die Periode (in Frames), in der die turbo-aktivierten Tasten betätigt werden." + "Die Periode in Frames, in der die Turbo-aktivierten Tasten betätigt werden." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, "Turbo-Haltedauer" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Die Anzahl der Frames aus der Turbo-Periode, für die die Tasten gedrückt gehalten werden. Wenn diese Zahl gleich oder größer als die Turbo-Periode ist, bleiben die Tasten gedrückt." + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, + "Die Anzahl der Frames aus der Turbo-Periode, für die die Tasten gedrückt gehalten werden. Wenn diese Zahl gleich oder größer als die Turbo-Periode ist, werden die Tasten nie losgelassen." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Halbe Periode" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, @@ -3427,35 +3460,43 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Klassischer Modus, Zwei-Tasten-Bedienung. Eine Taste halten und die Turbotaste antippen, um die Drücken-Loslassen-Sequenz zu aktivieren.\nDie Turbotaste kann unter Einstellungen/Eingabe/Port-1-Steuerung zugewiesen werden." + "Klassischer Modus, Zwei-Tasten-Bedienung. Eine Taste halten und die Turbotaste antippen, um die Drücken-Loslassen-Sequenz zu aktivieren.\nDie Turbotaste kann unter Einstellungen/Eingabe/Port-X-Steuerung zugewiesen werden." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Klassischer Umschalt-Modus, Zwei-Tasten-Vorgang. Eine Taste gedrückt halten und auf die Turbotaste tippen, um Turbo für diesen Taste zu aktivieren. Um Turbo zu deaktivieren: Den Knopf gedrückt halten und die Turbotaste erneut drücken.\nDie Turbotaste kann in den Einstellungen/Eingabe/Port-1-Steuerung zugewiesen werden." + "Klassischer Umschalt-Modus, Zwei-Tasten-Bedienung. Eine Taste gedrückt halten und auf die Turbotaste tippen, um Turbo für diese Taste zu aktivieren. Um Turbo zu deaktivieren: Den Knopf gedrückt halten und die Turbotaste erneut drücken.\nDie Turbotaste kann in den Einstellungen/Eingabe/Port-X-Steuerung zugewiesen werden." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Umschaltmodus. Die Turbotaste einmal drücken, um die Drücken-Loslassen-Sequenz für die gewählte Standardtaste zu aktivieren, und sie erneut drücken, um sie auszuschalten.\nDie Turbotaste kann unter Einstellungen/Eingabe/Port-1-Steuerung zugewiesen werden." + "Umschalt-Modus. Die Turbotaste einmal drücken, um die Drücken-Loslassen-Sequenz für die gewählte Standardtaste zu aktivieren, und sie erneut drücken, um sie auszuschalten.\nDie Turbotaste kann unter Einstellungen/Eingabe/Port-X-Steuerung zugewiesen werden." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Haltemodus. Die Drücken-Loslassen-Sequenz für die ausgewählte Standardtaste ist aktiv, solange die Turbotaste gedrückt gehalten wird.\nDie Turbotaste kann unter Einstellungen/Eingabe/Anschluss-1-Steuerung zugewiesen werden.\nUm die Autofire-Funktion der Heimcomputer-Ära zu emulieren, die Turbo- und Standardtasten so einstellen, dass sie mit der Joystick-Feuertaste übereinstimmen." + "Halte-Modus. Die Drücken-Loslassen-Sequenz für die ausgewählte Standardtaste ist aktiv, solange die Turbotaste gedrückt gehalten wird.\nDie Turbotaste kann unter Einstellungen/Eingabe/Port-X-Steuerung zugewiesen werden.\nUm die Autofire-Funktion der Heimcomputer-Ära zu emulieren, die Turbo- und Standardtasten so einstellen, dass sie mit der Joystick-Feuertaste übereinstimmen." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Standard-Taste für Turbo" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Turbo-Zuweisung" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Standard aktive Taste für Turbo-Modus 'Einzeltaste'." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "Turbo aktiviert RetroPad-Zuweisung. Leer verwendet die Port-spezifische Zuweisung." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Erlaube Turbo bei Steuerkreuz-Richtungseingaben" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Turbo-Taste" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "Wenn aktiviert, können digitale Richtungseingaben (auch bekannt als Steuerkreuz oder \"Hatswitch\") Turbo sein." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "Zielturbo-Taste im „Einzeltaste“-Modus." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Turbo bei Steuerkreuz-Richtungseingaben erlauben" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, + "Wenn aktiviert, können digitale Richtungseingaben (auch bekannt als Steuerkreuz oder „Hatswitch“) Turbo sein." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -3463,7 +3504,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Einstellungen für Turbofeuer ändern.\nHinweis: Für die Turbofunktion muss dem Eingabegerät im entsprechenden Menü „Port X Steuerung“ eine Turbotaste zugewiesen werden." + "Turbo-Einstellungen ändern." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3656,7 +3697,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Wechselt die aktuelle Anzeige zwischen dem Menü und dem laufenden Inhalt." + "Schaltet die aktuelle Anzeige zwischen Menü und Inhalt um." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3732,7 +3773,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Schaltet den Inhalt zwischen pausierten und nicht-pausierten Zuständen um." + "Schaltet den Inhalt zwischen pausiert und nicht-pausiert um." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -3940,6 +3981,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Verringert den Index des aktuell ausgewählten Replayslots." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Turbo-Feuer (Umschalten)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Schaltet Turbo-Feuer an/aus." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Mauszeiger einfangen (Umschalten)" @@ -4453,7 +4502,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Legt fest, ob Savestatefähigkeiten der Core Info ignoriert werden sollen, so dass mit verwandten Funktionen experimentiert werden kann (Run-Ahead, Zurückspulen usw)." + "Legt fest, ob Savestate-Fähigkeiten der Core-Info ignoriert werden sollen, so dass mit verwandten Funktionen experimentiert werden kann (Run-Ahead, Zurückspulen usw.)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4697,7 +4746,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatisch ein Savestate erstellen, wenn der Inhalt geschlossen wird. RetroArch lädt dieses Savestate automatisch, wenn 'Savestate automatisch laden' aktiviert ist." + "Beim Schließen des Inhalts automatisch einen Savestate erstellen. Dieser Savestate wird beim Start geladen, wenn „Savestate automatisch laden“ aktiviert ist." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -4873,14 +4922,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Im Dateibrowser nur Dateien mit unterstützten Dateitypen anzeigen." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Eingebauten Mediaplayer verwenden" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Nach aktuellem Core filtern" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Die im Dateibrowser anzuzeigenden Dateien durch aktuellen Core filtern." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Letztes Startverzeichnis merken" @@ -4889,6 +4938,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Den Dateibrowser im zuletzt verwendeten Pfad öffnen, wenn Inhalte aus dem Startverzeichnis geladen werden. Hinweis: Der Pfad wird beim Neustart von RetroArch zurückgesetzt." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Eingebauten Mediaplayer verwenden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Integrierten Bildbetrachter verwenden" + ) /* Settings > Frame Throttle */ @@ -5689,6 +5746,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Eingabe (Automatische Konfiguration) Verbindungsbenachrichtigungen" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Eingabe (Automatische Konfiguration)-Fehlerbenachrichtigungen" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Cheat-Code-Benachrichtigungen" @@ -5709,6 +5770,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Eine Bildschirmmeldung anzeigen, wenn Eingabegeräte angeschlossen/getrennt werden." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Zeigt eine Nachricht auf dem Bildschirm an, wenn Eingabegeräte nicht konfiguriert werden konnten." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Benachrichtigungen beim Laden von Eingabe-Remaps" @@ -5839,7 +5904,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Die Schriftgröße in Punkten wählen." + "Gibt die Schriftgröße in Punkten an. Wenn Widgets verwendet werden, wirkt sich diese Größe nur auf die Anzeige der Statistiken auf dem Bildschirm aus." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -5996,7 +6061,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Den aktuell laufenden Inhalt pausieren, wenn das Menü aktiv ist." + "Pausiert den Inhalt, wenn das Menü aktiv ist." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6353,7 +6418,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Die Wiedergabelisten anzeigen. (Neustart erforderlich bei Ozone/XMB)" + "Wiedergabelisten im Hauptmenü anzeigen. Wird in GLUI ignoriert, wenn Wiedergabelisten und Navigationsleiste aktiviert sind." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Wiedergabelisten-Tabs anzeigen" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Wiedergabelisten-Tabs anzeigen. Wirkt sich nicht auf RGUI aus. Navigationsleiste muss in GLUI aktiviert sein. (Neustart erforderlich auf Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6833,14 +6906,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "\"Benutzer\" anzeigen" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Wiedergabelistensymbole" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Art des anzuzeigenden Playlist-Symbols." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Die \"Benutzer\"-Einstellungen anzeigen." @@ -7793,7 +7858,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "Prüft CRC auf mögliche Duplikate" + "Per Checksumme auf mögliche Duplikate scannen" ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, @@ -8028,7 +8093,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Dateibrowser" + "Startverzeichnis" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8261,7 +8326,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Entscheiden, welche Informationen zum laufenden Inhalt geteilt werden." + "Festlegen, welche Informationen über den Inhalt geteilt werden sollen." ) MSG_HASH( @@ -8849,7 +8914,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Das Schnellmenü verlassen und den aktuellen Inhalt fortsetzen." + "Den Inhalt fortsetzen und das Schnellmenü verlassen." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -8865,7 +8930,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Den aktuellen Inhalt schließen. Nicht gespeicherte Änderungen können verloren gehen." + "Den Inhalt schließen. Alle nicht gespeicherte Änderungen können verloren gehen." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9001,7 +9066,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Die Einstellungen für die aktuell laufende Anwendung ändern." + "Die Optionen für den Inhalt ändern." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9009,7 +9074,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Die Steuerung für den aktuell laufenden Inhalt ändern." + "Die Steuerung für den Inhalt ändern." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, @@ -9103,11 +9168,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Einstellungen zurücksetzen" + "Core-Optionen zurücksetzen" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Alle Core-Einstellungen auf Standardwerte zurücksetzen." + "Setzt alle Optionen des aktuellen Cores auf deren Standardwerte." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9615,7 +9680,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Shaderdateien auf Änderungen überwachen. Nach dem Speichern von Änderungen an einem Shader wird dieser automatisch neu kompiliert und auf den laufenden Inhalt angewendet." + "Shaderdateien auf neue Änderungen beobachten. Nach dem Speichern von Änderungen an einem Shader auf den Datenträger, wird dieser automatisch neu kompiliert und auf den Inhalt angewendet." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10068,6 +10133,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Miniaturansichten umlaufend" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Zufällig auswählen" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Zurück" @@ -10796,7 +10865,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Laufende Inhalte im Hintergrund anzeigen, während das Schnellmenü aktiv ist. Das Deaktivieren der Transparenz kann die Farben des Designs verändern." + "Die Hintergrundanzeige des Inhalts aktivieren, wenn das Schnellmenü aktiv ist. Das Deaktivieren der Transparenz kann die Farben des Themas verändern." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11088,6 +11157,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Art des Vorschaubildes, das auf der linken Seite gezeigt werden soll." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Symbolminiaturbild" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Art des anzuzeigenden Miniaturbildes für die Wiedergabeliste." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Dynamisches Hintergrundbild" @@ -11347,6 +11424,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Eiskalt" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Dunkelgrau" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Hellgrau" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11374,6 +11459,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Wiedergabelisten werden in alphabetischer Reihenfolge neu sortiert, nachdem die Herstellerkomponente ihrer Namen entfernt wurde." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Sekundäres Vorschaubild" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Das Inhaltsmetadatenfenster durch ein zusätzliches Vorschaubild ersetzen." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Lauftext für Inhaltsmetadaten verwenden" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Wenn aktiviert, belegen alle Inhaltsmetadaten in der rechten Seitenleiste der Wiedergabelisten (zugeordneter Core, Spielzeit) eine einzelne Zeile. Text, der die Breite der Seitenleiste überschreitet, wird als Lauftext angezeigt. Wenn deaktiviert, werden alle Inhaltsmetadaten statisch angezeigt und so umbrochen, dass sie so viele Zeilen wie erforderlich belegen." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Vorschaubilder-Skalierungsfaktor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Vorschaubilderleiste skalieren." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Farbschema" @@ -11422,30 +11532,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_PURPLE_RAIN, "Violetter Regen" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Sekundäres Vorschaubild" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Das Inhaltsmetadatenfenster durch ein zusätzliches Vorschaubild ersetzen." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Lauftext für Inhaltsmetadaten verwenden" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Wenn aktiviert, belegen alle Inhaltsmetadaten in der rechten Seitenleiste der Wiedergabelisten (zugeordneter Core, Spielzeit) eine einzelne Zeile. Text, der die Breite der Seitenleiste überschreitet, wird als Lauftext angezeigt. Wenn deaktiviert, werden alle Inhaltsmetadaten statisch angezeigt und so umbrochen, dass sie so viele Zeilen wie erforderlich belegen." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Vorschaubilder-Skalierungsfaktor" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Vorschaubilderleiste skalieren." - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -12334,10 +12421,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Tastatur" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Integrierten Bildbetrachter verwenden" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Maximale Anzahl von Zwischenbildern" @@ -12461,14 +12544,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Wähle aus Wiedergabenliste" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Fortsetzen" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Das Schnellmenü verlassen und den aktuellen Inhalt fortsetzen." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Liste von %u Treffern ansehen" @@ -13059,10 +13134,6 @@ MSG_HASH( MSG_AUTODETECT, "Automatisch erkennen" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Automatisches Laden des Speicherzustands aus" - ) MSG_HASH( MSG_CAPABILITIES, "Fähigkeiten" @@ -14151,6 +14222,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Virtuelles Laufwerk konnte nicht geschlossen werden." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Automatisches Laden des Speicherzustands aus" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Automatisches Laden des Savestates aus \"%s\" fehlgeschlagen." @@ -14459,6 +14534,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Ein Cheat wurde aktiviert. Errungenschaften-Hardcore-Modus wurde für die aktuelle Sitzung deaktiviert." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Hardcore-Modus für Errungenschaften von Host geändert." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "Netplay-Host muss aktualisiert werden. Hardcore-Modus für Errungenschaften wurde für aktuelle Sitzung deaktiviert." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "%s gemeistert" @@ -15399,7 +15482,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Text am unteren Bildschirm einblenden. Aktivieren, um Tastenbeschreibungen auf dem unteren Bildschirm anzuzeigen. Dies schließt das Speicherdatum aus." + "Text am unteren Bildschirm einblenden. Aktivieren, um Schaltflächenbeschreibungen auf dem unteren Bildschirm anzuzeigen. Dies schließt das Savestate-Speicherdatum aus." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, @@ -15468,3 +15551,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "gestoppt." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "KI-Player überschreiben" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "KI-Spieler überschreiben Unterlabel" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "Spiel-KI" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "P1 überschreiben" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Spieler 01 überschreiben" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "P2 überschreiben" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Spieler 02 überschreiben" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Fehlerinformation anzeigen" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Fehlerinformation anzeigen" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "„Spiel-KI“ anzeigen" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Die Option „Spiel-KI“ anzeigen." + ) +#endif diff --git a/intl/msg_hash_el.h b/intl/msg_hash_el.h index 25225c6ca7..ee33f6d25a 100644 --- a/intl/msg_hash_el.h +++ b/intl/msg_hash_el.h @@ -2225,14 +2225,15 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, "Δευτερόλεπτα τα οποία χρειάζεται να κρατήσετε πατημένο κάποιο κουμπί μέχρι την σύνδεση του." ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Πλήκτρο \"Turbo\"" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Λειτουργία Turbo" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Προκαθορισμένο Πλήκτρο για Τούρμπο" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "Πλήκτρο \"Turbo\"" @@ -2330,10 +2331,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, "Επιστροφή" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Εναλλάσσει εκτελούμενο περιεχόμενο μεταξύ καταστάσεων σε παύση και μη παύση." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, @@ -2579,10 +2576,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, "Όπλο D-pad Δεξιά" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "Ενεργοποίηση Turbo" - ) /* Settings > Latency */ @@ -2705,13 +2698,17 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Φιλτράρισμα άγνωστων επεκτάσεων" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "Φιλτράρισμα με βάση τον τρέχων πυρήνα" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, "Χρήση Ενσωματωμένου Αναπαραγωγέα Πολυμέσων Use Builtin Media Player" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, - "Φιλτράρισμα με βάση τον τρέχων πυρήνα" + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Χρήση Ενσωματωμένου Προβολέα Εικόνων" ) /* Settings > Frame Throttle */ @@ -3352,7 +3349,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Περιηγητής Αρχείων" + "Ευρετήριο έναρξης" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, @@ -3667,10 +3664,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "Συνέχιση" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Συνέχιση εκτέλεσης του τρέχοντος περιεχομένου και έξοδος από το Γρήγορο Μενού." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, "Επανεκκίνηση" @@ -3743,18 +3736,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "Επιλογές Πυρήνα" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Αλλαγή επιλογών για το τρέχον εκτελούμενο περιεχόμενο." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "Χειρισμοί" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Αλλαγή χειρισμών για το τρέχον εκτελούμενο περιεχόμενο." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Απάτες" @@ -4571,6 +4556,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -4990,10 +4977,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Χρήστης" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Χρήση Ενσωματωμένου Προβολέα Εικόνων" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WAITABLE_SWAPCHAINS, "Σκληρός συγχρονισμός επεξεργαστή και κάρτας γραφικών. Μειώνει την καθυστέρηση με τίμημα την επίδοση." @@ -5045,14 +5028,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, "Εξαναγκασμένη αναλογία απεικόνισης" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Συνέχιση" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Συνέχιση εκτέλεσης του τρέχοντος περιεχομένου και έξοδος από το Γρήγορο Μενού." - ) MSG_HASH( /* FIXME Still exists in a comment about being removed */ MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, "Αδιαφάνεια Υποσέλιδου" @@ -5391,10 +5366,6 @@ MSG_HASH( MSG_AUTODETECT, "Αυτόματη ανίχνευση" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Αυτόματη φόρτωση κατάστασης αποθήκευσης από" - ) MSG_HASH( MSG_CAPABILITIES, "Ικανότητες" @@ -5607,6 +5578,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "Viewport size calculation failed! Will continue using raw data. This will probably not work right ..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Αυτόματη φόρτωση κατάστασης αποθήκευσης από" + ) MSG_HASH( MSG_DEVICE_CONFIGURED_IN_PORT, "διαμορφώθηκε στην θύρα" @@ -5967,4 +5942,11 @@ MSG_HASH( ) #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_en.h b/intl/msg_hash_en.h index bd90872f63..4a51481d9c 100644 --- a/intl/msg_hash_en.h +++ b/intl/msg_hash_en.h @@ -525,14 +525,11 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_ANALOG_SENSITIVITY, "Adjust the sensitivity of analogue sticks." ) + MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_MODE, "Select the general behaviour of turbo mode." ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "If enabled, digital directional inputs (also known as D-Pad or 'hatswitch') can be turbo." - ) MSG_HASH( MENU_ENUM_LABEL_HELP_INPUT_RETROPAD_BINDS, "Libretro uses a virtual gamepad abstraction known as the 'RetroPad' to communicate from frontends (like RetroArch) to cores and vice versa. This menu determines how the virtual RetroPad is mapped to the physical input devices and which virtual input ports these devices occupy.\nIf a physical input device is recognised and autoconfigured correctly, users probably do not need to use this menu at all, and for core-specific input changes, should use the Quick Menu's 'Controls' submenu instead." @@ -838,6 +835,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_MOUSE_CURSOR, "Show the Mouse Cursor With Overlay" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analogue Recentring Zone" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analogue stick input will be relative to first touch if pressed within this zone." + ) /* Settings > On-Screen Display > On-Screen Overlay > Keyboard Overlay */ @@ -1628,7 +1633,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Enable background display of running content while Quick Menu is active. Disabling transparency may alter theme colours." + "Enable background display of content while Quick Menu is active. Disabling transparency may alter theme colours." ) /* RGUI: Settings Options */ @@ -1715,9 +1720,18 @@ MSG_HASH( /* XMB: Settings Options */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Grey Dark" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Grey Light" + ) /* Ozone: Settings > User Interface > Appearance */ + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Colour Theme" @@ -1743,6 +1757,7 @@ MSG_HASH( "Grey Light" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -2269,10 +2284,6 @@ MSG_HASH( MSG_3DS_BOTTOM_MENU_DEFAULT, "Tap the Touch Screen to go\nto the RetroArch menu" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Display bottom menu font. Enable to display button descriptions on the bottom screen. This excludes the save-state date." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Font Colour Red" @@ -2307,4 +2318,11 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, "Scan Finished.

\nIn order for content to be correctly scanned, you must:\n
  • have a compatible core already downloaded
  • \n
  • have \"Core Info Files\" updated with the Online Updater
  • \n
  • have \"Databases\" updated with the Online Updater
  • \n
  • restart RetroArch if any of the above was just done
\nFinally, the content must match existing databases from here. If it is still not working, consider submitting a bug report." ) +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_eo.h b/intl/msg_hash_eo.h index de0cb1710e..06282b591a 100644 --- a/intl/msg_hash_eo.h +++ b/intl/msg_hash_eo.h @@ -545,6 +545,7 @@ MSG_HASH( #endif #ifdef ANDROID #endif + MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, "Enable hotkeys" @@ -575,10 +576,6 @@ MSG_HASH( /* Settings > Input > Port # Controls */ -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "Turbo enable" - ) /* Settings > Latency */ @@ -1039,6 +1036,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -1223,4 +1222,11 @@ MSG_HASH( ) #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index d61b74f182..ea6c557409 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Selecciona el núcleo a usar." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Descargar núcleo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Descarga el núcleo que esté cargado." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Busca una implementación de un núcleo libretro. La posición inicial del explorador dependerá de la ruta del directorio de núcleos. En caso de estar en blanco, la posición inicial será la raíz.\nSi el directorio de núcleos es un directorio, este se utilizará como posición inicial. Si es una ruta completa, la posición será la carpeta donde se encuentre el archivo." @@ -910,6 +918,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Soporte de Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Soporte de SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Soporte de libusb" @@ -1960,7 +1972,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Inserta uno o varios fotogramas negros entre fotogramas. Puede reducir en gran medida la distorsión por movimiento (motion blur) emulando el «scan-out» de los monitores CRT a costa de sacrificar brillo. No combinar con un intervalo de intercambio de VSync superior a 1, con subfotogramas, con el retraso de fotogramas o con Sincronizar FPS al contenido." + "ADVERTENCIA: los parpadeos rápidos pueden provocar persistencia de la imagen («imágenes fantasma») en algunas pantallas. Utiliza esta opción bajo tu propia responsabilidad. // Inserta uno o varios fotogramas negros entre fotogramas. Puede reducir en gran medida la distorsión por movimiento (motion blur) emulando el «scan-out» de los monitores CRT a costa de sacrificar brillo." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2044,7 +2056,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Introduce uno o varios fotogramas adicionales del shader entre fotogramas. Permite que los shaders reproduzcan efectos a una velocidad de fotogramas superior a la del contenido. Debería ser el mismo valor que la frecuencia de hercios actual de la pantalla. No combinar con un intervalo de intercambio de VSync superior a 1, con inserción de fotogramas negros, con el retraso de fotogramas o con Sincronizar FPS al contenido." + "ADVERTENCIA: los parpadeos rápidos pueden provocar persistencia de la imagen («imágenes fantasma») en algunas pantallas. Utiliza esta opción bajo tu propia responsabilidad. // Simula de forma básica el escalonamiento de las líneas de barrido a lo largo de varios subfotogramas dividendo la pantalla en partes verticales y renderizando cada una de las mismas en función de los subfotogramas que existan." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2120,7 +2132,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Simula de forma básica el escalonamiento de las líneas de barrido a lo largo de varios subfotogramas dividendo la pantalla en partes verticales y renderizando cada una de las mismas en función de los subfotogramas que existan." + "ADVERTENCIA: los parpadeos rápidos pueden provocar persistencia de la imagen («imágenes fantasma») en algunas pantallas. Utiliza esta opción bajo tu propia responsabilidad. // Simula de forma básica el escalonamiento de las líneas de barrido a lo largo de varios subfotogramas dividendo la pantalla en partes verticales y renderizando cada una de las mismas en función de los subfotogramas que existan." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2547,7 +2559,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Escala solo la altura o también la anchura. Los escalados irregulares se aplicarán a las imágenes en alta resolución." + "Escala la altura o la anchura. Los escalados irregulares se aplicarán solo a imágenes en alta resolución." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2645,11 +2657,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Compensación personalizada usada para desplazar horizontalmente el área de visualización (si es más ancha que la altura del contenido). 0,0 para extremo izquierdo y 1,0 para extremo derecho." + "Establece la posición horizontal del contenido cuando el área de visualización sea más ancha que el contenido. 0,0 para extremo izquierdo, 0,5 para centrar, 1,0 para extremo derecho." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Compensación personalizada usada para desplazar verticalmente el área de visualización (si es más alta que la altura del contenido). 0,0 para extremo superior y 1,0 para extremo inferior." + "Establece la posición vertical del contenido cuando el área de visualización sea más alta que el contenido. 0,0 para extremo superior, 0,5 para centrar, 1,0 para extremo inferior." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2670,11 +2682,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Compensación personalizada usada para desplazar horizontalmente el área de visualización (si es más ancha que la altura del contenido) en una orientación vertical. 0,0 para extremo izquierdo y 1,0 para extremo derecho." + "Establece la posición horizontal del contenido cuando el área de visualización sea más ancha que el contenido. 0,0 para extremo izquierdo, 0,5 para centrar, 1,0 para extremo derecho (en orientación vertical)." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Compensación personalizada usada para desplazar verticalmente el área de visualización (si es más alta que la altura del contenido) en una orientación vertical. 0,0 para extremo superior y 1,0 para extremo inferior." + "Establece la posición vertical del contenido cuando el área de visualización sea más alta que el contenido. 0,0 para extremo superior, 0,5 para centrar, 1,0 para extremo inferior (en orientación vertical)." ) #endif MSG_HASH( @@ -2785,7 +2797,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_FRAME_DELAY, - "Establece el tiempo de espera en milisegundos entre la ejecución del núcleo y la presentación de la imagen. Puede reducir la latencia a costa de aumentar la probabilidad de sufrir tirones de imagen.\nUn valor igual o superior a 20 se considerará como un porcentaje de la duración de fotogramas." + "Establece el tiempo de espera en milisegundos entre la ejecución del núcleo y la presentación de la imagen. Reduce la latencia a costa de aumentar la probabilidad de sufrir tirones en la imagen.\nUn valor igual o superior a 20 se considerará como un porcentaje de la duración de fotogramas." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTO, @@ -2922,7 +2934,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Silenciar sonido al usar el avance rápido" + "Silenciar audio durante el avance rápido" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2930,12 +2942,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Acelerar al usar el avance rápido" + "Acelerar audio durante el avance rápido" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Acelera el audio al usar el avance rápido. Evitará los chasquidos en el audio, pero cambiará su tono." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Silenciar audio durante el rebobinado" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Silencia automáticamente el audio al utilizar la función de rebobinado." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Ganancia de volumen (dB)" @@ -3477,22 +3497,35 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Mantén durante" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Al desactivar esta opción, se detendrán todas las opciones del modo turbo/autodisparo/«autofire»." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Periodo del turbo" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Indica la duración (en fotogramas) durante la que se pulsarán los botones con turbo." + "Indica la duración en fotogramas durante la que se pulsarán los botones con turbo." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, "Ciclo de trabajo del turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, "Indica el número de fotogramas en los que mantendrán pulsados los botones dentro del periodo del turbo. Si el valor es igual o superior al periodo del turbo, los botones no se soltarán nunca." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Medio ciclo" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Modo del turbo" @@ -3519,34 +3552,42 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Modo de manejo clásico de dos botones. Mantén pulsado un botón y pulsa a la vez el botón de turbo para activar la secuencia de pulsación y liberación.\nEl botón de turbo puede asignarse en Ajustes/Entrada/Controles del puerto 1." + "Modo de manejo clásico de dos botones. Mantén pulsado un botón y pulsa a la vez el botón de turbo para activar la secuencia de pulsación y liberación.\nEl turbo puede asignarse en Ajustes/Entrada/Controles del puerto X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Manejo clásico de dos botones. Mantén pulsado un botón y pulsa a la vez el botón de turbo para activar su modo turbo. Desactivar turbo: mantén pulsado el botón y vuelve a pulsar el botón de turbo.\nEl botón de turbo puede asignarse en Ajustes/Entrada/Controles del puerto 1." + "Manejo clásico de dos botones. Mantén pulsado un botón y pulsa a la vez el botón de turbo para activar su modo turbo. Desactivar turbo: mantén pulsado el botón y vuelve a pulsar el botón de turbo.\nEl turbo puede asignarse en Ajustes/Entrada/Controles del puerto X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Modo de alternancia. Pulsa el botón de turbo una vez para activar la secuencia de pulsación y liberación del botón predeterminado seleccionado y vuelve a pulsar el botón de turbo para desactivarlo.\nEl botón de turbo puede asignarse en Ajustes/Entrada/Controles del puerto 1." + "Modo de alternancia. Pulsa el botón de turbo una vez para activar la secuencia de pulsación y liberación del botón predeterminado seleccionado y vuelve a pulsar el botón de turbo para desactivarlo.\nEl turbo puede asignarse en Ajustes/Entrada/Controles del puerto X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Modo de mantener pulsado el botón. La secuencia de pulsación y liberación para el botón predeterminado seleccionado se mantendrá activa siempre y cuando se mantenga pulsado el botón de turbo.\nEl botón de turbo puede asignarse en Ajustes/Entrada/Controles del puerto 1.\nSi deseas emular el método de autodisparo/«autofire» de la época de los PC domésticos, asigna los botones de turbo y predeterminado para que sean el mismo que el botón de disparo del mando." + "Modo de mantener pulsado el botón. La secuencia de pulsación y liberación para el botón predeterminado seleccionado se mantendrá activa siempre y cuando se mantenga pulsado el botón de turbo.\nEl turbo puede asignarse en Ajustes/Entrada/Controles del puerto X.\nSi deseas emular el método de autodisparo/«autofire» de la época de los PC domésticos, asigna los botones de turbo y predeterminado para que sean el mismo que el botón de disparo del mando." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Botón predeterminado del turbo" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Asignación de turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Asigna el botón individual predeterminado para el modo turbo." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "La asignación que activará el turbo en el RetroPad. Si está en blanco, se utilizará la asignación específica del puerto." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Botón de turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "El botón que se usará para el turbo en el modo de botón dedicado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, "Permitir direcciones de la cruceta con turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, "Permite que los botones digitales de dirección (también conocidos como la cruceta o «seta») puedan usar el modo turbo." ) MSG_HASH( @@ -3555,7 +3596,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Cambia los ajustes del turbo.\nNota: la característica de turbo necesita que asignes un botón de turbo a tu dispositivo de entrada en el menú «Controles del puerto X» correspondiente." + "Cambia los ajustes del turbo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3752,7 +3793,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Muestra el menú o el contenido en ejecución." + "Muestra el menú o el contenido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3832,7 +3873,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Pone el contenido en ejecución en pausa o la desactiva." + "Pausa o reanuda el contenido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -4040,6 +4081,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Disminuye el índice de la posición de repetición seleccionada." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Pulsación turbo (alternar)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Activa o desactiva el modo de disparo turbo/autodisparo/«autofire»." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Capturar ratón (alternar)" @@ -4801,7 +4850,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Hace un guardado rápido de forma automática al cerrar un contenido. RetroArch lo cargará automáticamente si la opción «Cargar guardado rápido automáticamente» está activada." + "Hace un guardado rápido de forma automática al cerrar un contenido. El guardado rápido se cargará automáticamente si la opción «Cargar guardado rápido automáticamente» está activada." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -4981,14 +5030,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Muestra en el explorador de archivos únicamente a aquellos archivos que tengan extensiones conocidas." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usar visor de medios integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrar por núcleo actual" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Muestra en el explorador de archivos únicamente los archivos relacionados con el núcleo actual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Recordar el último directorio usado" @@ -4997,6 +5046,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Abre el explorador de archivos en el último directorio usado al cargar contenidos desde el directorio inicial. Nota: la posición volverá a su valor predeterminado al reiniciar RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Usar visor de medios integrado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Usar visor de imágenes integrado" + ) /* Settings > Frame Throttle */ @@ -5801,6 +5858,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Notificaciones de conexión de entrada (autoconfiguración)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Notificaciones de fallos de entrada (autoconfiguración)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Notificaciones de trucos" @@ -5821,6 +5882,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Muestra un mensaje en pantalla al conectar o desconectar dispositivos de entrada." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Muestra un mensaje en pantalla cuando no se puedan configurar dispositivos de entrada." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Notificaciones de carga de reasignaciones de entrada" @@ -5951,7 +6016,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Especifica el tamaño de la fuente de letra en puntos." + "Especifica el tamaño de la fuente en puntos. Cuando se utilicen los widgets, el tamaño solo se aplicará a las estadísticas en pantalla." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6108,7 +6173,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Si el menú es activado, pausará el contenido que se esté ejecutando." + "Pausa el contenido si el menú está activo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6469,7 +6534,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Muestra las listas de reproducción (es necesario reiniciar en Ozone/XMB)." + "Muestra las listas de reproducción en el menú principal. Se ignorará esta opción en GLUI si se activan las secciones de la lista de reproducción y la barra de navegación." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Mostrar secciones de listas de reproducción" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Muestra las secciones de las listas de reproducción. No afecta a RGUI. Es necesario activar la barra de navegación en GLUI (es necesario reiniciar en Ozone/XMB)." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6949,14 +7022,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Mostrar Usuario" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Iconos de las listas de reproducción" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "El tipo de miniatura que se mostrará como icono de las listas de reproducción." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Muestra los ajustes de usuario." @@ -8180,7 +8245,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Explorador de archivos" + "Directorio inicial" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8425,7 +8490,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Decide la información que se compartirá de los contenidos que ejecutes." + "Decide la información que se compartirá de los contenidos." ) MSG_HASH( @@ -9025,7 +9090,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Reanuda el contenido ejecutado y abandona el menú rápido." + "Reanuda el contenido y abandona el menú rápido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -9041,7 +9106,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Cierra el contenido actual. Se perderá cualquier progreso no guardado." + "Cierra el contenido. Se perderá cualquier progreso no guardado." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9177,7 +9242,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Cambia las opciones del contenido cargado." + "Cambia las opciones del contenido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9185,7 +9250,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Cambia los controles del contenido cargado." + "Cambia los controles del contenido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9279,11 +9344,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Restablecer opciones" + "Restablecer opciones del núcleo" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Cambia todas las opciones del núcleo a su configuración predeterminada." + "Reinicia todas las opciones del núcleo actual a sus valores predeterminados." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9807,7 +9872,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Busca cambios en los archivos de shaders. Una vez hayas guardado los cambios de un shader del disco, el shader se recompilará automáticamente y se aplicará al contenido ejecutado." + "Busca cambios en los archivos de shaders. Una vez hayas guardado los cambios de un shader del disco, el shader se recompilará automáticamente y se aplicará al contenido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10268,6 +10333,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Intercambiar miniaturas" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Selección aleatoria" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Volver" @@ -10988,7 +11057,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Muestra el contenido ejecutado en el fondo del menú rápido. Desactivar la transparencia podría alterar los colores del tema." + "Muestra el contenido en el fondo del menú rápido. Desactivar la transparencia podría alterar los colores del tema." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11312,6 +11381,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Indica el tipo de miniatura que se mostrará en la parte izquierda de la pantalla." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Miniatura de icono" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "El tipo de miniatura que se mostrará como icono de las listas de reproducción." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Fondo dinámico" @@ -11591,6 +11668,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Gélido" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Gris oscuro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Gris claro" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11618,6 +11703,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Reordena las listas de reproducción por orden alfabético quitando la parte del fabricante de sus nombres." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Miniatura secundaria" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Sustituye el panel de metadatos por otra miniatura." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Mostrar metadatos de contenidos en movimiento" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Si se activa esta opción, cada uno de los elementos de los metadatos de un contenido que se muestren en la barra derecha de las listas de reproducción (núcleo asociado, tiempo de juego...) ocupará únicamente una línea, y las cadenas que superen el ancho disponible se desplazarán automáticamente. Al desactivarla, cada elemento de los metadatos se mostrará de forma estática, ocupando las líneas que sean necesarias." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Factor de escala de miniaturas" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Cambia el tamaño de la barra de miniaturas." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Tema de colores" @@ -11650,10 +11760,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_DRACULA, "Drácula" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, - "Selenio" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, "Solarized (oscuro)" @@ -11675,30 +11781,11 @@ MSG_HASH( "Lluvia violeta" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Miniatura secundaria" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Sustituye el panel de metadatos por otra miniatura." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Mostrar metadatos de contenidos en movimiento" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Si se activa esta opción, cada uno de los elementos de los metadatos de un contenido que se muestren en la barra derecha de las listas de reproducción (núcleo asociado, tiempo de juego...) ocupará únicamente una línea, y las cadenas que superen el ancho disponible se desplazarán automáticamente. Al desactivarla, cada elemento de los metadatos se mostrará de forma estática, ocupando las líneas que sean necesarias." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Factor de escala de miniaturas" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Cambia el tamaño de la barra de miniaturas." + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "Selenio" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -12654,10 +12741,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Teclado" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Usar visor de imágenes integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Máximo de imágenes en swap chain" @@ -12793,14 +12876,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Seleccionar de una lista de reproducción" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Reanudar" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Reanuda el contenido actual y abandona el menú rápido." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Ver lista de %u coincidencias" @@ -13399,10 +13474,6 @@ MSG_HASH( MSG_AUTODETECT, "Detección automática" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Carga automática de guardado rápido en" - ) MSG_HASH( MSG_CAPABILITIES, "Funcionalidades" @@ -14483,6 +14554,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Error al cerrar la bandeja de discos virtual." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Carga automática de guardado rápido en" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Error al cargar automáticamente el guardado rápido «%s»." @@ -14791,6 +14866,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Se ha activado un truco. Los logros Hardcore han sido desactivados para esta sesión." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Logros Hardcore cambiados por el servidor." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "El servidor de juego en red necesita una actualización. Los logros Hardcore han sido desactivados para esta sesión." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Has dominado %s" @@ -14829,23 +14912,23 @@ MSG_HASH( ) MSG_HASH( MSG_CHEEVOS_HARDCORE_PAUSED_MANUAL_FRAME_DELAY, - "Modo «hardcore» pausado. No se permite ajustar manualmente el retraso en los fotogramas de vídeo." + "Modo Hardcore pausado. No se permite ajustar manualmente el retraso en los fotogramas de vídeo." ) MSG_HASH( MSG_CHEEVOS_HARDCORE_PAUSED_VSYNC_SWAP_INTERVAL, - "Modo «hardcore» pausado. No se permite un valor de intercambio de sincronía vertical superior a 1." + "Modo Hardcore pausado. No se permite un valor de intercambio de sincronía vertical superior a 1." ) MSG_HASH( MSG_CHEEVOS_HARDCORE_PAUSED_BLACK_FRAME_INSERTION, - "Modo «hardcore» pausado. No se permite insertar fotogramas negros." + "Modo Hardcore pausado. No se permite insertar fotogramas negros." ) MSG_HASH( MSG_CHEEVOS_HARDCORE_PAUSED_SETTING_NOT_ALLOWED, - "Modo «hardcore» pausado. Ajuste no permitido: %s=%s" + "Modo Hardcore pausado. Ajuste no permitido: %s=%s" ) MSG_HASH( MSG_CHEEVOS_HARDCORE_PAUSED_SYSTEM_NOT_FOR_CORE, - "Modo «hardcore» pausado. No puedes desbloquear logros «hardcore» de %s con %s" + "Modo Hardcore pausado. No puedes desbloquear logros Hardcore de %s con %s" ) MSG_HASH( MSG_CHEEVOS_GAME_NOT_IDENTIFIED, @@ -15800,3 +15883,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "detenido." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "Anular jugador de IA" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "Descripción de anulación de jugador de IA" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "IA de juego" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Anular J1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Anula al jugador 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Anular J2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Anula al jugador 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Mostrar depuración" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Muestra la depuración" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Mostrar IA de juego" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Muestra la opción «IA de juego»." + ) +#endif diff --git a/intl/msg_hash_fa.h b/intl/msg_hash_fa.h index d25ce102f5..23444b604d 100644 --- a/intl/msg_hash_fa.h +++ b/intl/msg_hash_fa.h @@ -2092,10 +2092,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "صدای ترکیب‌کننده را ساکت کنید." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "ساکت کردن در زمان جلو کشیدن تصویر" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, "افزونهٔ DSP" @@ -2301,6 +2297,7 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "تعلیق" ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "حالت توربو" @@ -2325,10 +2322,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, "یک دکمه (نگه داشتن)" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "دکمهٔ پیشفرض توربو" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, "کلیدهای میانبر" @@ -2511,10 +2504,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, "خشاب تفنگ" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "توربو (سرعتی)" - ) /* Settings > Latency */ @@ -2972,7 +2961,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "مرورگر فایل" + "مسیر شروع" ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, @@ -3531,6 +3520,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -3673,10 +3664,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, "ذخیرهٔ ضبط‌ها در پوشهٔ خروجی" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "ادامه" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, "بازی تحت شبکه" @@ -3811,4 +3798,11 @@ MSG_HASH( ) #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_fi.h b/intl/msg_hash_fi.h index cb5eb0fa01..ec8ff433bc 100644 --- a/intl/msg_hash_fi.h +++ b/intl/msg_hash_fi.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Valitse käytettävä ydin." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Vapauta ydin" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Vapauta ladattu ydin." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Selaa libretro ytimiä. Tiedostoselaimen aloituspaikka riippuu ydinten kansion polusta. Jos tyhjä, se alkaa juuresta.\nJos ydinkansion on kansio, valikko käyttää sitä pääkansiona. Jos ydinkansio on täydellinen polku, se alkaa kansiosta, jossa ytimen tiedosto on." @@ -906,6 +914,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2-tuki" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL-tuki" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb-tuki" @@ -2652,18 +2664,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE, "Mykistä kaikki äänet äänettömässä tilassa." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Mykistä pikakelattaessa" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "Mykistä ääni automaattisesti, kun pikakelaus on käytössä." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Nopeuta pikakelattaessa" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Nopeuta ääni pikakelatessa. Estää säröilyä, mutta nostaa taajuutta." @@ -3125,22 +3129,15 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Pidä" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbotulitus" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbon jakso" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Ajanjakso (kuvissa) kun turbo-yhteensopivia painikkeita painetaan." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Turbon käyttöjakso" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Kuvien määrä turbojaksolla, jonka aikana painikkeita pidetään painettuina. Jos tämä luku on yhtä suuri tai suurempi kuin turbojakso, painikkeet eivät koskaan vapaudu." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Turbotila" @@ -3166,12 +3163,8 @@ MSG_HASH( "Yksittäinen painike (Pito)" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Turbon oletuspainike" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Oletusarvoinen aktiivinen painike turbotilalle käyttäessä tilaa 'yksi painike'." + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Turbopainike" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -3322,10 +3315,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, "Valikon vaihto" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Vaihtaa valikon ja käynnissä olevan sisällön välillä nykyisellä näytöllä." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, "Lopeta (näppäin yhdistelmä)" @@ -3398,10 +3387,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "Keskeytä" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Vaihtaa käynnissä olevan sisällön keskeytyksen päälle tai pois." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, "Seuraava kuva" @@ -4183,10 +4168,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Tilan automaattinen tallennus" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Luo tilatallennus automaattisesti kun suljet sisällön. RetroArch lataa automaattisesti tämän tilatallennuksen, jos \"Lataa tilatallennus automaattisesti\" on käytössä." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "Tilan automaattinen lataaminen" @@ -4361,10 +4342,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Suodata tiedostoja tiedostoselaimessa tuettujen tiedostopäätteiden mukaan." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Käytä sisäänrakennettua mediasoitinta" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Suodata nykyisen ytimen mukaan" @@ -4377,6 +4354,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Avaa tiedostoselain viimeksi käytetyssä sijainnissa, kun lataat sisältöä aloitushakemistosta. Huom: sijainti palautetaan oletusarvoon RetroArchin uudelleenkäynnistyessä." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Käytä sisäänrakennettua mediasoitinta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Käytä sisäänrakennettua kuvankatselinta" + ) /* Settings > Frame Throttle */ @@ -5009,6 +4994,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Syötelaitteen (Automaattinen kokoonpano) yhdistämisen ilmoitukset" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Syötelaitteen (Autoconfig) epäonnistumisen ilmoitukset" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Huijauskoodi-ilmoitukset" @@ -5029,6 +5018,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Näytä näytöllä ilmoitus viesti, kun syöttölaitteita yhdistetään/irrotetaan." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Näytä viesti, kun syötelaitteita ei voitu määrittää." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Syötteen uudelleenmääritys ladattu -ilmoitukset" @@ -5145,10 +5138,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "Ilmoituksen koko" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Määritä fontin koko pisteinä." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, "Ilmoituksen sijainti (vaaka)" @@ -5258,10 +5247,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, "Keskeytä sisältö kun valikko on aktiivisena" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Keskeytä käynnissä oleva sisältö, jos valikko on aktiivinen." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, "Jatka sisältöä tilatallennusten käyttämisen jälkeen" @@ -6033,10 +6018,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Näytä \"Käyttäjä\"" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Soittolistan kuvakkeet" - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Näytä \"Käyttäjä\"-asetukset." @@ -7120,7 +7101,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Tiedostoselain" + "Aloituskansio" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, @@ -7935,10 +7916,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "Jatka" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Jatka käynnissä olevaa sisältöä ja poistu pikavalikosta." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, "Käynnistä uudelleen" @@ -7951,10 +7928,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, "Sulje sisältö" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Sulje nykyinen sisältö. Tallentamattomat muutokset saattavat kadota." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, "Ota kuvakaappaus" @@ -8087,18 +8060,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "Ytimen asetukset" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Muuta käynnissä olevan sisällön asetuksia." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "Ohjaus" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Muuta käynnissä olevan sisällön ohjausasetuksia." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Huijauskoodit" @@ -8191,11 +8156,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Nollaa asetukset" + "Nollaa ytimen asetukset" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Aseta kaikki ydinasetukset oletusarvoihin." + "Aseta kaikki nykyisen ytimen valinnat oletusarvoihin." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9076,6 +9041,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Kierrä pienoiskuvia" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Satunnainen valinta" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Takaisin" @@ -9830,10 +9799,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_TRANSPARENCY, "Läpinäkyvyys" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Ota käyttöön sisällön taustanäyttö, kun pikavalikko on aktiivisena. Läpinäkyvyyden poistaminen voi muuttaa teeman värejä." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, "Varjotehosteet" @@ -10407,6 +10372,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Jäänkylmä" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Tumman harmaa" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Vaalean harmaa" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -10426,6 +10399,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Soittolistat järjestetään uudelleen aakkosjärjestykseen sen jälkeen, kun valmistajan nimi soittolistojen nimistä on poistettu." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Toissijainen esikatselukuva" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Korvaa sisällön metatieto toisella esikatselukuvalla." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Käytä tekstinauhaa sisällön metatietoon" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Kun käytössä, soittolistojen oikean sivun metatietojen jokainen kohde (liitetty ydin, toistoaika) on yhdellä rivillä; merkkijonot, jotka ylittävät sivupalkin leveyden, näytetään vieritettävänä tekstinauhana. Kun pois päältä, kaikki sisällön metatiedot näytetään kiinteästi rivitettynä niin monella riville kuin tarvitaan." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Esikatselukuvan skaalauskerroin" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Skaalaa esikatselukuvien palkin koko." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Väriteema" @@ -10482,30 +10480,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_PURPLE_RAIN, "Violetti sade" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Toissijainen esikatselukuva" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Korvaa sisällön metatieto toisella esikatselukuvalla." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Käytä tekstinauhaa sisällön metatietoon" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Kun käytössä, soittolistojen oikean sivun metatietojen jokainen kohde (liitetty ydin, toistoaika) on yhdellä rivillä; merkkijonot, jotka ylittävät sivupalkin leveyden, näytetään vieritettävänä tekstinauhana. Kun pois päältä, kaikki sisällön metatiedot näytetään kiinteästi rivitettynä niin monella riville kuin tarvitaan." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Esikatselukuvan skaalauskerroin" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Skaalaa esikatselukuvien palkin koko." - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -11458,10 +11433,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Näp" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Käytä sisäänrakennettua kuvankatselinta" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "Määrää videoajurin käyttämään yksiselitteisesti määritettyä puskurointitilaa." @@ -11581,14 +11552,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Valitse soittolistalta" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Jatka" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Jatka käynnissä olevaa sisältöä ja poistu pikavalikosta." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Näytä luettelo %u vastaavuuksista" @@ -12171,10 +12134,6 @@ MSG_HASH( MSG_AUTODETECT, "Havaitse automaattisesti" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Tilan lataaminen kohteesta" - ) MSG_HASH( MSG_CAPABILITIES, "Ominaisuudet" @@ -13231,6 +13190,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Virtuaalisen levyaseman sulkeminen epäonnistui." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Tilan lataaminen kohteesta" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Tilatallennuksen automaattinen lataus kohteesta \"%s\" epäonnistui." @@ -14116,6 +14079,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_TIMEZONE, "Valitse aikavyöhyke, jotta voit määrittää sijaintisi päivämäärän ja ajan." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_TIMEZONE, + "Näyttää luettelon käytettävissä olevista aikavyöhykkeistä. Aikavyöhykkeen valitsemisen jälkeen aika ja päivämäärä on säädetään valittuun aikavyöhykkeeseen. Perusoletus on, että järjestelmän / laitteiston kello on asetettu UTC-aikaan." + ) #ifdef HAVE_LAKKA_SWITCH MSG_HASH( MENU_ENUM_LABEL_VALUE_LAKKA_SWITCH_OPTIONS, @@ -14344,3 +14311,10 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "pysäytetty." ) +#ifdef HAVE_GAME_AI + + + + + +#endif diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index 0e464c6a37..faaabb503c 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -67,6 +67,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Sélectionner le cœur à utiliser." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Décharger le cœur" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Relâche le cœur chargé." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Rechercher une implémentation de cœur libretro. Le dossier de démarrage du navigateur de fichiers dépend de votre dossier d'emplacement des cœurs. S'il n'est pas défini, il démarrera à la racine.\nSi l'emplacement des cœurs est un dossier, le menu l'utilisera comme dossier principal. Si le dossier d'emplacement des cœurs est un chemin complet, il démarrera dans le dossier où se trouve le fichier." @@ -906,6 +914,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Prise en charge de Video4Linux2 " ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Prise en charge de SSL " + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Prise en charge de Libusb " @@ -1108,7 +1120,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, - "Contrôles de base du menu" + "Touches de base du menu" ) /* Main Menu > Help > Basic Menu Controls */ @@ -1936,7 +1948,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Insérer une ou plusieurs images noires entre les images. Peut considérablement réduire le flou de mouvement en émulant le balayage CRT, mais au détriment de la luminosité. Ne pas combiner avec les options Intervalle d'échange > 1, sous-trames, Retard d'images ou Synchroniser à la fréquence d'affichage exacte du contenu." + "AVERTISSEMENT : Un scintillement rapide peut causer une persistance de l'image sur certains écrans. À utiliser à vos risques et périls // Insérer des images noires entre les images. Permet de réduire considérablement le flou de mouvement en émulant le balayage CRT, mais au détriment de la luminosité." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2020,7 +2032,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Insérer une ou plusieurs images noires entre les images. Permet aux shaders de créer des effets qui tournent à une fréquence d'image plus élevée que la vitesse réelle du contenu. Doit être réglé sur les Hz de l'écran actuel. Ne pas combiner avec Intervalle d'échange > 1, BFI, Retard d'image ou Synchroniser à la fréquence d'affichage exacte du contenu." + "AVERTISSEMENT : Un scintillement rapide peut causer une persistance de l'image sur certains écrans. À utiliser à vos risques et périls // Simule une ligne de balayage roulante basique au cours de plusieurs sous-images en divisant l'écran verticalement et en rendant chaque partie de l'écran en fonction du nombre de sous-images disponibles." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2096,7 +2108,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Simule une ligne de balayage roulante basique au cours de plusieurs sous-images en divisant l'écran verticalement et en rendant chaque partie de l'écran en fonction du nombre de sous-images disponibles." + "AVERTISSEMENT : Un scintillement rapide peut causer une persistance de l'image sur certains écrans. À utiliser à vos risques et périls // Simule une ligne de balayage roulante basique au cours de plusieurs sous-images en divisant l'écran verticalement et en rendant chaque partie de l'écran en fonction du nombre de sous-images disponibles." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2523,7 +2535,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Mettre à l'échelle la hauteur uniquement, ou la hauteur et la largeur. Les demi-étapes s'appliquent aux sources haute résolution." + "Mettre à l'échelle soit la hauteur ou la largeur, soit la hauteur et la largeur. Les demi-étapes s'appliquent uniquement aux sources haute résolution." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2625,11 +2637,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Biais de la fenêtre d'affichage personnalisé utilisé pour décaler la fenêtre d'affichage horizontalement (si plus large que la hauteur du contenu). 0.0 signifie tout à gauche et 1.0 signifie tout à droite." + "Position horizontale du contenu lorsque la fenêtre d'affichage est plus large que la largeur du contenu. 0,0 est à l'extrême gauche, 0,5 est au centre, 1,0 est à l'extrême droite." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Biais de la fenêtre d'affichage personnalisé utilisé pour décaler la fenêtre d'affichage verticalement (si plus grande que la hauteur du contenu). 0.0 signifie tout en haut et 1.0 signifie tout en bas." + "Position verticale du contenu lorsque la fenêtre d'affichage est plus haute que la hauteur du contenu. 0,0 est tout en haut, 0,5 est au centre, 1,0 est tout en bas." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2650,11 +2662,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Biais de la fenêtre d'affichage personnalisé utilisé pour décaler la fenêtre d'affichage horizontalement (si plus large que la hauteur du contenu). 0.0 signifie tout à gauche et 1.0 signifie tout à droite. (Orientation portrait)" + "Position horizontale du contenu lorsque la fenêtre d'affichage est plus large que la largeur du contenu. 0,0 est à l'extrême gauche, 0,5 est au centre, 1,0 est à l'extrême droite (orientation portrait)." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Biais de la fenêtre d'affichage personnalisé utilisé pour décaler la fenêtre d'affichage verticalement (si plus grande que la hauteur du contenu). 0.0 signifie tout en haut et 1.0 signifie tout en bas. (Orientation portrait)" + "Position verticale du contenu lorsque la fenêtre d'affichage est plus haute que la hauteur du contenu. 0,0 est tout en haut, 0,5 est au centre, 1,0 est tout en bas (orientation portrait)." ) #endif MSG_HASH( @@ -2890,7 +2902,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Couper le son lors de l'avance rapide" + "Couper le son pour l'avance rapide" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2898,12 +2910,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Accélération lors de l'avance rapide" + "Accélérer le son pour l'avance rapide" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Accélérer l'audio lors de l'avance rapide. Empêche les crépitents audio mais réhausse le pitch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Couper le son pour le rembobinage" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Coupe automatiquement le son lors du rembobinage." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Gain de volume (dB)" @@ -3437,22 +3457,35 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Maintenir" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Tir turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Désactivé arrête toutes les opérations de tir turbo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Délai d'activation du turbo " ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Durée (en images) après laquelle une touche en mode turbo est pressée." + "Durée en images après laquelle une touche en mode turbo est pressée." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, "Rapport cyclique du turbo " ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, "Le nombre d'images en mode turbo Turbo durant laquelle les touches sont maintenues enfoncées. Si ce nombre est égal ou supérieur au délai d'activation du turbo, les touches ne seront jamais relâchées." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Demi-période" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Mode turbo" @@ -3479,34 +3512,42 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Mode classique, fonctionnement à deux touches. Maintenez une touche enfoncée et pressez la touche Turbo pour activer la séquence de déclenchement.\nLa touche Turbo peut être assignée dans Réglages/Entrées/Touches du port 1." + "Mode classique, fonctionnement à deux touches. Maintenez une touche enfoncée et pressez la touche Turbo pour activer la séquence de déclenchement.\nL'affectation Turbo peut être assignée dans Réglages/Entrées/Touches du port X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Mode activer/désactiver classique, fonctionnement à deux touches. Maintenez une touche et appuyez sur la touche Turbo pour activer le turbo pour ce bouton. Pour désactiver le turbo : maintenez le bouton et appuyez à nouveau sur le bouton Turbo.\nLe bouton Turbo peut être assigné dans Réglages/Entrées/Port 1." + "Mode activer/désactiver classique, fonctionnement à deux touches. Maintenez une touche et appuyez sur la touche Turbo pour activer le turbo pour cette touche. Pour désactiver le turbo : maintenez la touche et appuyez à nouveau sur la touche Turbo.\nL'affectation Turbo peut être assignée dans Réglages/Entrées/Touches du port X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Mode activer/désactiver. Pressez une fois la touche Turbo pour activer la séquence de déclenchement pour la touche par défaut sélectionnée, une seconde fois pour la désactiver.\nLa touche Turbo peut être assignée dans Réglages/Entrées/Touches du port 1." + "Mode activer/désactiver. Pressez une fois la touche Turbo pour activer la séquence de déclenchement pour la touche par défaut sélectionnée, une seconde fois pour la désactiver.\nL'affectation Turbo peut être assignée dans Réglages/Entrées/Touches du port X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Mode maintenir. La séquence de déclenchement pour la touche par défaut sélectionnée est active tant que la touche Turbo est enfoncée.\nLa touche Turbo peut être assignée dans Réglages/Entrées/Touches du port 1.\nPour émuler la fonction tir automatique de l'ère des ordinateurs de famille, définissez les touches Turbo et les touches par défaut sur la même touche que celle du tir de la manette." + "Mode maintenir. La séquence de déclenchement pour la touche par défaut sélectionnée est active tant que la touche Turbo est enfoncée.\nL'affectation Turbo peut être assignée dans Réglages/Entrées/Touches du port X.\nPour émuler la fonction tir automatique de l'ère des ordinateurs de famille, définissez l'affectation et la touche sur la même touche que celle du tir de la manette." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Touche turbo par défaut" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Affectation turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Touche active par défaut pour le mode turbo 'Touche unique'." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "Affectation RetroManette activant le Turbo. Laisser vide utilise l'affectation spécifique au port." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Autoriser le turbo pour la croix directionnelle" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Touche Turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "Touche turbo cible en mode 'Touche unique'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Turbo autorise les directions de la croix directionnelle" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, "Si activé, les entrées numériques directionnelles (aussi connues sous le nom de croix ou 'pavé directionnel') peuvent être en mode turbo." ) MSG_HASH( @@ -3515,7 +3556,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Changez les paramètres de tir turbo.\nRemarque : la fonction turbo nécessite le mappage d'une touche turbo à votre périphérique d'entrée dans le menu 'Commandes du port X' correspondant." + "Modifier les réglages de tir turbo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3712,7 +3753,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Bascule l'affichage actuel entre le menu et l'exécution de contenu." + "Bascule l'affichage actuel entre le menu et le contenu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3792,7 +3833,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Met en pause/reprend le contenu en cours d'exécution." + "Met en pause/reprend le contenu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -4000,6 +4041,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Décrémente le numéro d'emplacement de replay sélectionné." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Tir Turbo (Activer/désactiver)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Active/désactive le tir turbo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Capture de la souris (activer/désactiver)" @@ -4761,7 +4810,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Créer automatiquement une sauvegarde instantanée à la fermeture de contenu. RetroArch chargera cette sauvegarde instantanée automatiquement si 'Chargement auto des sauvegardes instantanées' est activé." + "Faire automatiquement une sauvegarde instantanée lorsque le contenu est fermé. Cette sauvegarde instantanée est chargée au démarrage si l'option 'Chargement auto des sauvegardes instantanées' est activée." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -4884,7 +4933,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY_DEBUG, - "0 (debug)" + "0 (diagnostic)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY_INFO, @@ -4941,14 +4990,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtrer les fichiers affichés dans le navigateur de fichiers selon les extensions prises en charge." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Utiliser le lecteur média intégré" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrer par cœur actif" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtrer les fichiers affichés dans le navigateur de fichiers selon le cœur actuel." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Recharger le dernier dossier de démarrage utilisé" @@ -4957,6 +5006,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Ouvrir le navigateur de fichiers au dernier emplacement utilisé lors du chargement du contenu depuis le dossier de démarrage. Remarque : L'emplacement sera réinitialisé par défaut au redémarrage de RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Utiliser le lecteur média intégré" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Utiliser le lecteur d'images intégré" + ) /* Settings > Frame Throttle */ @@ -5761,6 +5818,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Notifications à la connexion de périphériques d'entrée (configuration automatique)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Notifications d'échec de périphériques d'entrée (configuration automatique)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Notifications de cheats" @@ -5781,6 +5842,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Afficher un message à l'écran lors de la connexion/déconnexion de périphériques d'entrées." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Afficher un message à l'écran lorsque des périphériques d'entrée n'ont pas pu être configurés." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Notifications au chargement de remappages des touches" @@ -5915,7 +5980,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Spécifier la taille de la police en points." + "Spécifie la taille de la police en points. Lorsque des widgets sont utilisés, cette taille n'a d'effet que sur l'affichage des statistiques à l'écran." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6072,7 +6137,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Mettre en pause le contenu en cours d'exécution si le menu est actif." + "Met en pause le contenu si le menu est actif." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6429,7 +6494,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Afficher les listes de lecture. (Redémarrage requis sur Ozone/XMB)" + "Afficher les listes de lecture dans le menu principal. Option ignorée dans GLUI si les onglets de liste de lecture et la barre de navigation sont activés." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Afficher les onglets de liste de lecture" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Afficher les onglets de liste de lecture. Cela n'affecte pas RGUI. La barre de navigation doit être activée dans GLUI. (Redémarrage requis pour Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6909,14 +6982,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Afficher 'Utilisateur'" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Icônes dans la liste de lecture" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Type de miniature pour l'icône dans la liste de lecture à afficher." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Afficher les réglages pour 'Utilisateur'." @@ -7130,7 +7195,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, - "Désactive les cheats, le rembobinage, le ralenti et le chargement des sauvegardes instantanées. Les succès gagnés en mode hardcore sont marquées de façon unique pour que vous puissiez montrer aux autres ce que vous avez accompli sans fonctionnalités d'assistance d'émulateur. La désactivation de ce paramètre lors de l'exécution redémarrera le jeu." + "Désactive les cheats, le rembobinage, le ralenti et le chargement des sauvegardes instantanées. Les succès gagnés en mode Hardcore sont marquées de façon unique pour que vous puissiez montrer aux autres ce que vous avez accompli sans fonctionnalités d'assistance d'émulateur. La désactivation de ce paramètre lors de l'exécution redémarrera le jeu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, @@ -8136,7 +8201,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Navigateur de fichiers " + "Dossier de démarrage" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8381,7 +8446,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Décidez quelles informations relatives au contenu en cours d'exécution seront partagées." + "Décidez quelles informations relatives au contenu seront partagées." ) MSG_HASH( @@ -8977,7 +9042,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Reprendre le contenu en cours et quitter le menu rapide." + "Reprendre le contenu et quitter le menu rapide." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -8993,7 +9058,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Fermer le contenu actuel. Toute modification non enregistrée pourrait être perdue." + "Fermer le contenu. Toute modification non enregistrée pourrait être perdue." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9129,7 +9194,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Modifier les options pour le contenu en cours d'exécution." + "Modifier les options pour le contenu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9137,7 +9202,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Modifier les contrôles pour le contenu en cours d'exécution." + "Modifier les touches pour le contenu." ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, @@ -9227,11 +9292,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Réinitialiser les options" + "Réinitialiser les options du cœur" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Définir toutes les options du cœur aux valeurs par défaut." + "Définit toutes les options du cœur actuel aux valeurs par défaut." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9743,7 +9808,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Verifie les changements dans les fichiers de shaders. Après avoir enregistré les modifications à un shader sur le disque, il sera automatiquement recompilé et appliqué au contenu en cours d'exécution." + "Verifie les changements dans les fichiers de shaders. Après avoir enregistré les modifications à un shader sur le disque, il sera automatiquement recompilé et appliqué au contenu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10204,6 +10269,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Faire défiler les miniatures" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Sélection aléatoire" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Retour" @@ -10952,7 +11021,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Activer l'affichage en arrière-plan du contenu en cours d'exécution lorsque le Menu rapide est actif. Désactiver la transparence peut modifier les couleurs du thème." + "Activer l'affichage en arrière-plan du contenu lorsque le Menu rapide est actif. Désactiver la transparence peut modifier les couleurs du thème." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11284,6 +11353,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Type de miniatures à afficher à gauche." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Miniature icône" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Type de miniature pour l'icône dans la liste de lecture à afficher." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Arrière-plan dynamique" @@ -11567,6 +11644,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Glacial" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Gris foncé" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Gris clair" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11594,6 +11679,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Les listes de lecture seront re-triées par ordre alphabétique après avoir supprimé le composant fabricant de leurs noms." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Miniature secondaire" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Remplace le panneau des métadonnées du contenu par une autre miniature." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Utiliser le défilement de texte pour les métadonnées du contenu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Si activée, cette option affichera chaque élément de métadonnées du contenu sur la barre latérale droite des listes de lectures (cœur associé, temps de jeu) sur une seule ligne; défilant si le texte est trop long pour la barre latérale. Si désactivée, chaque élément de métadonnées sera affiché statiquement, allant à la ligne si besoin." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Facteur de mise à l'échelle des miniatures " + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Mettre à l'échelle la taille de la barre des miniatures." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Thème de couleurs" @@ -11626,10 +11736,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_TWILIGHT_ZONE, "Quatrième dimension (Twilight Zone)" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, - "Sélénium" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, "Solarisé sombre" @@ -11651,30 +11757,11 @@ MSG_HASH( "Purple rain" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Miniature secondaire" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Remplace le panneau des métadonnées du contenu par une autre miniature." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Utiliser le défilement de texte pour les métadonnées du contenu" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Si activée, cette option affichera chaque élément de métadonnées du contenu sur la barre latérale droite des listes de lectures (cœur associé, temps de jeu) sur une seule ligne; défilant si le texte est trop long pour la barre latérale. Si désactivée, chaque élément de métadonnées sera affiché statiquement, allant à la ligne si besoin." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Facteur de mise à l'échelle des miniatures " - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Mettre à l'échelle la taille de la barre des miniatures." + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "Sélénium" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -12618,10 +12705,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Clavier" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Utiliser le lecteur d'images intégré" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Nombre d'images max en mémoire tampon " @@ -12757,14 +12840,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Sélectionner depuis une liste de lecture" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Reprendre" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Reprendre le contenu en cours et quitter le menu rapide." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Voir la liste des %u correspondances" @@ -13355,10 +13430,6 @@ MSG_HASH( MSG_AUTODETECT, "Détection automatique" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Chargement auto d'une sauvegarde instantanée depuis" - ) MSG_HASH( MSG_CAPABILITIES, "Capacités" @@ -14443,6 +14514,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Impossible de fermer le plateau du lecteur de disque virtuel." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Chargement auto d'une sauvegarde instantanée depuis" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Le chargement d'une sauvegarde automatique depuis \"%s\" a échoué." @@ -14751,6 +14826,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Un cheat a été activé. Succès en mode Hardcore désactivés pour la session en cours." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Le mode Hardcore des succès a été modifié par l'hôte." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "L'hôte du jeu en réseau doit être mis à jour. Succès en mode Hardcore désactivés pour la session en cours." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Maîtrisé %s" @@ -15748,3 +15831,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "arrêté." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "Remplacement du joueur IA" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "Sous-label remplacement du joueur IA" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "IA du jeu" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Remplacer j1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Remplace le joueur 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Remplacer j2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Remplace le joueur 02" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Afficher le diagnostic" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Afficher le diagnostic" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Afficher 'IA du jeu'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Afficher l'option 'IA du jeu'." + ) +#endif diff --git a/intl/msg_hash_gl.h b/intl/msg_hash_gl.h index 7667b654e3..e71745d6a5 100644 --- a/intl/msg_hash_gl.h +++ b/intl/msg_hash_gl.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Escolla o núcleo a empregar." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Descargar o núcleo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Liberar o núcleo cargado." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Navega por unha implementación do núcleo libretro. O lugar onde comeza o navegador depende da túa ruta do Directorio de Núcleos.\nlf Se está en branco, comezará na raíz. Se o Directorio de Núcleos é un directorio, o menú usará ese como carpeta principal. Se o Directorio de Núcleos é unha ruta completa, comezará na carpeta onde está o arquivo." @@ -914,6 +922,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Compatibilidade con Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Soporte SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Compatibilidade con libusb" @@ -1286,7 +1298,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DRIVER, - "Backend de sincronización na nube" + "Infraestrutura (backend) de sincronización na nube" ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOUD_SYNC_DRIVER, @@ -1566,7 +1578,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_INPUT_DRIVER_LINUXRAW, - "O controlador de entrada de linuxraw require un TTY activo. Os eventos do teclado lense directamente desde o TTY, o que o fai máis sinxelo, pero non tan flexible como udev. Non se admiten ratos, etc. Este controlador usa a API de joystick máis antiga (/dev/input/js*)." + "O controlador de entrada de linuxraw require un TTY activo. Os eventos do teclado lense directamente desde o TTY, o que o fai máis sinxelo, pero non tan flexible como udev. Non se admiten ratos, etc. Este controlador usa a API de Panca de mando máis antiga (/dev/input/js*)." ) MSG_HASH( MENU_ENUM_LABEL_HELP_INPUT_DRIVER_NO_DETAILS, @@ -1574,15 +1586,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, - "Telemando de xogo" + "Mando" ) MSG_HASH( MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, - "Controlador para usar. (O reinicio é necesario)" + "Controlador de mando a utilizar. (Reinicio necesario)" ) MSG_HASH( MENU_ENUM_LABEL_HELP_JOYPAD_DRIVER_DINPUT, - "Controlador de driver DirectInput." + "Controlador de mando DirectInput." ) MSG_HASH( MENU_ENUM_LABEL_HELP_JOYPAD_DRIVER_HID, @@ -1590,23 +1602,23 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_JOYPAD_DRIVER_LINUXRAW, - "Controlador Raw Linux, usa a API de joystick heredada. Use udev no seu lugar se é posible." + "Controlador Raw Linux, usa a API de panca de mando herdada. Use udev no seu lugar se é posible." ) MSG_HASH( MENU_ENUM_LABEL_HELP_JOYPAD_DRIVER_PARPORT, - "Controlador de Linux para controladores conectados ao porto paralelo mediante adaptadores especiais." + "Controlador de Linux para mandos conectados ao porto paralelo mediante adaptadores especiais." ) MSG_HASH( MENU_ENUM_LABEL_HELP_JOYPAD_DRIVER_SDL, - "Controlador de controlador baseado en bibliotecas SDL." + "Controlador de mando baseado en bibliotecas SDL." ) MSG_HASH( MENU_ENUM_LABEL_HELP_JOYPAD_DRIVER_UDEV, - "Controlador de controlador con interface udev, xeralmente recomendado. Usa a recente API de joypad evdev para compatibilidade con joystick. Admite conexión en quente e feedback forzado.\nPor defecto na maioría das distribucións, os nodos /dev/input son só root (modo 600). Podes configurar unha regra udev que faga accesibles para non root." + "Controlador de mando con interface udev, xeralmente recomendado. Usa a recente API do mando de xogo evdev para compatibilidade con panca de mando. Admite conexión en quente e feedback forzado.\nPor defecto na maioría das distribucións, os nodos /dev/input son só root (modo 600). Podes configurar unha regra udev que faga accesibles para non root." ) MSG_HASH( MENU_ENUM_LABEL_HELP_JOYPAD_DRIVER_XINPUT, - "Controlador de controlador XInput. Principalmente para controladores Xbox." + "Controlador de mando XInput. Principalmente para mandos Xbox." ) MSG_HASH( @@ -1952,7 +1964,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Insira cadro(s) negros entre cadros. Pode reducir moito o desenfoque de movemento emulando a exploración CRT, pero a costa do brillo. Non combine con Intervalo de intercambio > 1, sub-fotogramas, Retraso de fotogramas ou Sincronizar a velocidade de fotogramas de contido exacto." + "ADVERTENCIA: O destello rápido pode causar retención de imaxe en algunhas pantallas. Usa esta opción baixo a túa responsabilidade // Insire fotograma(s) en negro no medio dos fotogramas. Pode reducir notablemente o desenfoque de movemento emulando o funcionamento dunha pantalla de tubo á costa de perder brillo." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2036,7 +2048,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Insira marco(s) de sombreado extra entre cadros. Permite aos sombreadores facer efectos que se executan a un fps superior á taxa de contido real. Debe configurarse na pantalla actual Hz. Non combines con Intervalo de intercambio > 1, BFI, Retraso de fotogramas ou Sincronizar a velocidade de fotogramas de contido exacto." + "ADVERTENCIA: O destello rápido pode causar retención de imaxe en algunhas pantallas. Usa esta opción baixo a túa responsabilidade // Simula unha liña de exploración básica ó longo de varios subfotogramas dividindo a pantalla verticalmente e renderizando cada parte da pantalla segundo o número de subfotogramas." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2112,7 +2124,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Simula unha liña de escaneo en rotación básica sobre varios subfotogramas dividindo a pantalla verticalmente e representando cada parte da pantalla segundo cantos subfotogramas haxa." + "ADVERTENCIA: O destello rápido pode causar retención de imaxe en algunhas pantallas. Usa esta opción baixo a túa responsabilidade // Simula unha liña de exploración básica ó longo de varios subfotogramas dividindo a pantalla verticalmente e renderizando cada parte da pantalla segundo o número de subfotogramas." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2527,7 +2539,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Escalar só a altura, ou tanto a altura como o ancho. Os pasos medios aplícanse a fontes de alta resolución." + "Cambia a escala da altura, ancho ou ambas. As fraccións aplícanse só ás fontes de alta resolución." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2625,11 +2637,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Desviación personalizada do porto de vista usada para compensar o porto de vista horizontalmente (se for máis ancho que a altura do contido). 0.0 significa moi á esquerda e 1.0 significa moi á dereita." + "Posición horizontal do contido cando a xanela é máis ancha ca o contido. 0.0 é totalmente á esquerda, 0.5 é o centro, 1.0 é totalmente á dereita." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Desviación personalizada do porto de vista usada para compensar o porto de vista verticalmente (se for máis alto que a altura do contido). 0.0 significa arriba e 1.0 significa abaixo." + "Posición vertical do contido cando a xanela é máis alta ca o contido. 0.0 é arriba de todo, 0.5 é o centro, 1.0 é abaixo de todo." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2650,11 +2662,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Desviación personalizada do porto de vista usada para desprazar o porto de vista horizontalmente (se for máis ancho que a altura do contido). 0.0 significa á esquerda e 1.0 significa á dereita. (Orientación en retrato)" + "Posición horizontal do contido cando a xanela é máis ancha ca o contido (orientación vertical). 0.0 é totalmente á esquerda, 0.5 é o centro, 1.0 é totalmente á dereita" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Desviación personalizada do porto de vista usada para compensar o porto de vista verticalmente (se for máis alto que a altura do contido). 0.0 significa arriba e 1.0 significa abaixo. (Orientación en retrato)" + "Posición vertical do contido cando a xanela é máis alta ca o contido (orientación vertical). 0.0 é arriba de todo, 0.5 é o centro, 1.0 é abaixo de todo" ) #endif MSG_HASH( @@ -2894,7 +2906,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Acalar ao avanzar rápido" + "Acalar o son ao avanzar rápido" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2902,12 +2914,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Acelerar ao avanzar rápido" + "Acelerar o son ao avanzar rápido" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Acelera o audio ao avanzar rápido. Evita crepitar pero cambia de ton." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Acalar o son ao rebobinar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Acalar automaticamente o son ao rebobinar." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Ganancia de volume (dB)" @@ -3223,6 +3243,26 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, "Axusta o volume do fluxo de audio." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_NONE, + "Estado: N/D" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_STOPPED, + "Estado: Detido" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING, + "Estado: Reproducindo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_LOOPED, + "Estado: Reproducindo (en bucle)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL, + "Estado: Reproducindo (en secuencia)" + ) /* Settings > Audio > Menu Sounds */ @@ -3417,21 +3457,34 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Manter" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo fogo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Desactivado detén todas as operacións de disparo turbo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Período Turbo" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "O período (en fotogramas) no que se preme os botóns activados para turbo." + "O período en fotogramas no que se premen os botóns con turbo activado." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, "Ciclo de traballo turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "O número de fotogramas do período Turbo durante os que se manteñen pulsados os botóns. Se este número é igual ou superior ao período turbo, os botóns nunca se soltarán." + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, + "O número de fotogramas nos que os botóns se manteñen pulsados durante o período turbo. Se este número é igual ou maior que o período Turbo, os botóns nunca se soltarán." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Medio período" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, @@ -3459,35 +3512,43 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Modo clásico, operación con dous botóns. Mantén premido un botón e toca o botón Turbo para activar a secuencia do comunicado de prensa.\nO botón Turbo pódese asignar en Configuración/Entrada/Controis do porto 1." + "Modo clásico, operación de dous botóns. Mantén un botón e preme o botón Turbo para activar a secuencia de presión-liberación.\nA asignación do Turbo pode facerse en Configuración/Entrada/Controis do Porto X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Modo de alternancia clásico, operación con dous botóns. Mantén premido un botón e toca o botón Turbo para activar o turbo para ese botón. Para desactivar o turbo: manteña premido o botón e preme de novo o botón Turbo.\nO botón Turbo pódese asignar en Configuración/Entrada/Controis do porto 1." + "Modo clásico de alternancia, operación de dous botóns. Mantén un botón e preme o botón Turbo para activar o turbo para ese botón. Para desactivar o turbo: mantén o botón e preme o botón Turbo de novo.\nA asignación do Turbo pode facerse en Configuración/Entrada/Controis do Porto X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Alternar modo. Preme o botón Turbo unha vez para activar a secuencia de lanzamento de prensa para o botón predeterminado seleccionado, preme de novo para desactivalo.\nO botón Turbo pódese asignar en Configuración/Entrada/Controis do porto 1." + "Modo de alternancia. Preme o botón Turbo unha vez para activar a secuencia de presión-liberación para o botón predeterminado escollido, e preme de novo para desactivalo.\nA asignación do Turbo pode facerse en Configuración/Entrada/Controis do Porto X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Modo de espera. A secuencia de lanzamento de prensa para o botón predeterminado seleccionado está activa mentres se manteña premido o botón Turbo.\nO botón Turbo pódese asignar en Configuración/Entrada/Controis do porto 1.\nPara emular a función de disparo automático da era do ordenador doméstico, configura Turbo e os botóns predeterminados deben ser os mesmos que o botón de disparo do joystick." + "Modo de mantemento. A secuencia de presión-liberación para o botón predeterminado escollido está activa mentres o botón Turbo se manteña premido.\nA asignación do Turbo pode facerse en Configuración/Entrada/Controis do Porto X.\nPara emular a función de disparo automático da era dos microordenadores, asigna o mesmo botón de disparo da Panca de mando á función Bind e ao botón." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Botón Turbo predeterminado" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Asignación Turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Botón activo predeterminado para o modo Turbo \"Botón único\"." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "Turbo activando a asignación do RetroPad. Se está baleiro, utilízase a asignación específica do porto." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Permitir indicacións do Turbo D-Pad" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Botón Turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "Se está activada, as entradas direccionais dixitais (tamén coñecidas como d-pad ou 'hatswitch') poden ser turbo." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "Botón turbo de destino no modo 'Botón Único'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Permitir direccións do D-Pad no Turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, + "Se está activado, as entradas direccionais dixitais (tamén coñecidas como D-Pad ou 'hatswitch') poden usar o turbo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -3495,7 +3556,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Cambia a configuración do turbo fogo.\nNota: a función turbo require asignar un botón turbo ao teu dispositivo de entrada no menú \"Controis do porto X\" correspondente." + "Trocar configuracións de disparo turbo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3692,7 +3753,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Cambia a visualización actual entre menú e contido en execución." + "Troca a pantalla actual entre o menú e o contido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3772,7 +3833,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Cambia o contido en execución entre estados en pausa e non pausa." + "Troca o contido entre os estados de pausado e non pausado." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -3980,6 +4041,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Reduce o índice da ranura de reprodución seleccionado actualmente." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Disparo Turbo (Alternancia)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Activa/desactiva o disparo turbo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Colle o rato (alternar)" @@ -4245,19 +4314,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, - "D-Pad arriba" + "Cruceta Arriba" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, - "D-Pad abaixo" + "Cruceta abaixo" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, - "D-Pad esquerda" + "Cruceta esquerda" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, - "D-Pad dereita" + "Cruceta dereita" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, @@ -4497,7 +4566,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Especifica se ignorar as capacidades de estado de salvamento da información básica, o que permite probar con funcións relacionadas (adiante, rebobinar, etc.)." + "Especifica se ignorar a información do núcleo respecto as capacidades de salvar estados, o que permite experimentar con funcionalidades relacionadas (adiantar execución, rebobinar, etc.)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4741,7 +4810,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Fai automaticamente un estado de gardado cando o contido estea pechado. RetroArch cargará automaticamente este estado de gardado se \"Cargar estado automaticamente\" está activado." + "Gardar o estado automaticamente cando se pecha o contido. Este estado gardado se carga no arranque se \"Auto Cargar Estado\" está activado." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -4913,14 +4982,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtra os ficheiros que se mostran no Explorador de ficheiros polas extensións compatibles." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usa o reprodutor multimedia integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrar por núcleo actual" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtrar os arquivos que se mostran no Navegador de Arquivos polo núcleo actual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Lembra o último directorio de inicio usado" @@ -4929,6 +4998,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Abre o explorador de ficheiros na última localización utilizada ao cargar contido do directorio de inicio. Nota: a localización restablecerase ao valor predeterminado ao reiniciar RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Usa o reprodutor multimedia integrado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Use o visor de imaxes integrado" + ) /* Settings > Frame Throttle */ @@ -5286,6 +5363,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "Axusta o tamaño das zonas de superposición no rombo do botón da cara. Establécese ao 100 % para a simetría de 8 vías." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Zona de recentralización analóxica" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "A entrada do stick analóxico será relativa ao primeiro toque cando se prema dentro desta zona." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Superposición" @@ -5721,6 +5806,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Notificacións de conexión de entrada (configuración automática)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Notificacións de falla de entrada (Autoconfiguración)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Notificacións de códigos de trucos" @@ -5741,6 +5830,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Mostra unha mensaxe en pantalla ao conectar/desconectar dispositivos de entrada." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Amosar unha mensaxe na pantalla cando os dispositivos de entrada non poidan ser configurados." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Introducir notificacións cargadas de reasignación" @@ -5863,7 +5956,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Especifique o tamaño da fonte en puntos." + "Especifica o tamaño da fonte en puntos. Cando se usan widgets, este tamaño afecta só á visualización de estatísticas na pantalla." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6016,7 +6109,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Pausa o contido en execución se o menú está activo." + "Pausar o contido se o menú está activo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6353,7 +6446,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Mostra as listas de reprodución. (Requírese reiniciar en Ozone/XMB)" + "Amosar as listas de reprodución no Menú Principal. Ignorado en GLUI se as lapelas de listas de reprodución e a barra de navegación están activadas." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Amosar lapelas de listas de reprodución" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Amosar as lapelas de listas de reprodución. Non afecta a RGUI. A barra de navegación debe estar activada en GLUI. (Requírese reiniciar en Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6825,14 +6926,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Mostrar \"Usuario\"" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Iconas de listas de reprodución" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Tipo de miniatura da icona da lista de reprodución a amosar." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Mostrar a configuración de \"Usuario\"." @@ -7789,7 +7882,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "A exploración verifica CRC sobre posibles duplicados" + "Escanear verifica CRC en posibles duplicados" ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, @@ -8048,7 +8141,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Explorador de ficheiros" + "Directorio inicial" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8168,11 +8261,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, - "Perfís de controlador" + "Perfís de mando" ) MSG_HASH( MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, - "Neste directorio gárdanse os perfís de controladores utilizados para configurar automaticamente os controladores." + "Os perfís de mando utilizados para configurar automaticamente os mandos están almacenados nesta carpeta." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, @@ -8293,7 +8386,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Decida que información relacionada co contido en execución se compartirá." + "Decidir que información relacionada co contido se compartirá." ) MSG_HASH( @@ -8893,7 +8986,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Retoma o contido en execución e sae do menú rápido." + "Reanudar o contido e saír do Menú Rápido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -8909,7 +9002,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Pecha o contido actual. É posible que se perdan os cambios non gardados." + "Pechar o contido. Calquera troco non gardado poderá ser perdido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9045,7 +9138,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Cambia as opcións do contido en execución." + "Trocar as opcións para o contido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9053,7 +9146,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Cambia os controis do contido en execución." + "Trocar os controis para o contido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9151,11 +9244,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Opcións de restablecemento" + "Restaurar opcións do núcleo" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Establece todas as opcións básicas cos valores predeterminados." + "Restablece todas as opcións do núcleo actual aos valores predeterminados." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9675,7 +9768,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Observa os ficheiros do sombreador para ver novos cambios. Despois de gardar os cambios nun sombreador no disco, recompilarase automaticamente e aplicarase ao contido en execución." + "Vixiar os arquivos de sombreadores para novos trocos. Despois de gardar os trocos nun sombreado no disco, este será recompilado e aplicado automaticamente ao contido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10136,6 +10229,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Ciclo de miniaturas" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Escolla aleatoria" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Volver" @@ -10816,7 +10913,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Activa a visualización en segundo plano do contido en execución mentres o menú rápido está activo. A desactivación da transparencia pode alterar as cores do tema." + "Activar a visualización de fondo do contido mentres o Menú Rápido está activo. Desactivar a transparencia pode alterar as cores do tema." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11124,6 +11221,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Tipo de miniatura para mostrar á esquerda." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Miniatura da icona" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Tipo de miniatura da icona de lista de reprodución a mostrar." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Fondo dinámico" @@ -11423,6 +11528,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Xeo frío" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Gris Escuro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Gris Claro" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11450,6 +11563,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "As listas de reprodución volveranse ordenar por orde alfabética despois de eliminar o compoñente do fabricante dos seus nomes." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Miniatura secundaria" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Substitúe o panel de metadatos do contido por outra miniatura." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Usa o texto do ticker para os metadatos do contido" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Cando está activado, cada elemento de metadatos de contido que se mostra na barra lateral dereita das listas de reprodución (núcleo asociado, tempo de reprodución) ocupará unha única liña; as cadeas que superen o ancho da barra lateral mostraranse como texto de desprazamento. Cando estea desactivado, cada elemento de metadatos de contido mostrarase de forma estática, envolto para ocupar tantas liñas como sexa necesario." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Factor de escala de miniaturas" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Escala o tamaño da barra de miniaturas." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Cor do tema" @@ -11502,30 +11640,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_PURPLE_RAIN, "Choiva Morada" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Miniatura secundaria" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Substitúe o panel de metadatos do contido por outra miniatura." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Usa o texto do ticker para os metadatos do contido" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Cando está activado, cada elemento de metadatos de contido que se mostra na barra lateral dereita das listas de reprodución (núcleo asociado, tempo de reprodución) ocupará unha única liña; as cadeas que superen o ancho da barra lateral mostraranse como texto de desprazamento. Cando estea desactivado, cada elemento de metadatos de contido mostrarase de forma estática, envolto para ocupar tantas liñas como sexa necesario." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Factor de escala de miniaturas" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Escala o tamaño da barra de miniaturas." - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -12486,10 +12601,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Usuario" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Use o visor de imaxes integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Max Swapchain Imaxes" @@ -12625,14 +12736,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Selecciona dunha lista de reprodución" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Retomar" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Retoma o contido en execución e sae do menú rápido." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Ver a lista de %u coincidencias" @@ -13231,10 +13334,6 @@ MSG_HASH( MSG_AUTODETECT, "Detección automática" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Cargando automaticamente o estado de gardar desde" - ) MSG_HASH( MSG_CAPABILITIES, "Capacidades" @@ -14311,6 +14410,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Produciuse un erro ao pechar a bandexa do disco virtual." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Cargando automaticamente o estado de gardar desde" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Fallou a carga automática do estado de gardado de \"%s\"." @@ -14619,6 +14722,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Activouse un truco. Logros Modo Hardcore desactivado para a sesión actual." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Modo Hardcore dos logros cambiado polo host." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "O host do Xogo en Rede tense que actualizar. Modo Hardcore dos logros desactivado para esta sesión." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Dominou %s" @@ -15531,7 +15642,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Mostra a fonte do menú inferior. Activar para mostrar as descricións dos botóns na pantalla inferior. Isto exclúe a data do estado de salvación." + "Mostrar a fonte do menú inferior. Cando se activa mostra descricións dos botóns na parte inferior da pantalla. Isto exclúe a data do estado gardado." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, @@ -15596,3 +15707,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "parou." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "Substitución do xogador IA" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "O xogador de IA anula la subetiqueta" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "IA do Xogo" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Substituír p1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Substituír xogador p1" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Substituír p2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Substituír xogador p2" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Amosar depuración" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Amosar depuración" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Amosar \"Xogo IA\"" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Amosar a opción 'IA do xogo'." + ) +#endif diff --git a/intl/msg_hash_he.h b/intl/msg_hash_he.h index ebf011b6cf..271d246771 100644 --- a/intl/msg_hash_he.h +++ b/intl/msg_hash_he.h @@ -1325,6 +1325,11 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "החזק" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "ירי טורבו" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "תקופת טורבו" @@ -1576,7 +1581,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "סייר קבצים" + "תיקיית ההתחלה" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, @@ -1735,6 +1740,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -1887,4 +1894,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_hr.h b/intl/msg_hash_hr.h index b1bb6e775f..b5fc267ee3 100644 --- a/intl/msg_hash_hr.h +++ b/intl/msg_hash_hr.h @@ -1062,6 +1062,7 @@ MSG_HASH( "ISKLJUČENO" ) + /* Settings > Input > Haptic Feedback/Vibration */ @@ -1268,7 +1269,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Preglednik datoteka" + "Početna mapa" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, @@ -1491,6 +1492,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -1635,4 +1638,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_hu.h b/intl/msg_hash_hu.h index e814a6798f..1394c7ffec 100644 --- a/intl/msg_hash_hu.h +++ b/intl/msg_hash_hu.h @@ -67,6 +67,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "A használni kívánt mag." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Mag bezárása" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "A betöltött mag eltávolítása a memóriából." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Libretro magok tallózása. A böngésző a magok könyvtárából indul, ha az üres, akkor a gyökérkönyvtárból. Ha a magok könyvtára egy könyvtár, akkor a menüben ennél feljebb nem lehet lépni. Ha a magok könyvtára egy fájlra mutat, a menü az ezt tartalmazó könyvtárban indul." @@ -706,6 +714,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "SDL 2 támogatás" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Direct3D 8 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Direct3D 9 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Direct3D 10 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Direct3D 11 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Direct3D 12 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "GDI támogatás" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Vulkan támogatás" @@ -786,6 +818,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "PulseAudio támogatás" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "PipeWire támogatás" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "CoreAudio támogatás" @@ -866,6 +902,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 támogatás" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL támogatás" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb támogatás" @@ -1721,6 +1761,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PULSE, "PulseAudio illesztő. Ha a rendszer PulseAudio-t használ, mindenképpen ez az illesztő ajánlott pl. az ALSA helyett." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PIPEWIRE, + "PipeWire illesztő. Ha a rendszer PipeWire-t használ, mindenképpen ez az illesztő ajánlott pl. a PulseAudio helyett." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_JACK, "Jack Audio Connection Kit illesztő." @@ -1912,7 +1956,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Egy vagy több fekete képkocka beszúrása a képkockák közé. A mozgási elmosódást nagymértékben csökkentheti a CRT hatás emulálásával, a fényerő kárára. Nem kombinálható az 1-nél nagyobb váltóperiódussal, az alképkockákkal, képvárakoztatással, vagy a tartalom pontos képfrissítéséhez igazítással." + "FIGYELEM: a gyors villódzás bizonyos kijelzőkön képvisszatartást okozhat. Csak saját felelősségre. // Fekete képkockák beszúrása a képkockák közé. A mozgásból adódó elmosódást a CRT-szerű megjelenítéssel nagyban csökkenti, de a fényesség rovására." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -1996,7 +2040,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "További képkockák előállítása a shaderek számára a képkockák közt, így a shaderek a tartalomnál magasabb frissítésű effekteket is használhatnak. Ajánlott a képernyő frissítési frekvenciájára állítani. Nem kombinálható az 1-nél nagyobb váltóperiódussal, a fekete képkocka beszúrással, a képvárakoztatással, vagy a tartalom pontos képfrissítéséhez igazodással." + "FIGYELEM: a gyors villódzás bizonyos kijelzőkön képvisszatartást okozhat. Csak saját felelősségre. // Egyszerű gördülő elektronsugár szimuláció több alképkockán keresztül, a képernyőt az alképkockák számának megfelelően függőlegesen felosztva és részlegesen megjelenítve." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2072,7 +2116,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Egyszerű gördülő elektronsugár szimuláció több alképkockán keresztül, a képernyőt az alképkockák számának megfelelően függőlegesen felosztva és részlegesen megjelenítve." + "FIGYELEM: a gyors villódzás bizonyos kijelzőkön képvisszatartást okozhat. Csak saját felelősségre. // Egyszerű gördülő elektronsugár szimuláció több alképkockán keresztül, a képernyőt az alképkockák számának megfelelően függőlegesen felosztva és részlegesen megjelenítve." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2499,7 +2543,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Méretezés csak a magasság, vagy a magasság és szélesség szerint. A fél lépések a nagyfelbontású forrásokra vonatkoznak." + "Méretezés a magasság, a szélesség, vagy mindkettő szerint. A fél lépések csak a nagyfelbontású forrásokra vonatkoznak." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2601,11 +2645,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Az egyedi nézőablak vízszintes középrehelyezése, ha a nézőablak szélesebb, mint a tartalom. 0.0 esetén teljesen balra, 1.0 esetén teljesen jobbra igazodik." + "A tartalom vízszintes helyzete, amikor a nézőablak szélesebb annál. 0.0 a balra igazítás, 0.5 a középre helyezés, 1.0 a jobbra igazítás." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Az egyedi nézőablak függőleges középrehelyezése, ha a nézőablak magasabb, mint a tartalom. 0.0 esetén teljesen fentre, 1.0 esetén teljesen lentre igazodik." + "A tartalom függőleges helyzete, amikor a nézőablak magasabb annál. 0.0 a fentre igazítás, 0.5 a középre helyezés, 1.0 a lentre igazítás." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2626,11 +2670,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Az egyedi nézőablak vízszintes középrehelyezése, ha a nézőablak szélesebb, mint a tartalom. 0.0 esetén teljesen balra, 1.0 esetén teljesen jobbra igazodik. (Álló nézet esetén.)" + "A tartalom vízszintes helyzete, amikor a nézőablak szélesebb annál. 0.0 a balra igazítás, 0.5 a középre helyezés, 1.0 a jobbra igazítás. (Álló nézetben)" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Az egyedi nézőablak függőleges középrehelyezése, ha a nézőablak magasabb, mint a tartalom. 0.0 esetén teljesen fentre, 1.0 esetén teljesen lentre igazodik. (Álló nézet esetén.)" + "A tartalom függőleges helyzete, amikor a nézőablak magasabb annál. 0.0 a fentre igazítás, 0.5 a középre helyezés, 1.0 a lentre igazítás. (Álló nézetben)" ) #endif MSG_HASH( @@ -2878,7 +2922,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Hang kikapcsolása gyorsításkor" + "Hang némítása gyorsításkor" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2892,6 +2936,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "A hang gyorsított lejátszása gyorsításkor. Megakadályozza a recsegést, de megemeli a hangmagasságot." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Hang némítása visszatekeréskor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "A hang automatikus elnémítása visszatekerés közben." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Hangerő (dB)" @@ -2995,6 +3047,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, "Hangkésleltetés (ms)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_LATENCY, + "A legnagyobb hangkésleltetés ezredmásodpercben. Az illesztő a tényleges késleltetést ezen érték 50%-a körül próbálja tartani. Ha a hangillesztő nem tudja a kívánt késleltetést biztosítani, az érték eltérhet." + ) #ifdef HAVE_MICROPHONE /* Settings > Audio > Input */ @@ -3211,6 +3267,26 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, "A hangfolyam hangereje." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_NONE, + "Állapot: nincs adat" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_STOPPED, + "Leállítva" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING, + "Lejátszás alatt" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_LOOPED, + "Lejátszás alatt (ismétlés)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL, + "Lejátszás alatt (lépés a következőre)" + ) /* Settings > Audio > Menu Sounds */ @@ -3413,6 +3489,15 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Tartás" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbó mód" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Kikapcsolva minden turbó funkció leáll." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbó periódus" @@ -3422,13 +3507,17 @@ MSG_HASH( "Turbó gomb lenyomásakor ez lesz az ismétlés gyakorisága (képkockában)." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, "Turbó kitöltési tényező" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, "A turbó periódusból ennyi képkockáig lesznek lenyomva a gombok. Ha ugyanannyi vagy nagyobb, mint a Turbó periódus, a gomb sosem lesz felengedve." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Fél periódus" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Turbó mód" @@ -3455,35 +3544,43 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Klasszikus mód, kétgombos működés. Egy gombot nyomva tartva és a Turbo gombot megnyomva aktiválódik a megnyomás-elengedés szekvencia.\nA Turbo gomb a Beállítások / Bemenet / 1. csatlakozó beállításai alatt adható meg." + "Klasszikus mód, kétgombos működés. Egy gombot nyomva tartva és a Turbo gombot megnyomva aktiválódik a megnyomás-elengedés szekvencia.\nA Turbo gomb a Beállítások / Bemenet / X. csatlakozó beállításai alatt adható meg." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Klasszikus váltókapcsoló mód, kétgombos működés. Egy gombot nyomva tartva és a Turbo gombot megnyomva aktiválódik a megnyomás-elengedés szekvencia. Kikapcsoláshoz nyomva kell tartani a gombot és ismét megnyomni a Turbo gombot.\nA Turbo gomb a Beállítások / Bemenet / 1. csatlakozó beállításai alatt adható meg." + "Klasszikus váltókapcsoló mód, kétgombos működés. Egy gombot nyomva tartva és a Turbo gombot megnyomva aktiválódik a megnyomás-elengedés szekvencia. Kikapcsoláshoz nyomva kell tartani a gombot és ismét megnyomni a Turbo gombot.\nA Turbo gomb a Beállítások / Bemenet / X. csatlakozó beállításai alatt adható meg." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Átkapcsoló mód. A Turbo gombot egyszer megnyomva a kiválasztott alapértelmezett gombra aktiválódik a megnyomás-elengedés szekvencia, még egyszer megnyomva kikapcsol.\nA Turbo gomb a Beállítások / Bemenet / 1. csatlakozó beállításai alatt adható meg." + "Átkapcsoló mód. A Turbo gombot egyszer megnyomva a kiválasztott alapértelmezett gombra aktiválódik a megnyomás-elengedés szekvencia, még egyszer megnyomva kikapcsol.\nA Turbo gomb a Beállítások / Bemenet / X. csatlakozó beállításai alatt adható meg." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Nyomva tartó mód. A kiválasztott alapértelmezett gomb megnyomás-elengedés szekvenciája addig aktív, amíg a Turbo gomb le van nyomva.\nA Turbo gomb a Beállítások / Bemenet / 1. csatlakozó beállításai alatt adható meg.\nA házi számítógépek korszakának autofire funkciójának emulálásához a Turbo és az alapértelmezett gomb legyen ugyanat, mint a joystick tűzgombja." + "Nyomva tartó mód. A kiválasztott alapértelmezett gomb megnyomás-elengedés szekvenciája addig aktív, amíg a Turbo gomb le van nyomva.\nA Turbo gomb a Beállítások / Bemenet / X. csatlakozó beállításai alatt adható meg.\nA házi számítógépek korszakának autofire funkciójának emulálásához a Turbo és az alapértelmezett gomb legyen ugyanaz, mint a joystick tűzgombja." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Az alapértelmezett turbó gomb" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Turbó párosítás" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Alapértelmezett gomb a \"Single Button\" turbó módhoz." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "A turbó funkciót aktiváló RetroPad párosítás. Üres érték esetén a csatlakozónál megadott párosítás lesz érvényes." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Turbó iránygombok engedélyezése" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Turbó gomb" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "Bekapcsolva a digitális iránybemenetek (d-pad, hatswitch) is kiválaszthatóak turbó módban." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "A turbó funkció által aktivált gomb egygombos módban." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Turbó funkció engedélyezése az irányválasztóra" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, + "Bekapcsolva a digitális iránybemenetek (d-pad, hatswitch) is használhatóak turbó módban." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -3491,7 +3588,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "A turbó tűz beállítása. \nMegjegyzés: a turbó funkcióhoz be kell állítani egy turbó gombot a megfelelő csatlakozó kezelőszerveinél." + "A turbó tüzelés beállításai." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3688,7 +3785,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "A menü és a futó tartalom megjelenítése közt vált." + "Váltás a menü és a futó tartalom megjelenítése közt." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3768,7 +3865,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Váltás a futó tartalom megállítása és továbbengedése közt." + "Váltás a tartalom megállítása és továbbengedése közt." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -3976,6 +4073,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Eggyel csökkenti a visszajátszás rekeszének sorszámát." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Turbó tűz (átkapcsolás)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "A turbó tűz be- és kikapcsolása." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Egér megragadása (váltógomb)" @@ -4364,7 +4469,7 @@ MSG_HASH( "Pisztoly irányválasztó jobb" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, "Turbó" ) @@ -4737,7 +4842,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "A tartalom bezárásakor automatikusan készít egy mentést a játékállásról. Ha a \"Játékállás automatikus betöltése\" be van kapcsolva, ez fog betöltődni." + "Automatikus állapotmentés a tartalom bezárásakor. Ez az állapot töltődik be indításkor, ha az \"Automatikus játékállás betöltés\" be van kapcsolva." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -4917,14 +5022,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "A nem támogatott kiterjesztésű fájlok nem jelennek meg a Fájlböngészőben." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "A beépített médialejátszó használata" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Szűrés az aktuális mag szerint" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Az aktív mag által nem támogatott kiterjesztésű fájlok ne jelenjenek meg a Fájlböngészőben." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Utoljára használt kezdő könyvtár megjegyzése" @@ -4933,6 +5038,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "A Fájlböngésző az utoljára használt helyen nyílik meg a kezdő könyvtárból töltésnél. A RetroArch újraindításakor visszaáll az alapállapotra." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "A beépített médialejátszó használata" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "A beépített képnézegető használata" + ) /* Settings > Frame Throttle */ @@ -5290,6 +5403,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "A négy előlapi gomb átfedő zónáinak mérete. 100% a nyolc irányban szimmetrikus beállítás." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analóg központosítási zóna" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Ezen a zónán belüli érintéskor az analóg kar érzékelése az első érintéshez lesz viszonyítva." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Képernyőrátétek" @@ -5725,6 +5846,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Értesítések az automatikusan konfigurált bemeneti eszköz csatlakoztatásáról" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Értesítések a bemeneti eszköz automatikus konfigurációjának hibáiról" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Csalókód értesítések" @@ -5745,6 +5870,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Üzenet megjelenítése bemeneti eszközök csatlakoztatásakor és leválasztásakor." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Üzenet megjelenítése bemeneti eszközök sikertelen konfigurálásakor." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Értesítések remap fájlok betöltéséről" @@ -5879,7 +6008,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "A betűtípus mérete pontokban." + "A betűtípus mérete pontokban. Widgetek használatakor ez a méret csak a képernyőn megjelenő statisztikára van hatással." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6036,7 +6165,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Megállítja az éppen futó tartalmat, ha a menü aktiválódik." + "Tartalom megállítása, ha a menü aktív." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6393,7 +6522,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "A \"Játéklisták\" menü jelenjen meg. (Ozone / XMB esetén újraindítás szükséges.)" + "Játéklisták megjelenítése a főmenüben. GLUI esetén nincs hatása, ha a játéklista fülek és navigációs sáv engedélyezve van." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Fülek a játéklistáknak" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "A játéklisták megjelenítése külön füleken. RGUI-ra nincs hatása. GLUI esetén a navigációs sávot be kell kapcsolni. (Újraindítás szükséges Ozone/XMB esetén)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6873,14 +7010,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "\"Felhasználók\" látható" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Játéklista ikonok" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "A játéklista elemeinek ikonjai." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "A felhasználó beállításai jelenjenek meg." @@ -8108,7 +8237,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Fájlkezelő" + "Kezdő könyvtár" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8353,7 +8482,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "A futó tartalommal kapcsolatosan megosztott információk." + "A tartalommal kapcsolatosan megosztott információk." ) MSG_HASH( @@ -9105,7 +9234,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "A futó tartalom beállításai." + "A tartalomra vonatkozó beállítások." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9113,7 +9242,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "A futó tartalom irányításának változtatása." + "A tartalomra vonatkozó irányítás." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9211,11 +9340,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Beállítások visszaállítása" + "Magbeállítások visszaállítása" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Az összes magbeállítás visszaállítása alapértékre." + "A jelenlegi mag összes beállításának visszaállítása alapértékre." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9739,7 +9868,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "A shader fájl változásainak észlelése. A lemezen található shaderbe mentett változtatások után ez automatikusan újra lesz fordítva és alkalmazva a futó tartalomra." + "A shader fájl változásainak észlelése. Amikor a lemezen található shader megváltozik, automatikusan újra lesz fordítva és alkalmazva." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10200,6 +10329,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Bélyegképek váltogatása" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Véletlen választás" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Vissza" @@ -10956,7 +11089,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Amikor a gyorsmenü aktív, a futó tartalom látszódik a háttérben. Az átlátszóság kikapcsolása módosíthatja a menü színösszeállítását." + "Amikor a gyorsmenü aktív, a tartalom látszódik a háttérben. Az átlátszóság kikapcsolása módosíthatja a menü színösszeállítását." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11160,6 +11293,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "A bal oldalon megjelenő bélyegkép típusa." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Ikon bélyegkép" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "A játéklista elemeinek ikon típusa." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Dinamikus hátterek" @@ -11398,26 +11539,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "A játéklisták a gyártó neve nélküli betűrend szerint lesznek ábécésorrendben." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, - "Színösszeállítás" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, - "A színösszeállítás lecserélése." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_WHITE, - "Egyszerű fehér" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_BLACK, - "Egyszerű fekete" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_DRACULA, - "Drakula" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, "Másodlagos bélyegkép" @@ -11443,6 +11564,28 @@ MSG_HASH( "A bélyegkép oszlop méretezése." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, + "Színösszeállítás" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, + "A színösszeállítás lecserélése." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_WHITE, + "Egyszerű fehér" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_BLACK, + "Egyszerű fekete" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_DRACULA, + "Drakula" + ) + + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -11799,6 +11942,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, "Kezdő képernyő" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_LOGO, + "Logó" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, "Minden játéklista" @@ -12342,10 +12489,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Bill" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "A beépített képnézegető használata" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Swapchain képek maximális száma" @@ -12481,14 +12624,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Kiválasztás játéklistáról" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Folytatás" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "A futó tartalom folytatása és a gyorsmenü elhagyása." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "A %u találatból álló lista megtekintése" @@ -13087,10 +13222,6 @@ MSG_HASH( MSG_AUTODETECT, "Automatikus felismerés" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Játékállás automatikus betöltése innen" - ) MSG_HASH( MSG_CAPABILITIES, "Képességek" @@ -14175,6 +14306,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Virtuális lemeztálca becsukása sikertelen." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Játékállás automatikus betöltése innen" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Játékállás automatikus betöltése innen: \"%s\", sikertelen." @@ -14483,6 +14618,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Csalás aktiválva. A Hardcore trófea mód letiltva a mostani játékmenet idejére." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "A kiszolgáló megváltoztatta a trófeák Hardcore módját." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "A Netplay kiszolgálót frissíteni kell. A Hardcore trófea mód letiltva a mostani játékmenet idejére." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Mester szint: %s" @@ -15488,3 +15631,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "leállítva." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "MI játékos felülírás" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "MI játékos felülírás alcím" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "Játékos MI" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Az 1. játékos felülbírálata" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Az 1-es játékos felülbírálata" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "A 2. játékos felülbírálata" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "A 2-es játékos felülbírálata" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Hibakereső megjelenítése" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Hibakereső megjelenítése" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Játékos MI megjelenítése" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "A \"Játékos MI\" lehetőség jelenjen meg." + ) +#endif diff --git a/intl/msg_hash_id.h b/intl/msg_hash_id.h index d6f80be788..2d9841faf2 100644 --- a/intl/msg_hash_id.h +++ b/intl/msg_hash_id.h @@ -2084,10 +2084,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "Senyapkan suara Mixer." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Senyapkan saat dipercepat" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "Otomatis senyapkan audio saat menggunakan percepat." @@ -2437,21 +2433,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, "Jumlah detik untuk menahan input tombol untuk mengaturnya." ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Tekan Turbo" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Lama Turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Lamanya (sejumlah bingkai) saat tombol berturbo ditekan." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Daur Kerja Turbo" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Jumlah bingkai dari Lama Turbo yang tombolnya ditekan. Jika bilangan ini sama atau lebih besar dari yang di Lama Turbo, tombol akan ditekan terus." + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Lama Separuh" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, @@ -2462,12 +2455,20 @@ MSG_HASH( "Pilih tindakan utama tombol mode turbo." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Tombol Bawaan Turbo" + MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, + "Satu Tombol (Tahan)" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Tombol aktif bawaan untuk Mode Turbo 'Satu Tombol'." + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Pemeta Turbo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Tombol Turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "Menetapkan tombol turbo di mode 'Satu Tombol'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -2652,6 +2653,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Memulai/hentikan siaran alir dari sesi saat ini ke pelantar video daring." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Tekan Turbo (Nyala/Mati)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Menyala/matikan tekan turbo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, "Layar Penuh (Mati/Nyala)" @@ -2773,6 +2782,10 @@ MSG_HASH( /* Settings > File Browser */ +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Menyaring berkas sesuai Core saat ini di Peramban Berkas." + ) /* Settings > Frame Throttle */ @@ -3316,7 +3329,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Perambah Berkas" + "Direktori Awal" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -3887,6 +3900,8 @@ MSG_HASH( "Urut Daftar Main Setelah Pemenggalan Nama (Perlu Mulai Ulang)" ) + + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -4432,3 +4447,10 @@ MSG_HASH( MSG_SDL2_MIC_NEEDS_SDL2_AUDIO, "Mikrofon sdl2 perlu pengandar audio sdl2" ) +#ifdef HAVE_GAME_AI + + + + + +#endif diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 6a2e923698..89cc6b4cf2 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -67,6 +67,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Seleziona il core da utilizzare." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Scollega Core" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Rilascia il Core caricato." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Sfoglia l'implementazione di un core libretro. Quando il browser si avvia dipende dal percorso della directory principale. Se vuoto, verrà avviato in root.\nSe la directory principale è una directory, il menu la userà come cartella in alto. Se Core Directory è un percorso completo, verrà avviato nella cartella in cui si trova il file." @@ -898,6 +906,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Supporto Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Supporto SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Supporto Libusb" @@ -1916,7 +1928,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Inserisci fotogrammi neri tra fotogrammi. Puoi ridurre notevolmente la sfocatura del movimento emulando la scansione CRT, ma al costo della luminosità. Non combinare con Intervallo di scambio > 1, sottoframe, ritardo del frame o Sincronizza per ottenere un quadro di contenuto esatto." + "ATTENZIONE: lo sfarfallio rapido può causare persistenza delle immagini su alcuni display. Usare a proprio rischio // Inserire quadri neri tra i quadri. Può ridurre notevolmente la sfocatura del movimento emulando la scansione CRT, ma al costo della luminosità." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2000,7 +2012,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Inserisci fotogrammi shader aggiuntivi tra i quadri. Permette agli ombreggiatori di eseguire effetti con fps superiori al tasso di contenuto effettivo. Deve essere impostata alla schermata corrente Hz. Non combinare con Swap Intervallo > 1, BFI, Ritardo Frame o Sincronizzazione con Esact Content Framerate." + "ATTENZIONE: Il flickering rapido può causare persistenza delle immagini su alcuni display. Utilizzare a proprio rischio // Simula una linea di scanline di base su più sotto-frame dividendo lo schermo su verticalmente e rendendo ogni parte dello schermo in base a quanti sotto-frame ci sono." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2076,7 +2088,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Simula una linea di scanline di base su più sotto-frame dividendo lo schermo su verticalmente e rendendo ogni parte dello schermo in base a quanti sotto-frame ci sono." + "ATTENZIONE: Il flickering rapido può causare persistenza delle immagini su alcuni display. Utilizzare a proprio rischio // Simula una linea di scanline di base su più sotto-frame dividendo lo schermo su verticalmente e rendendo ogni parte dello schermo in base a quanti sotto-frame ci sono." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2503,7 +2515,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Scala solo altezza, o entrambi altezza e larghezza. Metà passi si applicano alle sorgenti ad alta risoluzione." + "Scala altezza o larghezza, o entrambe altezza e larghezza. Mezzi passaggi si applicano solo alle sorgenti ad alta risoluzione." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2601,11 +2613,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Bias di visualizzazione personalizzata utilizzato per spostare la vista orizzontalmente (se più ampia dell'altezza del contenuto). 0.0 significa lontano a sinistra e 1.0 significa lontano a destra." + "Posizione orizzontale del contenuto quando la vista è più larga della larghezza del contenuto. 0.0 è lontano a sinistra, 0.5 è al centro, 1.0 è lontano a destra." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Bias di visualizzazione personalizzata utilizzato per spostare la porta di visualizzazione verticalmente (se più alta dell'altezza del contenuto). 0.0 significa superiore e 1.0 significa basso." + "Posizione verticale del contenuto quando la vista è più alta dell'altezza del contenuto. 0.0 è in alto, 0.5 è al centro, 1.0 è in basso." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2626,11 +2638,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Bias di visualizzazione personalizzata utilizzato per spostare la vista orizzontalmente (se più ampia dell'altezza del contenuto). 0.0 significa lontano a sinistra e 1.0 significa lontano a destra. (Orientamento verticale)" + "Posizione orizzontale del contenuto quando la vista è più larga della larghezza del contenuto. 0.0 è lontano a sinistra, 0.5 è al centro, 1.0 è molto a destra. (Orientamento verticale)" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Bias di visualizzazione personalizzata utilizzato per spostare la porta di visualizzazione verticalmente (se più alta dell'altezza del contenuto). 0.0 significa superiore e 1.0 significa inferiore. (Orientamento verticale)" + "Posizione verticale del contenuto quando la vista è più alta dell'altezza del contenuto. 0.0 è in alto, 0.5 è al centro, 1.0 è in basso. (Orientamento verticale)" ) #endif MSG_HASH( @@ -2874,7 +2886,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Disattiva quando avanzi rapidamente" + "Muta Audio per la velocizzazione" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2882,12 +2894,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Accelerazione In Rapida Inoltro" + "Velocizzazione Audio Rapida" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Accelera l'audio quando si inoltra veloce. Previene crackling ma sposta il passo." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Muta audio per riavvolgimento" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Disattiva automaticamente l'audio quando si utilizza la velocizzazione." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Livello del volume audio (dB)" @@ -3409,22 +3429,35 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Tieni" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Modalità Turbo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Disabilitato interrompe tutte le operazioni di turbo fuoco." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Periodo Turbo" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Il periodo (in fotogrammi) quando i pulsanti abilitati per turbo sono premuti." + "Il periodo in fotogrammi quando i pulsanti abilitati a turbo vengono premuti." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, "Ciclo Operativo Turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, "Il numero di fotogrammi del Periodo Turbo per cui i pulsanti sono mantenuti. Se questo numero è uguale o maggiore del Turbo Period, i pulsanti non verranno mai rilasciati." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Metà Periodo" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Modalità Turbo" @@ -3451,35 +3484,43 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Modalità classica, operazione a due pulsanti. Tenere premuto un pulsante e toccare il pulsante Turbo per attivare la sequenza di rilascio presso.\nIl pulsante Turbo può essere assegnato in Impostazioni/Input/Porta 1 Controls." + "Modalità classica, operazione a due pulsanti. Tenere premuto un pulsante e toccare il pulsante Turbo per attivare la sequenza di rilascio presso.\nTurbo bind può essere assegnato in Impostazioni/Input/Port X Controls." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Modalità di commutazione classica, operazione a due pulsanti. Tieni premuto un pulsante e tocca il pulsante Turbo per abilitare il turbo per quel pulsante. Per disabilitare il turbo: tieni premuto il pulsante e premi nuovamente il pulsante Turbo. Il pulsante\nTurbo può essere assegnato in Impostazioni/Ingresso/Porta 1." + "Modalità di commutazione classica, operazione a due pulsanti. Tieni premuto un pulsante e tocca il pulsante Turbo per abilitare il turbo per quel pulsante. Per disabilitare il turbo: tieni premuto il pulsante e premi di nuovo il pulsante Turbo. Il Turbo Bind\npuò essere assegnato in Impostazioni/Input/Port X Controls." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Modalità attivazione/disattivazione. Premere il pulsante Turbo una volta per attivare la sequenza di rilascio della pressione per il pulsante predefinito selezionato, premere nuovamente per spegnerla.\nIl pulsante Turbo può essere assegnato in Impostazioni/Input/Porta 1 Controls." + "Modalità Abilitazione. Premere il pulsante Turbo una volta per attivare la sequenza di rilascio della pressione per il pulsante predefinito selezionato, premere nuovamente per spegnerla.\nTurbo bind può essere assegnato in Impostazioni/Input/Port X Controls." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Modalità premuta. La sequenza di rilascio premuto per il pulsante predefinito selezionato è attiva finché il pulsante Turbo è premuto giù.\nIl pulsante Turbo può essere assegnato in Impostazioni/Input/Porta 1 Controls.\nPer emulare la funzione di autofire dell'era del computer di casa, impostare i pulsanti Turbo e di default per essere lo stesso del pulsante di fuoco del joystick." + "Modalità premuta. La sequenza di rilascio premuto per il pulsante predefinito selezionato è attiva finché il pulsante Turbo è premuto giù.\nTurbo bind può essere assegnato in Impostazioni/Input/Port X Controls.\nPer emulare la funzione di autofire dell'era del computer di casa, impostare Bind e Pulsante allo stesso pulsante joystick fuoco." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Pulsante Predefinito Turbo" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Tasto Turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Pulsante attivo predefinito per la Modalità Turbo 'pulsante singolo'." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "Turbo attivando RetroPad bind. Vuoto utilizza il binding specifico alla porta." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Consenti direzioni con Turbo D-Pad" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Pulsante Turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "Se abilitato, gli ingressi direzionali digitali (noti anche come D-pad o \"hatswitch\") possono essere turbo." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "Pulsante turbo di destinazione in modalità 'Pulsante singolo'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Consenti Turbo Direzionali D-Pad" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, + "Se abilitata, gli ingressi direzionali digitali (noti anche come d-pad o 'hatswitch') possono essere turbo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -3487,7 +3528,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Modifica le impostazioni di turbo.\nNota: la funzione turbo richiede la mappatura di un pulsante turbo sul dispositivo di input nel corrispondente menu 'Port X Controls'." + "Cambia le impostazioni della modalità turbo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3764,7 +3805,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Consente di mettere in pausa o riprendere la riproduzione del contenuto." + "Alterna lo stato del contenuto tra in pausa e non in pausa." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -3972,6 +4013,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Diminuisce l'indice dello slot di replay attualmente selezionato." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Modalitù Turbo (Abilita)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Attiva/disattiva la modalità turbo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Prendi il Mouse (Abilita / Disabilita)" @@ -4485,7 +4534,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Specifica se ignorare le funzionalità di salvataggio di stato delle informazioni di base, consentendo di sperimentare con le caratteristiche correlate (Run-Ahead, riavvolgi, ecc)." + "Specifica se ignorare le informazioni di base salvare le capacità di stato, consentendo di sperimentare con le caratteristiche correlate (eseguire avanti, riavvolgimento, ecc)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4729,7 +4778,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Crea automaticamente uno stato di salvataggio quando il contenuto è chiuso. RetroArch caricherà automaticamente questo stato di salvataggio se 'Carica automaticamente lo stato' è abilitato." + "Crea automaticamente uno stato di salvataggio quando il contenuto è chiuso. Questo stato di salvataggio viene caricato all'avvio se 'Stato di caricamento automatico' è abilitato." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -4901,14 +4950,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtra i file che vengono mostrati nel File Browser per le estensioni supportate." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usa Lettore Multimediale Integrato" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtra per core corrente" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtra i file mostrati in Esplora file per nucleo corrente." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Ricorda L'Ultima Directory Di Avvio Usata" @@ -4917,6 +4966,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Aprire l'esplorazione file all'ultima posizione usata durante il caricamento del contenuto dalla cartella di avvio. Nota: la posizione sarà ripristinata a quella predefinita dopo il riavvio di RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Usa Lettore Multimediale Integrato" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Usa Visualizzatore Di Immagini Integrato" + ) /* Settings > Frame Throttle */ @@ -5721,6 +5778,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Notifiche di Connessione Input (Autoconfig)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Notifiche Di Input (Autoconfig) Fallite" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Notifiche Trucchi" @@ -5741,6 +5802,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Visualizza un messaggio sullo schermo quando si collegano/disconnettono i dispositivi di input." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Visualizza un messaggio sullo schermo quando i dispositivi di input non possono essere configurati." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Notifiche caricate di rimappatura dell'input" @@ -5875,7 +5940,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Specifica la dimensione del carattere in punti." + "Specifica la dimensione del carattere in punti. Quando i widget sono usati, questa dimensione ha effetto solo sul display delle statistiche sullo schermo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6032,7 +6097,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Metti in pausa il contenuto attualmente in esecuzione se il menu è attivo." + "Metti in pausa il contenuto se il menu è attivo." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6393,7 +6458,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Mostra le playlist. (Riavvio richiesto su Ozone/XMB)" + "Mostra le playlist nel menu principale. Ignorato in GLUI se le schede della playlist e della barra di navigazione sono abilitate." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Mostra le schede delle Playlist" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Mostra le schede della playlist. Non influisce su RGUI. La barra della navigazione deve essere abilitata in GLUI. (Riavvio richiesto su Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6869,14 +6942,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Mostra 'Utente'" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Icone Playlist" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Tipo di miniatura dell'icona della playlist da visualizzare." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Mostra impostazioni 'Utente'." @@ -8088,7 +8153,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Esplorazione File" + "Cartella predefinita" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8329,7 +8394,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Decidi quali informazioni relative al contenuto in esecuzione saranno condivise." + "Scegli quali informazioni relative al contenuto in esecuzione saranno condivise." ) MSG_HASH( @@ -8917,7 +8982,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Riprende il contenuto corrente e chiude il menu rapido." + "Riprendi il contenuto corrente e chiude il Menu Rapido." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -9069,7 +9134,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Modifica le opzioni per il contenuto attualmente in esecuzione." + "Cambia le opzioni per il contenuto." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9077,7 +9142,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Modifica i controlli per il contenuto attualmente in esecuzione." + "Cambia le opzioni degli input per il contenuto." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9171,11 +9236,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Ripristina Opzioni" + "Ripristina Opzioni Core" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Imposta tutte le opzioni dei nuclei ai valori predefiniti." + "Imposta tutte le opzioni del core attuale ai valori predefiniti." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9703,7 +9768,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Guardare i file shader per le nuove modifiche. Dopo aver salvato le modifiche a uno shader sul disco, verrà automaticamente ricompilato e applicato al contenuto in esecuzione." + "Monitora i file shader per le nuove modifiche. Dopo aver salvato le modifiche a uno shader sul disco, verrà automaticamente ricompilato e applicato al contenuto in esecuzione." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10164,6 +10229,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Ciclo miniature" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Selezione casuale" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Indietro" @@ -10365,11 +10434,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HOLD_SELECT, - "Mantieni Seelect (2 secondi)" + "Mantieni Select (2 secondi)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DOWN_SELECT, - "Giù + Seleziona" + "Giù + Select" ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_DISABLED, @@ -10864,7 +10933,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Abilita la visualizzazione dello sfondo dei contenuti in esecuzione mentre il Menu Veloce è attivo. La disabilitazione della trasparenza può alterare i colori dei temi." + "Abilita la visualizzazione dello sfondo dei contenuti in esecuzione mentre il Menu Rapido è attivo. La disabilitazione della trasparenza può alterare i colori dei temi." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11172,6 +11241,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Tipo di copertina da visualizzare a sinistra." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Miniatura Icona" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Tipo di miniatura icona della playlist da visualizzare." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Sfondo dinamico" @@ -11451,6 +11528,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Freddo glaciale" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Grigio Scuro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Grigio Chiaro" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11478,6 +11563,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Le scalette saranno riordinate in ordine alfabetico dopo aver rimosso il componente produttore dei loro nomi." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Miniatura Secondaria" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Sostituire il pannello dei metadati del contenuto con un'altra copertina." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Usa l'animazione del testo per i Metadati del Contenuto" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Se abilitata, ogni elemento di metadati di contenuto mostrato nella barra laterale destra delle playlist (nucleo associato, tempo di riproduzione) occuperà una singola riga; le stringhe che superano la larghezza della barra laterale saranno visualizzate come testo dell'animazione di scorrimento. Quando disabilitato, ogni elemento di metadati di contenuto verrà visualizzato staticamente, confezionato per occupare quante righe richieste." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Fattore scala delle copertine" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Scala la dimensione della barra delle miniature." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Colore del Tema" @@ -11506,10 +11616,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_TWILIGHT_ZONE, "Zona Crepuscolare" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, - "Selenio" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, "Scuro Solarizzato" @@ -11531,30 +11637,11 @@ MSG_HASH( "Pioggia Viola" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Miniatura Secondaria" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Sostituire il pannello dei metadati del contenuto con un'altra copertina." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Usa l'animazione del testo per i Metadati del Contenuto" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Se abilitata, ogni elemento di metadati di contenuto mostrato nella barra laterale destra delle playlist (nucleo associato, tempo di riproduzione) occuperà una singola riga; le stringhe che superano la larghezza della barra laterale saranno visualizzate come testo dell'animazione di scorrimento. Quando disabilitato, ogni elemento di metadati di contenuto verrà visualizzato staticamente, confezionato per occupare quante righe richieste." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Fattore scala delle copertine" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Scala la dimensione della barra delle miniature." + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "Selenio" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -12470,10 +12557,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Utente" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Usa Visualizzatore Di Immagini Integrato" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Massimo di immagini in swapchain" @@ -12597,14 +12680,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Seleziona da Playlist" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Riprendi" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Riprendi il contenuto corrente e chiude il menu rapido." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Visualizza la lista delle %u partite" @@ -13203,10 +13278,6 @@ MSG_HASH( MSG_AUTODETECT, "Trovato automaticamente" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Carica automaticamente il salvataggio da" - ) MSG_HASH( MSG_CAPABILITIES, "Funzionalità" @@ -14295,6 +14366,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Chiusura del vassoio del disco virtuale non riuscita." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Carica automaticamente il salvataggio da" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Caricamento automatico dello stato di salvataggio da \"%s\" non riuscito." @@ -14603,6 +14678,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Un trucco è stato attivato. Trofei della modalità Hardcore disabilitati per la sessione attuale." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Modalirà Obiettivi Hardcore cambiata dall'host." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "L'host Netplay deve essere aggiornato. La modalirà Obiettivi Hardcore disattivata per la sessione corrente." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Padroneggiato %s" @@ -15539,7 +15622,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Visualizza il carattere del menu inferiore. Abilita per visualizzare le descrizioni dei pulsanti nello schermo inferiore. Questo esclude la data di salvataggio." + "Visualizza il carattere del menu inferiore. Abilita per visualizzare le descrizioni dei pulsanti nella schermata inferiore. Questo esclude la data di salvataggio dello stato." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, @@ -15608,3 +15691,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "fermato." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "Sovrascrivi il giocatore IA" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "Descrizione sovrascrittura Giocatore IA" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "IA Gioco" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Sovrascrivi p1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Sovrascrivi giocatore 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Sovrascrivi p2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Sovrascrivi giocatore 02" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Mostra Debug" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Mostra Debug" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Mostra 'IA Gioco'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Mostra l'opzione 'IA Gioco'." + ) +#endif diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index df2076520f..5fef924962 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -726,6 +726,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "SDL2 対応" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Direct3D 8 対応" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Direct3D 9 対応" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Direct3D 10 対応" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Direct3D 11 対応" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Direct3D 12 対応" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "GDI 対応" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Vulkan 対応" @@ -806,6 +830,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "PulseAudio 対応" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "PipeWire 対応" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "CoreAudio 対応" @@ -886,6 +914,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 対応" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL 対応" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb 対応" @@ -1934,10 +1966,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, "黒フレーム挿入" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "フレーム間に黒フレームを挿入します。CRT スキャンをエミュレートすることで残像感を大幅に減らすことができますが、明るさが減少します。1 以上のスワップ間隔 (自動は可)、フレーム遅延または正確なコンテンツフレームレートに同期と組み合わせないでください。" - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, "フレーム間に黒フレームを挿入し、動きをより鮮明にします。現在のディスプレイのリフレッシュレート用に準備されたオプションのみを使用してください。144Hz、165Hz など、60Hz の倍数ではないリフレッシュレートでは使用できません。1 以上のスワップ間隔、フレーム遅延または正確なフレームレートに同期と組み合わせないでください。" @@ -2018,10 +2046,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES, "シェーダーサブフレーム" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "フレーム間に追加のシェーダーフレームを挿入します。シェーダーで実際のコンテンツフレームレートよりも高い FPS で動作するエフェクトを実行できるようになります。現在のディスプレイ Hz に対応するオプションを設定する必要があります。1 以上のスワップ間隔、黒フレーム挿入、正確なフレームレートに同期と組み合わせないでください。" - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, "コンテンツフレームレートよりも高速に動作するように設計されたシェーダー効果用に、フレーム間に追加のシェーダーフレームを挿入します。現在のディスプレイ Hz に対応するオプションのみを使用してください。144Hz、165Hz など、60Hz の倍数ではないリフレッシュレートでは使用できません。" @@ -2094,10 +2118,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCAN_SUBFRAMES, "ループ回転スキャンラインシミュレーション" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "画面を垂直に分割し、サブフレームの数に応じて画面の各部分をレンダリングすることで、複数のサブフレームにわたるブラウン管をカメラで撮影したときのようなループ回転スキャンラインをシミュレートします。" - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, "画面を垂直に分割し、画面の上端から下端にあるサブフレームの数に応じて画面の各部分をレンダリングすることで、複数のサブフレームにわたるブラウン管をカメラで撮影したときのようなループ回転スキャンラインをシミュレートします。" @@ -2513,6 +2533,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, "整数倍拡大" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, + "整数倍拡大軸" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_UNDERSCALE, + "アンダースケール" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_OVERSCALE, + "オーバースケール" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_SMART, "スマート" @@ -2591,14 +2623,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_Y, "表示領域 Y 座標補正" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "表示領域がコンテンツの幅より広い場合、水平方向のオフセットに使用される補正値です。0.0 は左端を、1.0 は右端を表します。" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "表示領域がコンテンツの高さより高い場合、垂直方向のオフセットに使用される補正値です。0.0 は上端を、1.0 は下端を表します。" - ) #if defined(RARCH_MOBILE) MSG_HASH( MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, @@ -2616,14 +2640,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, "表示領域 Y 座標補正 (縦向き)" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "表示領域がコンテンツの幅より広い場合、水平方向のオフセットに使用される補正値です。0.0 は左端を、1.0 は右端を表します (縦向き)。" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "表示領域がコンテンツの高さより高い場合、垂直方向のオフセットに使用される補正値です。0.0 は上端を、1.0 は下端を表します (縦向き)。" - ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, @@ -2852,18 +2868,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE, "サイレントモードですべてのオーディオを消音にします。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "早送り時に消音" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "早送りを使用中に自動的にオーディオを消音にします。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "早送り時に高速化" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "早送り時にオーディオを高速化します。音割れを防ぎますが、ピッチがずれます。" @@ -3381,22 +3389,15 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "長押し" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "連射" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "ターボ間隔" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "ターボを有効にしたボタンが押される間隔 (フレーム単位) です。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "ターボ間隔中のボタン押下フレーム数" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "ターボ間隔中にボタンの押下状態を維持するフレーム数です。この値をターボ間隔と同じかそれ以上にすると、ボタンは離されず押されたままの状態になります。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "ターボモード" @@ -3421,46 +3422,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, "シングルボタン (長押し)" ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "クラシックモードです。ターボの有効化ボタンと連射したいボタンを同時に押している間、連射したいボタンが連射されます。\nターボの有効化ボタンは [設定 > 入力 > ポート 1 コントロール] で割り当てることができます。" - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "クラシック切り替えモードです。連射したいボタンを押しながらターボの有効化ボタンを押すと、ターボを無効にするまで連射したいボタンが連射ボタンになります。ターボを無効にするには、連射ボタンを押しながらターボの有効化ボタンを押してください。\nターボの有効化ボタンは [設定 > 入力 > ポート 1 コントロール] で割り当てることができます。" - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "切り替えモードです。ターボの有効化ボタンを一度押すと、次にターボの有効化ボタンを押すまで選択されたデフォルトボタンが押下せずとも自動で連射されます。\nターボの有効化ボタンは [設定 > 入力 > ポート 1 コントロール] で割り当てることができます。" - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "長押しモードです。ターボの有効化ボタンを押している間、選択されたデフォルトボタンが連射されます。\nターボの有効化ボタンは [設定 > 入力 > ポート 1 コントロール] で割り当てることができます。\nホームコンピュータ時代の連射機能をエミュレートするには、ターボの有効化ボタンとデフォルトボタンをジョイスティックのファイアボタンと同じに設定します。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "ターボデフォルトボタン" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "ターボモード [シングルボタン] で連射されるデフォルトのボタンです。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "十字キーのターボを許可" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "有効にすると、デジタル方向入力 (十字キーまたは「ハットスイッチ」とも呼ばれます) がターボできるようになります。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "連射" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "連射の設定を変更します。\n注意: 連射機能を使用するには、対応する [ポート X コントロール] メニューで入力デバイスにターボの有効化ボタンを割り当てる必要があります。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, "触覚フィードバック/振動" @@ -3638,10 +3603,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, "メニュー切り替え" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "現在の表示をメニューと実行中のコンテンツの間で切り替えます。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, "終了 (コントローラー同時押し)" @@ -3718,10 +3679,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "一時停止" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "実行中のコンテンツの一時停止と非一時停止の状態を切り替えます。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, "コマ送り" @@ -4311,10 +4268,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, "ライトガン 十字キー 右" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "ターボの有効化" - ) /* Settings > Latency */ @@ -4427,10 +4380,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "コア情報のステートセーブ機能の対応有無を無視" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "コア情報のステートセーブ機能の対応有無を無視するかどうかを指定し、関連する機能 (先行実行、巻き戻しなど) を試すことができます。" - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4671,10 +4620,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "自動ステートセーブ" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "コンテンツを閉じたときに自動的にステートセーブを作成します。[自動ステートロード] が有効になっている場合、RetroArch はこのステートセーブを自動的にロードします。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "自動ステートロード" @@ -4853,10 +4798,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "ファイルブラウザに表示されるファイルを対応する拡張子でフィルタリングします。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "内蔵メディアプレイヤーを使用" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "現在のコアでフィルター" @@ -4869,6 +4810,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "コンテンツをロードする際に、最後に使用したディレクトリでファイルブラウザを開きます。注意: 再起動すると場所はデフォルトにリセットされます。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "内蔵メディアプレイヤーを使用" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "内蔵画像ビューアを使用" + ) /* Settings > Frame Throttle */ @@ -5817,10 +5766,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "通知のサイズ" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "フォントサイズをポイントで指定します。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, "通知の表示位置 (水平)" @@ -5974,10 +5919,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, "メニュー表示時にコンテンツを一時停止" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "メニューを表示している間、現在実行中のコンテンツを一時停止します。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, "ステートセーブ後にコンテンツを再開" @@ -6323,10 +6264,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, "[プレイリスト] を表示" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "[プレイリスト] メニューを表示します。 (Ozone/XMB で再起動が必要)" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, "[エクスプローラー] を表示" @@ -6805,14 +6742,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "[ユーザー] を表示" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "プレイリストアイコン" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "表示するプレイリストアイコンサムネイルの種類です。" - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "[ユーザー] 設定を表示します。" @@ -7771,10 +7700,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_WITHOUT_CORE_MATCH, "対応するコアがインストールされていないコンテンツをスキャンし、プレイリストに追加することを許可します。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "スキャン時に重複の可能性がある場合 CRC をチェック" - ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, "特に PSP/PSN タイトルで、ISO が重複するシリアルを持つ場合があります。シリアルにのみ依存すると、スキャナーがコンテンツを間違ったシステムに入れてしまうことがあります。これにより CRC チェックが追加され、スキャンが大幅に遅くなりますが、より正確になる可能性があります。" @@ -8032,7 +7957,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "ファイルブラウザ" + "開始ディレクトリ" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8275,10 +8200,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT, "Rich Presence コンテンツ形式" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "実行中のコンテンツに関連する情報について、どのような情報を共有するかを決定します。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT_CONTENT, @@ -8875,10 +8796,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "再開" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "クイックメニューを閉じて現在動作中のアプリを再開します。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, "再起動" @@ -8891,10 +8808,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, "コンテンツを閉じる" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "現在のコンテンツを閉じます。すべての保存されていない設定は失われる可能性があります。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, "スクリーンショットを撮影" @@ -9027,18 +8940,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "コアオプション" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "現在動作中のコンテンツのオプションを変更します。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "コントロール" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "現在動作中のコンテンツのコントロールを変更します。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "チート" @@ -9133,14 +9038,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTION_OVERRIDE_INFO, "現在使用中のオプションファイルです。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "オプションをリセット" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "すべてのコアオプションをデフォルトの値に設定します。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, "オプションを強制的にディスクに保存" @@ -9669,10 +9566,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, "ディスク上のシェーダーファイルに加えられた変更を自動的に適用します。" ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "シェーダーファイルの新しい変更を監視します。シェーダーの変更をディスクに保存すると、自動的に再コンパイルされ実行中のコンテンツに適用されます。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, "最後に使用したシェーダーディレクトリを記憶" @@ -10914,10 +10807,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_TRANSPARENCY, "透明度" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "クイックメニューがアクティブな間、実行中のコンテンツの背景表示を有効にします。透明度を無効にするとテーマカラーが変わることがあります。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, "影のエフェクト" @@ -11455,6 +11344,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDGAR, "ミッドガル" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "グレーダーク" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "グレーライト" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11482,6 +11379,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "メーカー名が削除されたプレイリストをアルファベット順に並べ替えます。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "セカンダリーサムネイル" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "コンテンツのメタデータパネルを、選択したサムネイルを表示するパネルに置き換えます。" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "コンテンツのメタデータ表示にティッカーテキストを使用" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "有効にすると、プレイリストの右サイドバーに表示されるコンテンツメタデータの各項目 (関連付けされたコア、プレイ時間) が 1 行で表示されます。サイドバーの幅を超える文字列はスクロールティッカーテキストとして表示されます。無効にすると、コンテンツメタデータの各項目は静的に表示され、必要な行数に応じて折り返されます。" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "サムネイル表示倍率" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "サムネイルバーのサイズの表示倍率です。" + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "カラーテーマ" @@ -11510,30 +11432,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_PURPLE_RAIN, "パープルレイン" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "セカンダリーサムネイル" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "コンテンツのメタデータパネルを、選択したサムネイルを表示するパネルに置き換えます。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "コンテンツのメタデータ表示にティッカーテキストを使用" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "有効にすると、プレイリストの右サイドバーに表示されるコンテンツメタデータの各項目 (関連付けされたコア、プレイ時間) が 1 行で表示されます。サイドバーの幅を超える文字列はスクロールティッカーテキストとして表示されます。無効にすると、コンテンツメタデータの各項目は静的に表示され、必要な行数に応じて折り返されます。" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "サムネイル表示倍率" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "サムネイルバーのサイズの表示倍率です。" - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -11899,6 +11798,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, "タイトルスクリーン" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_LOGO, + "ロゴ" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, "すべてのプレイリスト" @@ -12450,10 +12353,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "キーボード" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "内蔵画像ビューアを使用" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "最大スワップチェーンイメージ" @@ -12589,14 +12488,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "プレイリストから選択" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "再開" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "クイックメニューを閉じて現在動作中のアプリを再開します。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "%u 一致リストを表示" @@ -13195,10 +13086,6 @@ MSG_HASH( MSG_AUTODETECT, "自動検出" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "ステートセーブを自動ロード中 from" - ) MSG_HASH( MSG_CAPABILITIES, "対応機能" @@ -14287,6 +14174,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "仮想ディスクトレイを閉じることができませんでした。" ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "ステートセーブを自動ロード中 from" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "\"%s\" からのステートセーブの自動読み込みに失敗しました。" @@ -15513,10 +15404,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "フォントを有効にする" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "下メニューのフォントを表示します。下画面にボタンの説明を表示することが出来ます。ステートセーブの日付は表示されません。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "フォントの色 (赤)" @@ -15584,3 +15471,10 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "停止しました。" ) +#ifdef HAVE_GAME_AI + + + + + +#endif diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index cfa8f52551..bd4624f956 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "사용할 코어를 선택합니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "코어 닫기" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "불러와져있는 코어를 종료합니다." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "libretro 코어 파일을 탐색합니다. 탐색기가 시작되는 위치는 코어 디렉토리 경로를 따릅니다. 만약 비어있다면 루트에서 시작됩니다.\n코어 디렉토리가 폴더로 설정되면 메뉴상에서 최상위 폴더로 사용됩니다. 코어 디렉토리가 전체 경로라면 파일이 있는 폴더에서 시작됩니다." @@ -914,6 +922,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 지원" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL 지원" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Libusb 지원" @@ -1980,7 +1992,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "프레임 사이에 검정색 프레임을 삽입합니다. CRT 스캔을 에뮬레이션하여 모션 블러를 크게 줄일 수 있지만 밝기는 저하됩니다. 스왑 간격 > 1, 서브프레임, 프레임 지연, 정확한 프레임 동기화 설정들과 함께 사용하지 마십시오." + "주의: 빠른 깜빡임은 일부 디스플레이에 잔상을 남길 수 있습니다. 사용에 주의가 필요합니다 // 프레임 사이에 검은 프레임을 삽입합니다. CRT 스캔을 흉내내어 모션 블러를 크게 줄일 수 있지만, 화면 밝기가 저하됩니다." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2064,7 +2076,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "프레임 사이에 추가 셰이더 프레임을 삽입합니다. 셰이더가 콘텐츠의 프레임 레이트보다 더 높은 프레임 레이트로 작업을 수행할 수 있게 합니다. 현재 디스플레이의 주사율 Hz와 일치하는 값으로 설정되어야 합니다. 스왑 간격 > 1, 검정색 프레임 삽입, 정확한 프레임 동기화 설정들과 함께 사용하지 마십시오." + "주의: 빠른 깜빡임은 일부 디스플레이에 잔상을 남길 수 있습니다. 사용에 주의가 필요합니다 // 화면을 여러 세로 구간으로 나누고 다수의 서브프레임으로부터 각 구간에 해당하는 서브프레임을 렌더하는 방식으로 롤링 스캔라인 효과를 흉내냅니다." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2140,7 +2152,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "화면을 여러 세로 구간으로 나누고 다수의 서브프레임으로부터 각 구간에 해당하는 서브프레임을 렌더하는 방식으로 롤링 스캔라인 효과를 흉내냅니다." + "주의: 빠른 깜빡임은 일부 디스플레이에 잔상을 남길 수 있습니다. 사용에 주의가 필요합니다 // 화면을 여러 세로 구간으로 나누고 다수의 서브프레임으로부터 각 구간에 해당하는 서브프레임을 렌더하는 방식으로 롤링 스캔라인 효과를 흉내냅니다." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2567,7 +2579,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "화면 크기를 조정할 때 기준을 높이로 할지, 높이와 너비 모두로 할지 설정합니다. 고해상도 영상에는 절반 단위 조정도 적용됩니다." + "화면 크기를 조정할 때 기준을 높이로 할지, 너비로 할지, 높이와 너비 모두로 할지 설정합니다. 절반 단위 조정은 고해상도 영상에만 적용됩니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2669,11 +2681,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "뷰포트 너비가 콘텐츠 너비보다 넓을 경우 뷰포트 가로 위치를 조정할 때 사용할 사용자 뷰포트 바이어스입니다. 0.0은 왼쪽 끝, 1.0은 오른쪽 끝입니다." + "뷰포트 가로 길이가 컨텐츠 가로 길이보다 길 때 컨텐츠를 표시할 가로 위치입니다. 0.0은 왼쪽 끝, 0.5는 가운데, 1.0은 오른쪽 끝입니다." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "뷰포트 높이가 콘텐츠 높이보다 길 경우 뷰포트 세로 위치를 조정할 때 사용할 사용자 뷰포트 바이어스입니다. 0.0은 맨 위, 1.0은 맨 아래입니다." + "뷰포트 세로 길이가 컨텐츠 세로 길이보다 길 때 컨텐츠를 표시할 세로 위치입니다. 0.0은 위쪽 끝, 0.5는 가운데, 1.0은 아래쪽 끝입니다." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2694,11 +2706,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "뷰포트 너비가 콘텐츠 너비보다 넓을 경우 뷰포트 가로 위치를 조정할 때 사용할 사용자 뷰포트 바이어스입니다. 0.0은 왼쪽 끝, 1.0은 오른쪽 끝입니다. (세로 화면)" + "뷰포트 가로 길이가 컨텐츠 가로 길이보다 길 때 컨텐츠를 표시할 가로 위치입니다. 0.0은 왼쪽 끝, 0.5는 가운데, 1.0은 오른쪽 끝입니다. (세로 화면)" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "뷰포트 높이가 콘텐츠 높이보다 길 경우 뷰포트 세로 위치를 조정할 때 사용할 사용자 뷰포트 바이어스입니다. 0.0은 맨 위, 1.0은 맨 아래입니다. (세로 화면)" + "뷰포트 세로 길이가 컨텐츠 세로 길이보다 길 때 컨텐츠를 표시할 세로 위치입니다. 0.0은 위쪽 끝, 0.5는 가운데, 1.0은 아래쪽 끝입니다. (세로 화면)" ) #endif MSG_HASH( @@ -2950,7 +2962,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "빨리 감기 중 음소거" + "빨리 감기 중 오디오 음소거" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2964,6 +2976,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "빨리 감기 중 오디오의 속도를 올립니다. 소리 깨짐 효과를 방지하지만 음높이가 올라갑니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "뒤로 감기 중 오디오 음소거" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "뒤로 감기를 사용할 때 오디오를 음소거합니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "오디오 볼륨 레벨 (dB)" @@ -3509,21 +3529,34 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "꾹 누르기" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "터보 입력" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "비활성화할 경우 모든 터보 입력이 중단됩니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "터보 반복 간격" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "터보 설정된 버튼이 눌렸을 때 사용될 입력 간격(프레임)입니다." + "터보 설정된 버튼을 누르고 있으면, 이 프레임 간격마다 버튼 입력이 반복됩니다." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "터보 입력 시간" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, + "터보 홀드 시간" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "터보 설정된 버튼이 눌렸을 때 사용될 누르고 있을 기간(프레임)입니다. 이 값이 터보 간격 값과 같거나 더 클 경우, 버튼은 눌린 상태로 유지될 것입니다." + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, + "터보 설정된 버튼을 누르고 있을 때 버튼이 눌려 있을 프레임 간격입니다. 이 값이 터보 반복 간격 값과 같거나 더 클 경우, 버튼은 계속 눌린 상태로 유지됩니다." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "반복 간격의 절반" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, @@ -3551,35 +3584,43 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "클래식 모드, 2버튼 작동. 버튼을 누른 상태에서 터보 버튼을 클릭해 활성화합니다.\n터보 버튼은 설정/입력/포트 1 컨트롤에서 할당할 수 있습니다." + "두 개의 버튼을 사용하는 클래식 모드입니다. 원하는 버튼을 누른 상태에서 터보 활성화 버튼을 눌러 터보 입력을 활성화합니다.\n터보 활성화 버튼은 설정/입력/X번 포트 입력 설정에서 할당할 수 있습니다." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "클래식 토글 모드, 2버튼 작동. 원하는 버튼을 누른 상태에서 터보 버튼을 눌러 활성화합니다. 터보를 끄려면: 원하는 버튼을 누른 상태에서 터보 버튼을 한 번 더 누릅니다.\n터보 버튼은 설정/입력/포트 1 컨트롤에서 할당할 수 있습니다." + "두 개의 버튼을 사용하는 클래식 토글 모드입니다. 원하는 버튼을 누른 상태에서 터보 활성화 버튼을 누르면 해당 버튼의 터보 입력이 활성화됩니다. 터보 입력을 끄려면: 원하는 버튼을 누른 상태에서 터보 활성화 버튼을 한 번 더 누릅니다.\n터보 활성화 버튼은 설정/입력/X번 포트 입력 설정에서 할당할 수 있습니다." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "토글 모드. 터보 버튼을 한 번 누르면 선택한 기본 버튼의 터보가 활성화되고 다시 한 번 누르면 꺼집니다.\n터보 버튼은 설정/입력/포트 1 컨트롤에서 할당할 수 있습니다." + "토글 모드입니다. 터보 활성화 버튼을 한 번 누르면 지정된 버튼의 터보 입력이 활성화되고, 한 번 더 누르면 비활성화됩니다.\n터보 활성화 버튼은 설정/입력/X번 포트 입력 설정에서 할당할 수 있습니다." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "홀드 모드. 터보 버튼을 누르고 있는 동안 선택한 기본 버튼의 터보가 활성화됩니다.\n터보 버튼은 설정/입력/포트 1 컨트롤에서 할당할 수 있습니다.\n가정용 컴퓨터 시대의 자동 발사 기능을 모방하려면 터보 버튼과 기본 버튼을 조이스틱 발사 버튼과 동일하게 설정하십시오." + "홀드 모드입니다. 터보 활성화 버튼이 눌려 있는 동안 지정된 버튼의 터보 입력이 활성화됩니다.\n터보 활성화 버튼은 설정/입력/X번 포트 입력 설정에서 할당할 수 있습니다.\n가정용 컴퓨터 시대의 자동 연사 기능을 모방하려면, 터보 활성화 버튼과 지정 버튼을 동일한 조이스틱 발사 버튼으로 할당하십시오." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "터보 기본 버튼" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "터보 활성화 버튼" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "'단일 버튼' 터보 모드의 기본 터보 활성화 버튼을 설정합니다." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "터보를 활성화하는 RetroPad 입력입니다. 비워둘 경우 개별 포트에서 할당된 버튼이 사용됩니다." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "터보 십자패드 방향 허용" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "터보 지정 버튼" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "활성화되면 디지털 방향 입력 (십자패드 또는 'hatswitch'라고도 함) 이 터보가 될 수 있습니다." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "'단일 버튼' 모드에서 터보를 활성화할 지정 버튼입니다." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "방향 패드 터보 입력 허용" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, + "활성화할 경우, 디지털 방향 입력(십자패드 또는 '햇스위치'라고도 함)에도 터보 입력을 사용할 수 있게 됩니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -3587,7 +3628,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "터보 발사 설정 변경입니다.\n참고: 터보 기능을 사용하려면 해당 '포트 X 컨트롤' 메뉴에서 터보 버튼을 입력 장치에 매핑해야 합니다." + "터보 입력 설정을 변경합니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3784,7 +3825,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "실행중인 콘텐츠와 메뉴 사이를 전환합니다." + "콘텐츠와 메뉴 사이를 전환합니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -4072,6 +4113,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "선택된 리플레이 슬롯의 인덱스를 감소시킵니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "터보 입력 (켜기/끄기)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "터보 입력을 켜거나 끕니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "마우스 잡기 (켜기/끄기)" @@ -4460,8 +4509,8 @@ MSG_HASH( "무기 D-패드 오른쪽" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "터보 사용" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, + "터보" ) /* Settings > Latency */ @@ -4837,7 +4886,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "콘텐츠가 종료되면 자동으로 상태저장 파일을 생성합니다. 자동 상태 불러오기가 활성화 되어 있으면 다음 시작시 해당 상태저장을 자동으로 불러옵니다." + "컨텐츠를 종료할 때 자동으로 상태저장을 생성합니다. '상태저장 자동으로 불러오기'가 활성화되어 있는 경우, 이 상태저장을 다음 시작 시에 자동으로 불러옵니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -5017,14 +5066,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "파일 탐색기에서 지원되는 확장자의 파일만 표시합니다." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "내장 미디어 플레이어 사용" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "현재 코어에 따라 필터" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "현재 코어에서 사용 가능한 파일만 표시합니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "최근 사용한 시작 디렉토리 기억" @@ -5033,6 +5082,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "시작 디렉토리에서 콘텐츠를 불러올 경우 최근 사용한 위치에서 파일 탐색기를 시작합니다. 참고: RetroArch를 재시작하면 기본 위치로 초기화 됩니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "내장 미디어 플레이어 사용" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "내장 이미지 뷰어 사용" + ) /* Settings > Frame Throttle */ @@ -5398,6 +5455,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "전면 버튼이 겹치는 부분의 크기를 조절합니다. 100%로 설정하면 8방향 구역의 크기가 모두 같아집니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "아날로그 중심점 재정의 구역 범위" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "지정한 구역 내에서 터치를 시작할 경우 처음 터치한 위치를 아날로그 스틱 입력의 중심점으로 사용합니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "오버레이" @@ -5833,6 +5898,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "입력 (자동구성) 연결 알림" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "입력 (자동구성) 실패 알림" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "치트 코드 알림" @@ -5853,6 +5922,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "입력 장치를 연결/연결 해제할 때 화면에 메시지를 표시합니다." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "입력 장치가 제대로 설정되지 못했을 때 화면에 메시지를 표시합니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "입력 설정파일 불러오기 알림" @@ -5987,7 +6060,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "포인트 단위로 폰트 크기를 설정합니다." + "폰트 크기(포인트)를 지정합니다. 위젯을 사용하는 경우, 이 크기 설정은 온스크린 통계 표시에만 적용됩니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6144,7 +6217,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "RetroArch 메뉴가 활성화되면 실행중인 콘텐츠를 일시정지합니다." + "메뉴가 활성화되면 컨텐츠를 일시정지합니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6505,7 +6578,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "실행목록을 표시합니다. (Ozone/XMB 사용시 재시작 필요)" + "메인 메뉴에 실행목록을 표시합니다. GLUI에서는 실행목록 탭과 내비게이션 바가 활성화된 경우 무시됩니다." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "실행목록 탭 표시" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "실행목록 탭을 표시합니다. RGUI에서는 무시됩니다. GLUI에서는 내비게이션 바가 활성화되어 있어야 합니다. (Ozone/XMB 사용시 재시작 필요)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6985,14 +7066,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "'사용자' 표시" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "실행목록 아이콘" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "표시할 실행목록 아이콘 섬네일의 종류입니다." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "'사용자' 설정을 표시합니다." @@ -7957,11 +8030,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "스캔은 가능한 중복에 대해 CRC를 확인" + "CRC 검사로 중복 여부 확인" ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, - "때때로 ISO는 특히 PSP/PSN 타이틀의 경우 시리즈를 복제합니다. 시리즈에만 의존하면 스캐너가 콘텐츠를 잘못된 시스템에 배치하는 경우가 있습니다. 이렇게 하면 CRC 검사가 추가되어 스캔 속도가 상당히 느려지지만 더 정확할 수 있습니다." + "종종 내용은 다르지만 같은 시리얼 값을 가지는 ISO들이 존재하며, 이는 특히 PSP/PSN 타이틀에서 빈번히 발견됩니다. 시리얼 값만으로 콘텐츠를 구분할 경우 콘텐츠가 잘못된 시스템으로 분류될 수 있습니다. 이 옵션을 활성화하면 CRC 검사 과정이 추가되며, 검사 속도가 현저히 느려지지만, 더 정확한 결과를 얻을 수 있습니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LIST, @@ -8216,7 +8289,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "파일 탐색기" + "시작 디렉토리" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8461,7 +8534,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "실행중인 콘텐츠에 대해 어떤 정보를 공유할지 결정합니다." + "콘텐츠에 대한 어떤 정보를 공유할지 결정합니다." ) MSG_HASH( @@ -9061,7 +9134,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "빠른 메뉴를 종료하고 현재 실행 중인 콘텐츠를 이어합니다" + "빠른 메뉴를 종료하고 콘텐츠로 돌아갑니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -9077,7 +9150,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "현재 콘텐츠를 종료합니다. 저장되지 않은 내용은 사라지게 됩니다." + "콘텐츠를 종료합니다. 저장되지 않은 내용은 사라지게 됩니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9213,7 +9286,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "현재 실행중인 콘텐츠의 옵션을 변경합니다." + "콘텐츠의 옵션을 변경합니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9221,7 +9294,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "현재 실행중인 콘텐츠의 조작방법 설정을 변경합니다." + "콘텐츠의 조작 방법을 변경합니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9319,11 +9392,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "옵션 초기화" + "코어 옵션 초기화" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "모든 코어 옵션을 기본값으로 초기화합니다." + "현재 코어의 모든 옵션을 기본값으로 초기화합니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9855,7 +9928,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "셰이더 파일에서 변경 사항을 확인합니다. 셰이더 변경 사항을 디스크에 저장하면 자동으로 다시 컴파일되어 실행 중인 콘텐츠에 적용됩니다." + "셰이더 파일의 변경을 감지합니다. 셰이더의 변경 사항이 디스크에 저장되면 셰이더가 자동으로 다시 컴파일되어 콘텐츠에 적용됩니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10320,6 +10393,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "미리보기 전환" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "랜덤 선택" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "이전" @@ -10996,7 +11073,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "빠른 메뉴 활성 시 실행 중인 컨텐츠를 배경 화면으로 표시합니다. 이 설정을 변경하면 테마 색상이 달라질 수 있습니다." + "빠른 메뉴 활성 시 콘텐츠를 배경 화면으로 표시합니다. 이 설정을 변경하면 테마 색상이 달라질 수 있습니다." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11340,6 +11417,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "왼쪽에 표시할 미리보기의 종류입니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "아이콘 미리보기" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "표시할 실행목록 아이콘 미리보기의 종류입니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "다이나믹 백그라운드" @@ -11647,6 +11732,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDGAR, "미드가르" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "어두운 회색" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "밝은 회색" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11674,6 +11767,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "이름에서 제조사 항목을 삭제한 후 실행목록을 알파벳 순으로 다시 정렬합니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "두 번째 미리보기" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "콘텐츠 메타데이터 패널 대신 다른 미리보기를 표시합니다." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "콘텐츠 메타데이터 한 줄로 표시" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "사용할 경우, 오른쪽 사이드바에 표시되는 콘텐츠 메타데이터(코어, 실행 시간 등)를 항목당 한 줄씩으로 표시합니다. 사이드바 너비를 초과하는 길이의 문구는 스크롤됩니다. 사용하지 않을 경우, 컨텐츠 메타데이터는 필요한 만큼 줄 수를 늘려가며 정적으로 표시됩니다." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "미리보기 배율" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "섬네일 바의 크기 배율을 설정합니다." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "색상 테마" @@ -11714,10 +11832,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_DRACULA, "드라큘라" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, - "셀레늄" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, "솔라라이즈 다크" @@ -11739,30 +11853,11 @@ MSG_HASH( "자줏빛 비" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "두 번째 미리보기" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "콘텐츠 메타데이터 패널 대신 다른 미리보기를 표시합니다." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "콘텐츠 메타데이터 한 줄로 표시" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "사용할 경우, 오른쪽 사이드바에 표시되는 콘텐츠 메타데이터(코어, 실행 시간 등)를 항목당 한 줄씩으로 표시합니다. 사이드바 너비를 초과하는 길이의 문구는 스크롤됩니다. 사용하지 않을 경우, 컨텐츠 메타데이터는 필요한 만큼 줄 수를 늘려가며 정적으로 표시됩니다." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "미리보기 배율" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "섬네일 바의 크기 배율을 설정합니다." + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "셀레늄" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -12742,10 +12837,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "키보드" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "내장 이미지 뷰어 사용" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "최대 스왑체인 이미지" @@ -12881,14 +12972,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "실행목록에서 선택" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "이어하기" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "빠른 메뉴를 종료하고 현재 실행 중인 콘텐츠를 이어합니다." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "%u 일치 목록 확인" @@ -13487,10 +13570,6 @@ MSG_HASH( MSG_AUTODETECT, "자동감지" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "상태저장 자동 불러오기: " - ) MSG_HASH( MSG_CAPABILITIES, "기능" @@ -14583,6 +14662,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "가상 디스크 트레이를 닫지 못했습니다." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "상태저장 자동 불러오기: " + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "\"%s\"에서 상태저장을 자동으로 불러오지 못했습니다." @@ -14885,11 +14968,19 @@ MSG_HASH( ) MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED, - "상태저장을 불러왔습니다. 현재 세션의 하드코어 모드 도전과제는 해제됩니다." + "상태저장을 불러왔습니다. 도전과제 하드코어 모드가 현재 세션에서 비활성화되었습니다." ) MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, - "치트가 활성화 되었습니다. 현재 세션의 하드코어 모드 도전과제는 해제됩니다." + "치트가 활성화되었습니다. 도전과제 하드코어 모드가 현재 세션에서 비활성화되었습니다." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "호스트가 도전과제 하드코어 모드를 변경했습니다." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "넷플레이 호스트가 오래된 버전을 사용 중입니다. 도전과제 하드코어 모드가 현재 세션에서 비활성화되었습니다." ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, @@ -14901,7 +14992,7 @@ MSG_HASH( ) MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_ENABLE, - "하드코어 모드 사용 중에는 상태저장 및 뒤로 감기 기능을 이용할 수 없습니다." + "도전과제 하드코어 모드 사용 중에는 상태저장 및 뒤로 감기 기능을 이용할 수 없습니다." ) MSG_HASH( MSG_CHEEVOS_GAME_HAS_NO_ACHIEVEMENTS, @@ -15916,3 +16007,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "중지됨." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "AI 플레이어 할당" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "AI 플레이어 할당 설명" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "게임 AI" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "p1 할당" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "플레이어 1에 할당" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "p2 할당" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "플레이어 2에 할당" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "디버그 표시" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "디버그 표시" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "'게임 AI' 표시" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "'게임 AI' 옵션을 표시합니다." + ) +#endif diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 5920c32309..610f0903da 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -240,6 +240,10 @@ MSG_HASH( MENU_ENUM_LABEL_AUDIO_DRIVER_RWEBAUDIO, "rwebaudio" ) +MSG_HASH( + MENU_ENUM_LABEL_AUDIO_DRIVER_AUDIOWORKLET, + "audioworklet" + ) MSG_HASH( MENU_ENUM_LABEL_AUDIO_DRIVER_JACK, "jack" @@ -693,7 +697,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_CLOSE_CONTENT, - "unload_core" + "close_content" ) MSG_HASH( MENU_ENUM_LABEL_COLLECTION, @@ -827,6 +831,10 @@ MSG_HASH( MENU_ENUM_LABEL_CORE_LIST, "load_core" ) +MSG_HASH( + MENU_ENUM_LABEL_CORE_LIST_UNLOAD, + "unload_core" + ) MSG_HASH( MENU_ENUM_LABEL_SIDELOAD_CORE_LIST, "sideload_core" @@ -1009,6 +1017,10 @@ MSG_HASH( MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_DISK_INDEX, "deferred_dropdown_box_list_disk_index" ) +MSG_HASH( + MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_RETROPAD_BIND, + "deferred_dropdown_box_list_input_retropad_bind" + ) MSG_HASH( MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE, "deferred_dropdown_box_list_input_device_type" @@ -1039,6 +1051,10 @@ MSG_HASH( MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_AUDIO_DEVICE, "deferred_dropdown_box_list_audio_device" ) +MSG_HASH( + MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MIDI_DEVICE, + "deferred_dropdown_box_list_midi_device" + ) #ifdef HAVE_MICROPHONE MSG_HASH( MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MICROPHONE_DEVICE, @@ -1550,6 +1566,10 @@ MSG_HASH( MENU_ENUM_LABEL_DISK_OPTIONS, "core_disk_options" ) +MSG_HASH( + MENU_ENUM_LABEL_DISK_INDEX, + "core_disk_index" + ) MSG_HASH( MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, "downloaded_file_detect_core_list" @@ -1940,10 +1960,6 @@ MSG_HASH( MENU_ENUM_LABEL_INPUT_DRIVER, "input_driver" ) -MSG_HASH( - MENU_ENUM_LABEL_INPUT_DUTY_CYCLE, - "input_duty_cycle" - ) MSG_HASH( MENU_ENUM_LABEL_INPUT_RETROPAD_BINDS, "input_retropad_binds" @@ -2184,10 +2200,6 @@ MSG_HASH( MENU_ENUM_LABEL_INPUT_TOUCH_ENABLE, "input_touch_enable" ) -MSG_HASH( - MENU_ENUM_LABEL_INPUT_TURBO_PERIOD, - "input_turbo_period" - ) MSG_HASH( MENU_ENUM_LABEL_INPUT_USER_10_BINDS, "10_input_binds_list" @@ -3402,10 +3414,6 @@ MSG_HASH( MENU_ENUM_LABEL_RESTART_RETROARCH, "restart_retroarch" ) -MSG_HASH( - MENU_ENUM_LABEL_RESUME, - "resume" - ) MSG_HASH( MENU_ENUM_LABEL_RESUME_CONTENT, "resume_content" @@ -3502,6 +3510,22 @@ MSG_HASH( MENU_ENUM_LABEL_CREATE_NEW_PLAYLIST, "playlist_create" ) +MSG_HASH( + MENU_ENUM_LABEL_ADD_TO_PLAYLIST_QUICKMENU, + "playlist_add_quickmenu" + ) +MSG_HASH( + MENU_ENUM_LABEL_DEFERRED_ADD_TO_PLAYLIST_QUICKMENU, + "deferred_add_to_playlist_quickmenu" + ) +MSG_HASH( + MENU_ENUM_LABEL_ADD_ENTRY_TO_PLAYLIST_QUICKMENU, + "add_entry_to_playlist_quickmenu" + ) +MSG_HASH( + MENU_ENUM_LABEL_CREATE_NEW_PLAYLIST_QUICKMENU, + "playlist_create_quickmenu" + ) MSG_HASH( MENU_ENUM_LABEL_SET_CORE_ASSOCIATION, "set_core_association" @@ -6216,6 +6240,10 @@ MSG_HASH( MENU_ENUM_LABEL_NOTIFICATION_SHOW_AUTOCONFIG, "notification_show_autoconfig" ) +MSG_HASH( + MENU_ENUM_LABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "notification_show_autoconfig_fails" + ) MSG_HASH( MENU_ENUM_LABEL_NOTIFICATION_SHOW_CHEATS_APPLIED, "notification_show_cheats_applied" @@ -6585,8 +6613,20 @@ MSG_HASH( "input_turbo_mode" ) MSG_HASH( - MENU_ENUM_LABEL_INPUT_TURBO_DEFAULT_BUTTON, - "input_turbo_default_button" + MENU_ENUM_LABEL_INPUT_TURBO_BIND, + "input_turbo_bind" + ) +MSG_HASH( + MENU_ENUM_LABEL_INPUT_TURBO_BUTTON, + "input_turbo_button" + ) +MSG_HASH( + MENU_ENUM_LABEL_INPUT_TURBO_PERIOD, + "input_turbo_period" + ) +MSG_HASH( + MENU_ENUM_LABEL_INPUT_TURBO_DUTY_CYCLE, + "input_turbo_duty_cycle" ) MSG_HASH( MENU_ENUM_LABEL_INPUT_ALLOW_TURBO_DPAD, @@ -6632,3 +6672,25 @@ MSG_HASH( MENU_ENUM_LABEL_GAMEMODE_ENABLE, "game_mode_enable" ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_CORE_GAME_AI_OPTIONS, + "core_game_ai_options" + ) +MSG_HASH( + MENU_ENUM_LABEL_QUICK_MENU_SHOW_GAME_AI, + "quick_menu_show_game_ai" + ) +MSG_HASH( + MENU_ENUM_LABEL_GAME_AI_OVERRIDE_P1, + "game_ai_override_p1" + ) +MSG_HASH( + MENU_ENUM_LABEL_GAME_AI_OVERRIDE_P2, + "game_ai_override_p2" + ) +MSG_HASH( + MENU_ENUM_LABEL_GAME_AI_SHOW_DEBUG, + "game_ai_show_debug" + ) +#endif diff --git a/intl/msg_hash_mt.h b/intl/msg_hash_mt.h index b960f0acc4..ec36df9ebe 100644 --- a/intl/msg_hash_mt.h +++ b/intl/msg_hash_mt.h @@ -134,6 +134,7 @@ #ifdef ANDROID #endif + /* Settings > Input > Haptic Feedback/Vibration */ @@ -415,6 +416,8 @@ /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -463,4 +466,11 @@ #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index e9a9701b58..67aa301923 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -2256,18 +2256,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "Demp audio van mixer." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Dempen bij Vooruitspoelen" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "Audio automatisch dempen bij gebruik van Vooruitspoelen." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Versnelling bij snel vooruitspoelen" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Versnel de audio wanneer je snel vooruitgaat. Voorkomt kraken maar verschuift de pitch." @@ -2709,22 +2701,15 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_BIND_HOLD, "Aantal seconden om een invoer vast te houden om deze te binden." ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo-vuur" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbo Periode" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "De periode (in frames) wanneer turbo-ingeschakelde knoppen worden ingedrukt." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Turbo Duty Cyclus" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Het aantal frames uit de Turbo-periode waarvoor de knoppen worden ingedrukt. Als dit aantal gelijk is aan of groter is dan de Turbo-periode, zullen de knoppen nooit loslaten." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Turbo Modus" @@ -2745,22 +2730,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, "Enkelvoudige knop (Vasthouden)" ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Klassieke modus, twee-knop bewerking. Houd een knop ingedrukt en druk op de Turbo knop om de indrukken-loslaten sequentie te activeren.\nTurbo knop kan worden toegewezen in Instellingen/Invoer/Poort 1 Controls." - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Omschakelen modus. Druk eenmaal op de Turbo knop om de indrukken-loslaten sequentie voor de geselecteerde standaard knop te activeren, druk opnieuw op de knop om deze uit te schakelen.\nTurbo knop kan worden toegewezen in Instellingen/Invoer/Poort 1 Controls." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Turbo Standaardknop" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Standaard actieve knop voor Turbo Modus 'Enkele Knop'." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "Turbo-vuur" @@ -2898,10 +2867,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, "Menu-schakel" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Schakelt de huidige weergave tussen het menu en de actieve inhoud." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, "Afsluiten (Bedieningscombinatie)" @@ -2978,10 +2943,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "Pauzeren" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Schakelt om inhoud uit te voeren tussen onderbroken en niet-onderbroken staten." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, "Frame-voortgang" @@ -3735,10 +3696,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Automatisch Slaan de Staat op" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatisch een slagstaat maken wanneer inhoud wordt gesloten. RetroArch zal deze slagstaat automatisch laden als 'Staat Automatisch Laden' is ingeschakeld." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, "Laad de slagstaat automatisch bij het opstarten." @@ -3881,10 +3838,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtreer onbekende extensies" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Gebruik ingebouwde media speler" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filter op Huidige Core" @@ -3893,6 +3846,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Onthoud de Laatst Gebruikte Startmap" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Gebruik ingebouwde media speler" + ) /* Settings > Frame Throttle */ @@ -5156,7 +5113,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Bestandsbeheer" + "Favorieten" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, @@ -5862,6 +5819,7 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, "Selecteer een ander kleurenschema." @@ -5875,6 +5833,7 @@ MSG_HASH( "Zwart" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -6133,10 +6092,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, "Forceer beeldverhouding" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Hervatten" - ) MSG_HASH( /* FIXME Still exists in a comment about being removed */ MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, "Voettekst Zichtbaarheid" @@ -6763,4 +6718,11 @@ MSG_HASH( ) #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_no.h b/intl/msg_hash_no.h index 1ad42b3146..bbc320045e 100644 --- a/intl/msg_hash_no.h +++ b/intl/msg_hash_no.h @@ -71,6 +71,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Velg hvilken kjerne du skal bruke." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_CORE_LIST, + ".." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, "Åpne innhold" @@ -2153,6 +2157,7 @@ MSG_HASH( MSG_INPUT_BIND_TIMEOUT, "Tidsavbrudd" ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbo periode" @@ -2425,10 +2430,6 @@ MSG_HASH( /* Settings > File Browser */ -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Bruk innebygd mediespiller" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrer etter gjeldende kjerne" @@ -2437,6 +2438,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Husk sist brukte startmappe" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Bruk innebygd mediespiller" + ) /* Settings > Frame Throttle */ @@ -2613,10 +2618,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "Størrelse på varsling" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Angi skriftstørrelsen i punkter." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_ENABLE, "Varslingsbakgrunn" @@ -2662,10 +2663,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, "Sett innholdet på pause når menyen er aktiv" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Pauser det nåværende innholdet som kjører når menyen er aktiv." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUIT_ON_CLOSE_CONTENT, "Avslutt ved stenging av innhold" @@ -2815,10 +2812,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, "Vis 'Spillelister'" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Vis spillelistene. (Omstart kreves på Ozone/XMB)" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, "Vis \"Utforsk\"" @@ -3428,7 +3421,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Filutforsker" + "Startmappe" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, @@ -3787,18 +3780,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "Gjenoppta" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Gjenoppta gjeldende innhold og forlat hurtigmenyen." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, "Lukk innhold" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Lukk dette innholdet. Eventuelle ulagrede endringer vil gå tapt." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, "Ta skjermbilde" @@ -4391,6 +4376,8 @@ MSG_HASH( "Sekundært miniatyrbilde" ) + + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -4789,14 +4776,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Velg fra en spilleliste" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Gjenoppta" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Gjenoppta gjeldende innhold og forlat hurtigmenyen." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, "Nettspill" @@ -5428,3 +5407,10 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "stoppet." ) +#ifdef HAVE_GAME_AI + + + + + +#endif diff --git a/intl/msg_hash_oc.h b/intl/msg_hash_oc.h index 247bb5f8e2..4dd9c0f1b9 100644 --- a/intl/msg_hash_oc.h +++ b/intl/msg_hash_oc.h @@ -302,6 +302,7 @@ MSG_HASH( #ifdef ANDROID #endif + /* Settings > Input > Haptic Feedback/Vibration */ @@ -611,6 +612,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -707,4 +710,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_or.h b/intl/msg_hash_or.h index 375526b027..ccacdd3197 100644 --- a/intl/msg_hash_or.h +++ b/intl/msg_hash_or.h @@ -430,6 +430,7 @@ MSG_HASH( #ifdef ANDROID #endif + /* Settings > Input > Haptic Feedback/Vibration */ @@ -779,6 +780,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -875,4 +878,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_pl.h b/intl/msg_hash_pl.h index 7ddae92c13..2c7a3c7267 100644 --- a/intl/msg_hash_pl.h +++ b/intl/msg_hash_pl.h @@ -910,6 +910,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Obsługa Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Wsparcie SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Obsługa libusb" @@ -1264,6 +1268,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_CONFIGS, "Po włączeniu pliki konfiguracyjne zostaną zsynchronizowane z chmurą." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_THUMBS, + "Po włączeniu miniaturki zostaną zsynchronizowane z chmurą. Na ogół niezalecane z wyjątkiem dużych kolekcji niestandardowych obrazów miniatur; w przeciwnym razie lepszy wybór jest pobieracz miniatur." + ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_SYSTEM, "Gdy włączone, pliki systemowe będą synchronizowane z chmurą. To może znacząco wydłużyć czas potrzebny do synchronizacji; używaj z ostrożnością." @@ -1737,6 +1745,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PULSE, "Sterownik PulseAudio. Jeśli system używa PulseAudio, upewnij się, że używasz tego sterownika zamiast np. ALSA." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PIPEWIRE, + "Sterownik PipeWire. Jeśli system używa PipeWire, upewnij się, że używasz tego sterownika zamiast np. PulseAudio." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_JACK, "Sterownik Jack Audio Connection Kit." @@ -1924,7 +1936,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Wstaw czarne ramki między ramkami. Może znacznie zmniejszyć rozmycie ruchu poprzez emulowanie skanowania CRT, ale kosztem jasności. Nie łączyć z Interwalem Swap > 1, podramki, ramki Frame lub Synchronizuj z dokładną zawartością." + "OSTRZEŻENIE: Szybkie migotanie może spowodować utrzymywanie się obrazu na niektórych wyświetlaczach. Używaj na własne ryzyko // Wstaw czarne ramki między klatkami. Może znacznie zmniejszyć rozmycie ruchu poprzez emulowanie skanowania CRT, ale kosztem jasności." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2008,7 +2020,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Wstawia dodatkowe klatki shadera pomiędzy klatkami. Umożliwia shaderom wykonywanie efektów, które działają z wyższą liczbą klatek na sekundę niż rzeczywista częstotliwość wyświetlania treści. Powinno być ustawione na bieżące Hz ekranu. Nie łączyć z opcjami Interwał zmiany klatek > 1, BFI, Opóźnienie klatek lub Synchronizuj do dokładnego framerate'u zawartości." + "OSTRZEŻENIE: Szybkie migotanie może spowodować utrzymywanie się obrazu na niektórych wyświetlaczach. Użwać na własne ryzyko // Symuluje prostą kroczącą linię skanującą nad wieloma podklatkami poprzez podzielenie ekranu pionowo i renderowanie każdej części ekranu w zależności od liczby podklatek." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2084,7 +2096,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Symuluje prostą kroczącą linię skanującą na wielu podklatkach poprzez podzielenie ekranu w górę pionowo i renderowanie każdej części ekranu w zależności od liczby podklatek." + "OSTRZEŻENIE: Szybkie migotanie może spowodować utrzymywanie się obrazu na niektórych wyświetlaczach. Użwać na własne ryzyko // Symuluje prostą kroczącą linię skanującą nad wieloma podklatkami poprzez podzielenie ekranu pionowo i renderowanie każdej części ekranu w zależności od liczby podklatek." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2502,12 +2514,12 @@ MSG_HASH( "Skala całkowita" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, - "Oś skali całkowitej" + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, + "Skaluj wideo tylko w krokach całkowitych. Rozmiar bazowy zależy od geometrii i proporcji podanej w rdzeniu." ) MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Skaluj tylko wysokość lub zarówno wysokość, jak i szerokość. Połowa kroków dotyczy źródeł o wysokiej rozdzielczości." + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, + "Oś skali całkowitej" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_SMART, @@ -2571,14 +2583,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_X, "Podgląd zakotwiczenia X" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Własny widok używany do wyrównywania widoku poziomo (jeśli jest większy niż wysokość zawartości). 0.0 oznacza lewy i 1.0 oznacza prawo." - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Własny widok używany do wyrównywania widoku poziomo (jeśli jest większy niż wysokość zawartości). 0.0 oznacza lewy i 1.0 oznacza prawo." - ) #if defined(RARCH_MOBILE) MSG_HASH( MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, @@ -2588,14 +2592,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, "Podgląd kotwicy X (orientacja pionowa)" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Własny widok używany do wyrównywania widoku poziomo (jeśli jest większy niż wysokość zawartości). 0.0 oznacza lewo, a 1.0 oznacza prawo. (orientacja pionowa)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Własny widok używany do przesuwania widoku pionowo (jeśli jest wyższy niż wysokość zawartości). 0.0 oznacza górny i 1.0 oznacza dolny (orientacja pionowa)" - ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, @@ -2816,18 +2812,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE, "Wycisz wszystkie dźwięki w trybie cichym." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Wycisz podczas przyspieszania" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "Automatycznie wycisz dźwięk podczas używania przyspieszenia." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Przyspiesz podczas przewijania do przodu" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Poziom głośności (dB)" @@ -3237,22 +3225,15 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Przytrzymaj" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo Ogień" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Okres turbo" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Okres (w klatkach) po naciśnięciu przycisków włączonych turbo." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Turbo Cykl Duty" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Liczba klatek z okresu Turbo, w którym przyciski są przytrzymywane. Jeśli liczba ta jest równa lub większa od okresu Turbo, przyciski nigdy nie zostaną uruchomione." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Tryb turbo" @@ -3277,34 +3258,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, "Pojedynczy przycisk (Przytrzymanie)" ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Tryb klasyczny, operacja dwóch przycisków. Przytrzymaj przycisk i naciśnij przycisk Turbo, aby aktywować sekwencję odblokowania.\nPrzycisk Turbo może być przypisany w Ustawieniach/Input/Port 1 Controls." - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Przełącz tryb. Naciśnij przycisk Turbo, aby aktywować sekwencję uwalniania dla wybranego przycisku domyślnego, naciśnij go ponownie aby go wyłączyć.\nPrzycisk Turbo może być przypisany w Ustawieniach/Input/Port 1 Controls." - ) -MSG_HASH( - MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Tryb przytrzymania. Sekwencja zwolnienia dla wybranego domyślnego przycisku jest aktywna, dopóki przycisk Turbo jest przytrzymywany w dół.\nPrzycisk Turbo może być przypisany w Ustawieniach/Input/Port 1 Controls.\nAby emulować funkcję autoognia w epoce komputera domowego, ustaw Turbo i domyślne przyciski aby były takie same jak przycisk ognia joysticka." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Domyślny przycisk turbo" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Domyślny aktywny przycisk dla trybu turbo \"Pojedynczy przycisk\"." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "Turbo Ogień" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Zmień ustawienia turbo ognia.\nUwaga: funkcja turbo wymaga zmapowania przycisku turbo do urządzenia wejściowego w odpowiednim menu \"Elementy sterujące portu X\"." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, "Haptyczne sprzężenie zwrotne / wibracje" @@ -3462,10 +3419,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, "Przełączanie menu" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Przełącza bieżący wyświetlacz pomiędzy menu i uruchomioną treścią." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, "Wyjście (Kontroler Combo)" @@ -3538,10 +3491,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "Pauza" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Przełącza uruchomioną zawartość pomiędzy stanami wstrzymanymi i niewstrzymanymi." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, @@ -4079,6 +4028,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_CACHE_ENABLE, "Utrzymuj stałą lokalną pamięć podręczną zainstalowanych informacji o rdzeniach. Znacznie skraca czas ładowania na platformach z wolnym dostępem do dysku." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, + "Określa, czy zignorować podstawowe informacje zapisują możliwości stanu, pozwalające na eksperymentowanie z powiązanymi funkcjami (uruchamianie z przodu, przewijanie itp.)." + ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4281,7 +4234,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatycznie utwórz stan zapisu, gdy zawartość jest zamknięta. RetroArch automatycznie załaduje ten stan zapisu, jeśli włączona jest opcja \"Załaduj stan automatycznie\"." + "Automatycznie utwórz stan zapisu, gdy zawartość jest zamknięta. Ten stan zapisów jest załadowany przy starcie, jeśli włączony jest \"Automatycznej wczytywanie\"." ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, @@ -4437,14 +4390,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtruj pliki wyświetlane w przeglądarce plików przez obsługiwane rozszerzenia." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Użyj wbudowanego odtwarzacza multimedialnego" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtruj według bieżącego rdzenia" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtruj pliki wyświetlane w przeglądarce plików według aktualnego rdzenia." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Zapamiętaj ostatnio używany katalog startowy" @@ -4453,6 +4406,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Otwórz przeglądarkę plików w ostatnio używanej lokalizacji podczas ładowania zawartości z katalogu startowego. Uwaga: Lokalizacja zostanie przywrócona do wartości domyślnych po ponownym uruchomieniu RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Użyj wbudowanego odtwarzacza multimedialnego" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Użyj wbudowanej przeglądarki zdjęć" + ) /* Settings > Frame Throttle */ @@ -5259,7 +5220,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Określ rozmiar czcionki w punktach." + "Określ rozmiar czcionki w punktach. Gdy widżety są używane, ten rozmiar ma wpływ tylko na wyświetlanie statystyk na ekranie." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -5370,10 +5331,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, "Wstrzymaj zawartość, gdy Menu jest aktywne" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Zatrzymaj aktualnie uruchomioną zawartość, jeśli menu jest aktywne." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, "Wznów zawartość po użyciu zapisów stanu" @@ -5721,7 +5678,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Pokaż listy odtwarzania. (Wymagane estart na Ozone/XMB)" + "Pokaż listy odtwarzania w menu głównym. Ignorowane w GLUI, jeśli karty playlisty i pasek nawigacji są włączone." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Pokaż karty playlist" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Pokaż karty playlisty. Nie ma wpływu na RGUI. Pasek nawigacyjny musi być włączony w GLUI. (Pestart wymagany w Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6145,14 +6110,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Pokaż 'Użytkownik'" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Ikony listy odtwarzania" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Typ miniatury ikony listy odtwarzania do wyświetlenia." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Pokaż ustawienia 'Użytkownika'." @@ -7244,7 +7201,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Przeglądarka plików" + "Katalog startowy" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, @@ -7991,10 +7948,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "Wznów zawartość" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Wznów aktualnie uruchomioną zawartość i opuść szybkie menu." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, "Uruchom ponownie" @@ -8007,10 +7960,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, "Zamknij zawartość" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Zamknij bieżącą zawartość. Wszelkie niezapisane zmiany mogą zostać utracone." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, "Zrób zrzut ekranu" @@ -8127,18 +8076,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "Opcje rdzenia" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Zmień opcje aktualnie wyświetlanej treści." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "Elementy sterujące" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Zmień elementy sterujące dla aktualnie uruchomionej zawartości." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Kody" @@ -8209,14 +8150,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTION_OVERRIDE_INFO, "Bieżący plik opcji w użyciu." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Resetuj opcje" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Przywrócić całą konfigurację rdzeni do wartości domyślnych." - ) /* - Legacy (unused) */ MSG_HASH( @@ -8996,6 +8929,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Cykl miniatury" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Losowy wybór" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Cofnij" @@ -9714,10 +9651,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_RGUI_MENU_THEME_PRESET, "Wybierz predefiniowany motyw menu z przeglądarki plików." ) -MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Włącz wyświetlanie w tle uruchomionych treści, gdy szybkie menu jest aktywne. Wyłączenie przezroczystości może zmienić kolory motywu." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, "Efekty cienia" @@ -10008,6 +9941,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Typ miniatury do wyświetlenia po lewej stronie." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Miniatura ikony" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Typ miniatury ikony listy odtwarzania do wyświetlenia." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Dynamiczne tło" @@ -10235,6 +10176,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Lodowy zimny" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Ciemny szary" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Jasno szary" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -10258,6 +10207,27 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Listy odtwarzania zostaną ponownie posortowane w kolejności alfabetycznej po usunięciu składnika producenta ich nazw." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Drugorzędna miniatura" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Zastąp panel metadanych na inną miniaturę." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Użyj paska tekstu dla metadanych zawartości" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Gdy włączony, każdy element metadanych zawartości wyświetlany na prawym pasku bocznym playlisty (powiązany rdzeń, czas odtwarzania) będzie zajmował pojedynczą linię; ciągi przekraczające szerokość paska bocznego będą wyświetlane jako przewijany tekst. Po wyłączeniu, każdy element metadanych zawartości będzie wyświetlany statycznie, zawinięty i zajmujący tyle wierszy, ile jest wymagane." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Współczynnik skali miniatur" + ) + MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, "Wybierz inny motyw koloru." @@ -10306,26 +10276,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_PURPLE_RAIN, "Fioletowy deszcz" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Drugorzędna miniatura" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Zastąp panel metadanych na inną miniaturę." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Użyj paska tekstu dla metadanych zawartości" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Gdy włączony, każdy element metadanych zawartości wyświetlany na prawym pasku bocznym playlisty (powiązany rdzeń, czas odtwarzania) będzie zajmował pojedynczą linię; ciągi przekraczające szerokość paska bocznego będą wyświetlane jako przewijany tekst. Po wyłączeniu, każdy element metadanych zawartości będzie wyświetlany statycznie, zawinięty i zajmujący tyle wierszy, ile jest wymagane." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Współczynnik skali miniatur" - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -11254,10 +11205,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Użytkownik" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Użyj wbudowanej przeglądarki zdjęć" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "Informuje sterownik wideo, aby jawnie użył określonego trybu buforowania." @@ -11377,14 +11324,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Wybierz z playlisty" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Wznów" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Wznów aktualnie uruchomioną zawartość i opuść szybkie menu." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Zobacz listę %u dopasowań" @@ -11959,10 +11898,6 @@ MSG_HASH( MSG_AUTODETECT, "Automatyczne wykrywanie" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Automatyczne ładowanie stanu zapisu" - ) MSG_HASH( MSG_CAPABILITIES, "Możliwości" @@ -12971,6 +12906,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "Obliczenie rozmiaru obszaru widoku nie powiodło się! Nadal używane będą surowe dane. To prawdopodobnie nie zadziała dobrze..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Automatyczne ładowanie stanu zapisu" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Automatyczne ładowanie stanu zapisu z \"%s\" nie powiodło się." @@ -13937,6 +13876,10 @@ MSG_HASH( MSG_3DS_BOTTOM_MENU_LOAD_STATE, "Załaduj\nPunkt przywracania" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, + "Wyświetlaj czcionkę dolnego menu. Włącz, aby wyświetlić opisy przycisków na dolnym ekranie. Wyklucza to datę zapisu." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_OPACITY, "Przezroczystość koloru czcionki" @@ -13968,3 +13911,26 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "zatrzymano." ) +#ifdef HAVE_GAME_AI + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "Gra AI" + ) + +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Zastąp gracza 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Zastąp p2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Zastąp gracza 02" + ) + + +#endif diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 20e36cf6be..6005798949 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -67,6 +67,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Carrega um núcleo para ser executado." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Descarregar Núcleo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Liberar o núcleo carregado." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Procura executar um núcleo libretro. O navegador começa no seu diretório \"Núcleos\". Caso esteja em branco, começará na raiz (root).\nCaso o diretório \"Núcleos\" seja um diretório, o menu usará o diretório como uma pasta. Caso o diretório \"Núcleos\" seja um endereço completo, começará na pasta do arquivo." @@ -143,7 +151,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, - "Atualizador on-line" + "Atualizador online" ) MSG_HASH( MENU_ENUM_SUBLABEL_ONLINE_UPDATER, @@ -207,7 +215,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_QUIT_RETROARCH, - "Sair do RetroArch. Matar o programa de qualquer maneira difícil (SIGKILL, etc.) encerrará o RetroArch sem salvar a configuração. Em Unix-likes, SIGINT/SIGTERM permite uma desinicialização limpa que inclui salvamento de configuração se ativado." + "Sair do RetroArch. Matar o programa de qualquer maneira difícil (SIGKILL, etc.) encerrará o RetroArch sem salvar a configuração. Em sistemas baseados em Unix, SIGINT/SIGTERM permite uma 'desinicialização' limpa que inclui salvamento de configuração se ativado." ) /* Main Menu > Load Core */ @@ -292,7 +300,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_GOTO_EXPLORE, - "Navegue por todo o conteúdo correspondente ao banco de dados por meio de uma interface de pesquisa categorizada." + "Navegue por todo o conteúdo correspondente ao banco de dados por uma interface com pesquisa categorizada." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_GOTO_CONTENTLESS_CORES, @@ -491,9 +499,13 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_REQUIRED_HW_API, "API gráficas necessárias" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_PATH, + "Caminho completo" +) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SUPPORT_LEVEL, - "Suporte ao jogo salvo" + "Suporte a Salvar Estado (Save State)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DISABLED, @@ -501,7 +513,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BASIC, - "Básico (salva/carrega)" + "Básico (Salva/Carrega)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SERIALIZED, @@ -509,11 +521,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DETERMINISTIC, - "Determinístico (salva/carrega, rebobina, execução antecipada, Netplay)" + "Determinístico (Salva/Carrega, Rebobina, Execução antecipada, Netplay)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_IN_CONTENT_DIRECTORY, - "- Nota: Os arquivos do sistema estão no Diretório de Conteúdo' está ativado no momento." + "- Nota: 'Arquivos de sistema estão no Diretório de Conteúdo' está ativado no momento." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_PATH, + "- Pesquisando em: \"%s\"" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MISSING_REQUIRED, @@ -545,7 +561,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_SET_STANDALONE_EXEMPT, - "Impede que este núcleo seja exibido na aba / menu 'Núcleos sem conteúdo. Aplica-se somente quando o modo de exibição é definido como 'Personalizado'." + "Impede que este núcleo seja exibido na aba/menu 'Núcleos sem conteúdo'. Aplica-se somente quando o modo de exibição é definido como 'Personalizado'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_DELETE, @@ -806,6 +822,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "Suporte ao PulseAudio" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "Suporte ao PipeWire" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "Suporte ao CoreAudio" @@ -886,6 +906,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Suporte ao Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Suporte ao SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Suporte ao libusb" @@ -938,7 +962,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SCORE, - "Nota" + "Pontuação" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MEDIA, @@ -1536,6 +1560,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_DRIVER, "Define o driver de entrada.\nOs drivers de vídeo podem forçar um driver de entrada diferente." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_INPUT_DRIVER_UDEV, + "O driver udev lê eventos evdev para suporte ao teclado. Ele também suporta callback de teclado, mouses e touchpads.\nPor padrão na maioria das distros, os nós /dev/input são root-only (modo 600). Você pode configurar uma regra udev que os torna acessíveis para non-root." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_INPUT_DRIVER_LINUXRAW, "O driver de entrada linuxraw requer um TTY. Os eventos do teclado são lidos diretamente do TTY, o que o torna mais simples, mas não tão flexível quanto o udev. Mouses, etc não são suportados. Este driver usa a API mais antiga do joystick (/dev/input/js*)." @@ -1733,6 +1761,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PULSE, "Driver PulseAudio. Se o sistema usa PulseAudio, certifique-se de usar este driver em vez de, por exemplo, ALSA." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PIPEWIRE, + "Driver do PipeWire. Se o sistema usa PipeWire, lembre-se de usar esse driver em vez de e.g. PulseAudio." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_JACK, "Driver de Kit de Conexão Jack Áudio." @@ -1910,10 +1942,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_THREADED, "Melhora o desempenho ao custo de uma maior latência e mais engasgadas no sinal de vídeo. Use apenas caso não seja possível obter a velocidade máxima de outra forma." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_THREADED, + "Use um driver de vídeo multitarefa. Usar isto pode melhorar o desempenho a custo de possível latência e mais travamentos de vídeo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, "Inserção de quadro opaco" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, + "AVISO: Tremulação rápida pode causar persistência de imagem em algumas telas. Use por sua conta em risco // Insira quadro(s) preto(s) entre os quadros. Pode reduzir significativamente o desfoque de movimento emulando a varredura de CRT, mas ao custo do brilho." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, + "Insere quadro(s) preto(s) entre quadros para maior clareza de movimento. Utilize apenas a opção designada para a sua taxa de atualização de exibição atual. Não é para uso em taxas de atualização que não são múltiplos de 60Hz, como 144Hz, 165Hz, etc. Não combine com o intervalo de troca > 1, sub-frames, Delay de Frame ou Sincronizar para Framerate de Conteúdo Exato. Deixar o sistema com o VRR está certo, apenas não está configurado. Se você notar a retenção de imagens em qual[...]" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_120, "1 - Para taxa de atualização de 120Hz" @@ -1934,6 +1978,70 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_360, "5 - Para taxa de atualização de 360Hz" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_420, + "6 - Para taxa de atualização de 420Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_480, + "7 - Para taxa de atualização de 480Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_540, + "8 - Para taxa de atualização de 540Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_600, + "9 - Para taxa de atualização de 600Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_660, + "10 - Para taxa de atualização de 660Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_720, + "11 - Para taxa de atualização de 720Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_780, + "12 - Para taxa de atualização de 780Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_840, + "13 - Para taxa de atualização de 840Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_900, + "14 - Para taxa de atualização de 900Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_960, + "15 - Para taxa de atualização de 960Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BFI_DARK_FRAMES, + "Inserção de Quadros Pretos - Quadros Escuros" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_BFI_DARK_FRAMES, + "Ajuste o número de quadros pretos na sequência total de escaneamento BFI. Mais equivalea maior nitidez, menos é igual a maior brilho. Não se aplica ao 120hz, pois há apenas 1 quadro BFI para trabalhar com o total. As configurações maiores que o possível vão limitar ao máximo possível para a taxa de atualização escolhida." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_BFI_DARK_FRAMES, + "Ajusta o número de quadros exibidos na sequência BFI que são pretos. Mais quadros pretos aumentam a nitidez, mas reduzem o brilho. Não aplicável ao 120hz, pois há apenas um quadro extra de 60hz no total, por isso, deve ser preto, caso contrário o BFI não estaria de modo algum ativa." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES, + "Subquadros de sombreamento" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, + "AVISO: Tremulação rápida pode causar persistência de imagem em algumas telas. Use por sua conta em risco // Simula uma varredura básica sobre vários subquadros dividindo a tela verticalmente e renderizando cada parte da tela de acordo com quantos subquadros há." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, + "Insere quadro(s) preto(s) entre quadros para maior nitidez. Utilize apenas a opção designada para a sua taxa de atualização de exibição atual. Não use em taxas de atualização que não são múltiplos de 60Hz, como 144Hz, 165Hz, etc. Não combine com o intervalo de troca > 1, subquadros, Delay de Frame ou Sincronizar para Framerate de Conteúdo Exato. Deixar o sistema com o VRR está certo, apenas não está configurado. Se você notar a retenção de imagens em qualquer momento, você d[...]" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_120, "2 - Para taxa de atualização de 120Hz" @@ -1966,6 +2074,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_540, "9 - Para taxa de atualização de 540Hz" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_600, + "10 - Para taxa de atualização de 600Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_660, + "11 - Para taxa de atualização de 660Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_720, + "12 - Para taxa de atualização de 720Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_780, + "13 - Para taxa de atualização de 780Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_840, + "14 - Para taxa de atualização de 840Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_900, + "15 - Para taxa de atualização de 900Hz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_960, + "16 - Para taxa de atualização de 960Hz" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, "Habilitar captura de tela da GPU" @@ -1976,7 +2112,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Simula o rolamento básico da linha de varredura em múltiplos sub-quadros, dividindo a tela verticalmente e renderizando cada parte conforme a quantidade de sub-quadros existente." + "AVISO: Tremulação rápida pode causar persistência de imagem em algumas telas. Use por sua conta em risco // Simula uma varredura básica sobre vários subquadros dividindo a tela verticalmente e renderizando cada parte da tela de acordo com quantos subquadros há." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2046,6 +2182,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FILTER, "Aplica um filtro de vídeo processado pela CPU. Afeta muito o desempenho. Alguns filtros de vídeo podem funcionar apenas nos núcleos que usam cores com 32 ou 16 bits." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_FILTER, + "Aplica um filtro de vídeo processado pela CPU. Afeta muito o desempenho. Alguns filtros de vídeo podem funcionar apenas nos núcleos que usam cores com 32 ou 16 bits. Bibliotecas de filtros de vídeo, vinculadas dinamicamente, podem ser selecionadas." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_REMOVE, "Remover o filtro do vídeo" @@ -2054,6 +2194,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FILTER_REMOVE, "Descarregue qualquer filtro de vídeo ativo que utilize processamento da CPU." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_NOTCH_WRITE_OVER, + "Habilitar tela cheia sobre o entalhe (“notch”) em dispositivos Android" +) /* Settings > Video > CRT SwitchRes */ @@ -2116,6 +2260,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, "Selecione qual a tela será usada." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_MONITOR_INDEX, + "Monitor preferido. 0 (padrão) significa que nenhum monitor tem a preferência, 1 e acima (1 sendo primeiro monitor), sugere ao RetroArch para usar esse monitor em particular." + ) #if defined (WIIU) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_WIIU_PREFER_DRC, @@ -2369,6 +2517,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, "Dimensionar com valores inteiros" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_SCALING, + "Arredonde para baixo ou para cima para o próximo inteiro. 'Inteligente' reduzirá a escala quando a imagem é cortada demais." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_UNDERSCALE, + "Reduzir escala" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_OVERSCALE, + "Aumentar escala" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_SMART, "Inteligente" @@ -2393,6 +2553,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_CONFIG, "Configuração" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_SQUARE_PIXEL, + "PAR 1:1 (%u:%u DAR)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_CORE_PROVIDED, "Fornecida pelo núcleo" @@ -2423,6 +2587,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, "Posição Y personalizada da proporção de tela" ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_X, + "Deslocamento do eixo X do ponto de âncora da viewport" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_X, + "Deslocamento do eixo X do ponto de âncora da viewport" + ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_Y, + "Deslocamento do eixo Y do ponto de âncora da viewport" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_BIAS_Y, + "Deslocamento do eixo Y do ponto de âncora da viewport" + ) #if defined(RARCH_MOBILE) #endif MSG_HASH( @@ -2523,6 +2703,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_ADAPTIVE_VSYNC, "A sincronização vertical está ativada até que o desempenho caia abaixo da taxa de atualização alvo. Pode minimizar os travamentos quando o desempenho cai abaixo do tempo real e seja mais eficiente em termos de energia." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, + "Atraso de Quadro" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTO, "Atraso automático de quadro" @@ -2636,10 +2820,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE, "Silenciar todo o áudio no Modo Silencioso." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Silenciar no avanço rápido" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "Silenciar automaticamente o áudio ao usar o avanço rápido." @@ -2899,6 +3079,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, "Ajuste o volume do fluxo de áudio." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_NONE, + "Estado: N/A" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_STOPPED, + "Estado: Parado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING, + "Estado: Reproduzindo" + ) /* Settings > Audio > Menu Sounds */ @@ -2953,6 +3145,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, "Substitua os vínculos da entrada com os vínculos definidos para o núcleo atual." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_REMAP_SORT_BY_CONTROLLER_ENABLE, + "Ordenar remapeamento por controle" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_REMAP_SORT_BY_CONTROLLER_ENABLE, + "Os remapeamento só serão aplicados ao controle ativo no qual foram salvos." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, "Auto configuração" @@ -2962,12 +3162,28 @@ MSG_HASH( "Configura automaticamente os controles que possuem um perfil, estilo Plug-and-Play." ) #if defined(HAVE_DINPUT) || defined(HAVE_WINRAWINPUT) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_NOWINKEY_ENABLE, + "Desativar teclas de atalho do Windows (requer reinício)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_NOWINKEY_ENABLE, "Mantenha as combinações das teclas de atalho dentro do aplicativo." ) #endif #ifdef ANDROID +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SELECT_PHYSICAL_KEYBOARD, + "Selecione teclado físico" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_SELECT_PHYSICAL_KEYBOARD, + "Use este dispositivo como teclado físico e não como um controle." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_INPUT_SELECT_PHYSICAL_KEYBOARD, + "Se RetroArch identificar um teclado como algum tipo de controle, esta configuração pode ser usada para forçar RetroArch ajustar o dispositivo mal identificado como um teclado.\nIsso pode ser útil se você estiver tentando emular um computador em algum dispositivo Android TV e também possuir um teclado físico que pode ser anexado ao dispositivo." + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SENSORS_ENABLE, @@ -3057,22 +3273,27 @@ MSG_HASH( MSG_INPUT_BIND_PRESS, "Pressione uma tecla do teclado, mouse ou controle" ) +MSG_HASH( + MSG_INPUT_BIND_RELEASE, + "Solte todas as teclas e os botões!" + ) +MSG_HASH( + MSG_INPUT_BIND_TIMEOUT, + "Tempo de espera" + ) +MSG_HASH( + MSG_INPUT_BIND_HOLD, + "Segurar" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Modo turbo" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Período do turbo" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "O período (em quadros) onde os botões com o turbo ativados são pressionados." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Ciclo de operação turbo" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "A quantidade de quadros enquanto os botões estiverem pressionados no tempo do turbo. Caso este número seja igual ou maior que o tempo do turbo, os botões nunca serão liberados." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Modo turbo" @@ -3082,20 +3303,20 @@ MSG_HASH( "Selecione o comportamento geral do modo turbo." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Botão padrão de turbo" + MENU_ENUM_LABEL_VALUE_TURBO_MODE_CLASSIC, + "Clássico" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "O botão individual para o modo turbo." + MENU_ENUM_LABEL_VALUE_TURBO_MODE_CLASSIC_TOGGLE, + "Clássico (Alternar)" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Permitir direções turbo dos botões direcionais" + MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON, + "Botão Único (Alternar)" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "Se ativada, as entradas dos direcionais digitais (botões direcionais) podem ser turbo." + MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, + "Botão Único (Segurar)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -3121,6 +3342,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, "Teclas de atalho" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, + "Altera as configurações e as atribuições das teclas de atalho, como ativar o menu durante o jogo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, "Controle da porta %u" @@ -3234,10 +3459,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, "Ativar menu" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Alterna a exibição atual entre menu e conteúdo em execução." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, "Sair (atalho do controle)" @@ -3314,10 +3535,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "Pausar" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Alterna entre os estados pausado ​​e não pausado do conteúdo em execução." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, "Avanço do Quadro" @@ -3484,6 +3701,38 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Inicia ou interrompe o transmissão da sessão atual para uma plataforma de vídeo online." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, + "Reproduzir Replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_PLAY_REPLAY_KEY, + "Reproduzir arquivo de replay do slot selecionado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, + "Gravar replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_RECORD_REPLAY_KEY, + "Gravar arquivo de replay no slot selecionado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, + "Interromper Gravação/Replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_HALT_REPLAY_KEY, + "Interrompe gravação/reprodução do replay atual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, + "Próximo Slot de Replay" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, + "Slot de Replay Anterior" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Captura do mouse (alternar)" @@ -3627,6 +3876,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, "Índice de dispositivo" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_PREFERRED, + "Preferido" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_RESERVED, + "Reservado" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_REMAP_PORT, "Porta mapeada" @@ -3798,6 +4055,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_RUN_AHEAD_UNSUPPORTED, "Núcleo atual é incompatível com a execução antecipada, porque não tem suporte determinístico ao jogo salvo." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUNAHEAD_MODE, + "Executar à frente" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RUN_AHEAD_FRAMES, "Número de quadros para a execução antecipada" @@ -4072,8 +4333,8 @@ MSG_HASH( "Salvar jogo automaticamente" ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Cria automaticamente um jogo salvo quando o conteúdo for fechado. O RetroArch carregará automaticamente este jogo salvo se \"Carregue automaticamente o jogo salvo\" estiver ativado." + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, + "Carregar jogo automaticamente" ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, @@ -4178,6 +4439,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, "Define o nível de registro de eventos para os núcleos. Se o nível do registro enviado por um núcleo for abaixo deste valor, este é ignorado." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY_DEBUG, + "0 (Depuração)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY_WARNING, + "2 (Aviso)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY_ERROR, + "3 (Erro)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOG_TO_FILE, "Registrar em arquivo" @@ -4213,10 +4486,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtrar extensões desconhecidas" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Utilizar o reprodutor de mídia integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrar por núcleo atual" @@ -4225,6 +4494,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Lembrar do último diretório usado" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Utilizar o reprodutor de mídia integrado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Utilizar o visualizador de imagem integrado" + ) /* Settings > Frame Throttle */ @@ -4688,6 +4965,10 @@ MSG_HASH( /* Settings > On-Screen Display > On-Screen Overlay > Overlay Lightgun */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_PORT_ANY, + "Qualquer" + ) /* Settings > On-Screen Display > On-Screen Overlay > Overlay Mouse */ @@ -4977,10 +5258,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "Tamanho da notificações na tela" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Especifique o tamanho da fonte em pontos." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, "Posição X da notificação na tela" @@ -5040,6 +5317,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SETTINGS, "Altera as configurações da aparência da tela do menu." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_APPICON_SETTINGS, + "Ícone do aplicativo" + ) #ifdef _3DS MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_BOTTOM_SETTINGS, @@ -5086,10 +5367,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, "Pausar conteúdo quando o menu estiver ativado" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Pause o conteúdo em execução no momento caso o menu esteja ativo." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, "Retornar ao conteúdo ao usar salvamento" @@ -6135,6 +6412,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR, "Posição" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR_TOPLEFT, + "Superior Esquerdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR_TOPCENTER, + "Centro Superior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR_TOPRIGHT, + "Superior Direito" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR_BOTTOMLEFT, + "Inferior esquerdo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR_BOTTOMCENTER, + "Centro inferior" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR_BOTTOMRIGHT, + "Inferior direito" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_PADDING_AUTO, + "Preenchimento alinhado" + ) /* Settings > Achievements > Visibility */ @@ -6142,6 +6447,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SETTINGS, "Visibilidade" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SUMMARY, + "Resumo de inicialização" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SUMMARY_ALLGAMES, + "Todos os jogos identificados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VERBOSE_ENABLE, + "Mensagens detalhadas" + ) /* Settings > Network */ @@ -6872,7 +7189,11 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Navegador de arquivos" + "Diretório inicial" + ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, + "Arquivos de configuração" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, @@ -7083,10 +7404,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT, "Formato da presença rica do conteúdo" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Define as informações que serão compartilhadas do conteúdo em execução." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT_CONTENT, @@ -7251,6 +7568,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_LIST, "Análise configurável com base nos nomes do conteúdo. Não requer que os conteúdos coincidam ao banco de dados." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SCAN_ENTRY, + "Escanear" + ) /* Import Content > Scan File */ @@ -7747,6 +8068,26 @@ MSG_HASH( MENU_ENUM_SUBLABEL_REPLAY_SLOT, "Altera o compartimento do jogo salvo selecionado atualmente." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAY_REPLAY, + "Reproduzir Replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAY_REPLAY, + "Reproduzir arquivo de replay do slot selecionado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_REPLAY, + "Gravar replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORD_REPLAY, + "Gravar arquivo de replay no slot selecionado." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HALT_REPLAY, + "Interromper Gravação/Replay" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, "Adicionar aos favoritos" @@ -7799,18 +8140,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "Configurações do núcleo" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Altera as opções para o conteúdo que está sendo executado." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "Controles" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Altera os controles para o conteúdo que está sendo executado." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Trapaças" @@ -7895,11 +8228,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Redefinir" + "Redefinir Opções do Núcleo" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Redefine todas as configurações do núcleo para os seus valores padrão." + "Define todas as opções do núcleo atual para os valores padrão." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -8527,6 +8860,26 @@ MSG_HASH( /* Quick Menu > Overrides */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERRIDE_FILE_INFO, + "Arquivo de predefinição ativo" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERRIDE_FILE_INFO, + "O arquivo de predefinição atual está em uso." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERRIDE_FILE_LOAD, + "Carregar arquivo de predefinição" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERRIDE_FILE_LOAD, + "Carregar e substituir configuração atual." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERRIDE_FILE_SAVE_AS, + "Salvar arquivo de predefinição como" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, "Salvar personalizações do núcleo" @@ -8543,6 +8896,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, "Salva um arquivo de configuração que será aplicado a todo o conteúdo carregado no mesmo diretório que o arquivo atual. Terá prioridade sobre a configuração principal." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REMOVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Remover predefinição do diretório de conteúdo" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, "Salvar personalizações de jogo" @@ -9203,6 +9560,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG_FORCED, "Analógico direito (forçado)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_KEY, + "Tecla %s" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_UP, "Roda do mouse para cima" @@ -9330,6 +9691,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_FULL_WIDTH_LAYOUT, "Redimensiona e posiciona as entradas do menu para aproveitar melhor o espaço disponível na tela. Desabilite isso para usar a disposição clássica de duas colunas de largura fixa." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, + "Filtro linear" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_LINEAR_FILTER, "Adiciona um leve desfoque para suavizar arestas dos pixels no menu." @@ -9350,17 +9715,25 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_ASPECT_RATIO, "Seleciona a proporção do menu. As proporções widescreen aumentam a resolução horizontal da interface do menu. (pode exigir uma reinicialização se a opção \"Bloquear proporção de exibição do menu\" estiver desabilitada)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_ASPECT_RATIO_LOCK, + "Bloquear proporção de tela" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_ASPECT_RATIO_LOCK, "Garante que o menu seja sempre exibido com a proporção correta. Se desativado, o menu rápido será esticado para corresponder ao conteúdo atualmente carregado." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_MENU_COLOR_THEME, + "Cor do Tema" + ) MSG_HASH( MENU_ENUM_SUBLABEL_RGUI_MENU_COLOR_THEME, "Define o tema de cores. \"Personalizado\" permite o uso dos arquivos de predefinição de temas." ) MSG_HASH( - MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Habilita o conteúdo executado no fundo do Menu Rápido. Desativar a transparência pode alterar as cores do tema." + MENU_ENUM_LABEL_VALUE_MENU_RGUI_TRANSPARENCY, + "Transparência" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -9477,6 +9850,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_ASPECT_RATIO_16_10_CENTRE, "16:10 (centralizado)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_ASPECT_RATIO_21_9_CENTRE, + "21:9 (centralizado)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_ASPECT_RATIO_3_2_CENTRE, "3:2 (centralizado)" @@ -9732,6 +10109,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_XMB_LAYOUT, "Seleciona uma disposição diferente para a interface XMB." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_THEME, + "Tema dos ícones" + ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_THEME, "Seleciona um tema diferente de ícone para o RetroArch." @@ -9756,6 +10137,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, "Seleciona um efeito de plano de fundo animado. Pode exigir mais processamento gráfico. Se o desempenho for insatisfatório, desligue este efeito ou reverta para um mais simples." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, + "Cor do Tema" + ) MSG_HASH( MENU_ENUM_SUBLABEL_XMB_VERTICAL_THUMBNAILS, "Exibe a miniatura esquerda sob a direita, no lado direito da tela." @@ -9911,6 +10296,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Gelado" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Cinza escuro" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Cinza claro" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -9930,6 +10323,35 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "As listas de reprodução serão reorganizadas em ordem alfabética após remover o componente do fabricante de seus nomes." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Miniatura secundária" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Substitui o painel de metadados do conteúdo por outra miniatura." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Reduzir textos longos dos metadados" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Ao habilitar esta opção, cada elemento dos metadados de um conteúdo a ser exibido na barra direita das listas de reprodução (núcleo associado, tempo de jogo...) vai ocupar apenas uma linha, cadeias que excedem a largura da barra se moverão automaticamente. Desabilitando, cada elemento dos metadados é apresentado estaticamente, estendendo as linhas conforme necessário." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Fator de escala de miniaturas" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Altera o tamanho da barra de miniaturas." + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, + "Cor do Tema" + ) MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, "Define o tema de cores." @@ -9979,30 +10401,11 @@ MSG_HASH( "Chuva Roxa" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Miniatura secundária" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Substitui o painel de metadados do conteúdo por outra miniatura." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Reduzir textos longos dos metadados" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Ao habilitar esta opção, cada elemento dos metadados de um conteúdo a ser exibido na barra direita das listas de reprodução (núcleo associado, tempo de jogo...) vai ocupar apenas uma linha, cadeias que excedem a largura da barra se moverão automaticamente. Desabilitando, cada elemento dos metadados é apresentado estaticamente, estendendo as linhas conforme necessário." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Fator de escala de miniaturas" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Altera o tamanho da barra de miniaturas." + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "Selênio" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -10049,6 +10452,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_AUTO_ROTATE_NAV_BAR, "Move automaticamente a barra de navegação no lado direito da tela na orientação em modo retrato." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, + "Cor do Tema" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_MENU_TRANSITION_ANIMATION, "Habilita os efeitos de animação ao navegar entre diferentes opções de menu." @@ -10395,6 +10802,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, "Tela de título" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_LOGO, + "Logotipo" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, "Todas as listas de reprodução" @@ -10922,10 +11333,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Usuário" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Utilizar o visualizador de imagem integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Máximo de imagens na cadeia de troca" @@ -11049,14 +11456,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Selecionar de uma lista de reprodução" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Continuar" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Continua a execução do conteúdo atual e sai do menu rápido." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Ver lista de %u coincidências" @@ -11631,10 +12030,6 @@ MSG_HASH( MSG_AUTODETECT, "Detectar automaticamente" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Autocarregando jogo salvo de" - ) MSG_HASH( MSG_CAPABILITIES, "Capacidades" @@ -12535,6 +12930,26 @@ MSG_HASH( MSG_ACHIEVEMENT_UNLOCKED, "Conquista desbloqueada" ) +MSG_HASH( + MSG_LEADERBOARD_STARTED, + "Tentativa do ranking iniciou" + ) +MSG_HASH( + MSG_LEADERBOARD_FAILED, + "Tentativa do ranking falhou" + ) +MSG_HASH( + MSG_LEADERBOARD_SUBMISSION, + "Enviado %s para %s" /* Submitted [value] for [leaderboard name] */ + ) +MSG_HASH( + MSG_LEADERBOARD_RANK, + "Classificação: %d" /* Rank: [leaderboard rank] */ + ) +MSG_HASH( + MSG_LEADERBOARD_BEST, + "Melhor: %s" /* Best: [value] */ + ) MSG_HASH( MSG_CHANGE_THUMBNAIL_TYPE, "Alterar o tipo de miniatura" @@ -12619,6 +13034,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Houve uma falha ao fechar a bandeja virtual do disco." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Autocarregando jogo salvo de" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "O carregamento automático do jogo salvo a partir de \"%s\" falhou." @@ -12839,6 +13258,30 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_ENABLE, "Modo Hardcore habilitado: jogos salvos e rebobinamento foram desativados." ) +MSG_HASH( + MSG_CHEEVOS_UNSUPPORTED_COUNT, + "%d não suportado" +) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_MANUAL_FRAME_DELAY, + "Hardcore pausado. Não é permitido definir manualmente o atraso de quadro de vídeo." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_SYSTEM_NOT_FOR_CORE, + "Hardcore pausado. Você não pode ganhar conquistas de hardcore para %s usando %s" + ) +MSG_HASH( + MSG_CHEEVOS_GAME_NOT_IDENTIFIED, + "RetroAchievements: Jogo não pôde ser identificado." + ) +MSG_HASH( + MSG_CHEEVOS_GAME_LOAD_FAILED, + "RetroAchievements: falha ao carregar jogo %s" + ) +MSG_HASH( + MSG_CHEEVOS_CHANGE_MEDIA_FAILED, + "RetroAchievements: falha ao alterar a mídia %s" + ) MSG_HASH( MSG_RESAMPLER_QUALITY_LOWEST, "Muito baixa" @@ -12891,6 +13334,10 @@ MSG_HASH( MSG_MANUAL_CONTENT_SCAN_DAT_FILE_LOAD_ERROR, "Falha ao carregar o arquivo DAT do arcade (o formato é inválido?)" ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_INVALID_CONTENT, + "Nenhum conteúdo válido encontrado." + ) MSG_HASH( MSG_MANUAL_CONTENT_SCAN_START, "Analisando conteúdo: " @@ -13577,10 +14024,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Ativar fonte" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Mostra a fonte do menu inferior. Ative para exibir as descrições dos botões na tela inferior. Não tem compatibilidade com a data do jogo salvo." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Vermelho da fonte" @@ -13636,3 +14079,26 @@ MSG_HASH( MSG_IOS_TOUCH_MOUSE_DISABLED, "Toque do mouse está desabilitado" ) +MSG_HASH( + MSG_AI_SERVICE_STOPPED, + "parado." + ) +#ifdef HAVE_GAME_AI + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "IA do jogo" + ) + + + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Mostrar depuração" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Mostrar depuração" + ) + +#endif diff --git a/intl/msg_hash_pt_pt.h b/intl/msg_hash_pt_pt.h index c34d6541db..e189e88011 100644 --- a/intl/msg_hash_pt_pt.h +++ b/intl/msg_hash_pt_pt.h @@ -195,7 +195,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, - "Sair" + "Encerrar" ) MSG_HASH( MENU_ENUM_SUBLABEL_QUIT_RETROARCH, @@ -495,6 +495,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_REQUIRED_HW_API, "API de Gráficos Necessária" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_PATH, + "Caminho Completo" +) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SUPPORT_LEVEL, "Posição de gravação de estado" @@ -519,6 +523,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_IN_CONTENT_DIRECTORY, "- Nota: A opção \"Ficheiros do Sistema estão na Pasta de Conteúdos\" está atualmente ativada." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_PATH, + "- A procurar em: '%s" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MISSING_REQUIRED, "Em falta, Requerido:" @@ -543,6 +551,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LOCK, "Previne que o núcleo atualmente instalado seja modificado. Pode ser usado para evitar atualizações indesejadas quando o conteúdo requer uma versão específica do núcleo (por exemplo, conjuntos de ROM Arcade)." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_SET_STANDALONE_EXEMPT, + "Excluir do menu 'Núcleos sem conteúdo'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_SET_STANDALONE_EXEMPT, + "Impede que este núcleo seja exibido na aba/menu 'Núcleos sem conteúdo'. Aplica-se somente quando o modo de exibição é definido como 'Personalizado'." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_DELETE, "Remover núcleo" @@ -694,6 +710,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "Suporte a SDL2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Suporte a Direct3D 8" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Suporte a Direct3D 9" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Suporte a Direct3D 10" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Suporte a Direct3D 11" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Suporte a Direct3D 12" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "Suporte a GDI" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Suporte a Vulkan" @@ -774,6 +814,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "Suporte a PulseAudio" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "Suporte para PipeWire" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "Suporte a CoreAudio" @@ -854,6 +898,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Suporte a Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Suporte SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Suporte a libusb" @@ -916,6 +964,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CONTROLS, "Mapeamento de teclas" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ARTSTYLE, + "Estilo de arte" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GAMEPLAY, "Jogabilidade" @@ -924,10 +976,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NARRATIVE, "Narrativa" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PACING, + "Ritmo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PERSPECTIVE, + "Perspectiva" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SETTING, "Definição" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_VEHICULAR, + "Veicular" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, "Editora" @@ -964,6 +1028,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, "Edição da revista Edge" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, + "Mês de lançamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, + "Ano de lançamento" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, "Classificação BBFC" @@ -1011,18 +1083,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, "Carregar configuração" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIGURATIONS, + "Carregar configuração existente e substituir os valores atuais." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, "Guardar configuração atual" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG, + "Substituir o arquivo de configuração atual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, "Guardar nova configuração" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_NEW_CONFIG, + "Salvar a configuração atual em arquivo separado." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESET_TO_DEFAULT_CONFIG, "Repor os valores padrão" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESET_TO_DEFAULT_CONFIG, + "Repor todas as configurações para os valores padrão." + ) /* Main Menu > Help */ @@ -1084,6 +1172,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, "Áudio" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, + "Modificar as definições de saída de som." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, "Entrada" @@ -1124,14 +1216,94 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SAVING_SETTINGS, "Modificar as definições de gravação." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SETTINGS, + "Sincronização na Nuvem" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SETTINGS, + "Modificar as definições de sincronização na Nuvem." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_ENABLE, + "Ativar sincronização na Nuvem" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_ENABLE, + "Tentativa de sincronizar configurações, sram e estados para um provedor de armazenamento na Nuvem." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DESTRUCTIVE, + "Sincronia de Nuvem Destrutiva" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_SAVES, + "Sincronização: Salvas/Estados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_CONFIGS, + "Sincronização: Ficheiros de configuração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_THUMBS, + "Sincronização: Imagens em Miniaturas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_SYSTEM, + "Sincronização: Arquivos do Sistema" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_SAVES, + "Quando ativado, salvar/estados serão sincronizados para a nuvem." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_CONFIGS, + "Quando ativado, os arquivos de configuração serão sincronizados para a nuvem." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_THUMBS, + "Quando ativado, as miniaturas serão sincronizadas para a nuvem. Não é geralmente recomendado, exceto para grandes coleções de imagens em miniatura personalizadas; caso contrário, o transferidor de miniaturas é uma escolha melhor." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_SYSTEM, + "Quando ativado, os arquivos do sistema serão sincronizados para a nuvem. Isto pode aumentar significativamente o tempo necessário para sincronizar; usar com cuidado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_DESTRUCTIVE, + "Quando desativado, os arquivos são movidos para uma pasta de backup antes de serem substituídos ou excluídos." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DRIVER, + "Sincronização da nuvem Backend" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_DRIVER, + "Qual protocolo de rede de armazenamento na nuvem a usar." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_URL, + "URL de armazenamento da Nuvem" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_URL, + "A URL para a entrada de API aponta para o serviço de armazenamento em nuvem." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_USERNAME, "Utilizador" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_USERNAME, + "Nome de utilizador para a conta de armazenamento na nuvem." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_PASSWORD, "Palavra-passe" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_PASSWORD, + "Senha para a conta de armazenamento na nuvem." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, "Registo" @@ -1144,10 +1316,90 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, "Explorador de ficheiros" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, + "Alterar definições do explorador de ficheiros." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CONFIG, + "Ficheiros de configuração." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_COMPRESSED_ARCHIVE, + "Arquivo comprimido." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_RECORD_CONFIG, + "A gravar arquivo de configuração." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CURSOR, + "Arquivo do cursor do banco de dados." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_CONFIG, + "Ficheiros de configuração." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_SHADER_PRESET, + "Arquivo de predefinição de sombreado." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_SHADER, + "Arquivo shader." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_REMAP, + "Remap do arquivo de controle." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CHEAT, + "Arquivo de cheat." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_OVERLAY, + "Arquivo de Overlay." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_RDB, + "Arquivo de banco de dados." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_FONT, + "Arquivo de fonte TrueType." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_FILE_BROWSER_PLAIN_FILE, "Ficheiro simples." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_MOVIE_OPEN, + "Vídeo. Selecione para abrir este arquivo com o reprodutor de vídeo." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_MUSIC_OPEN, + "Vídeo. Selecione para abrir este arquivo com o reprodutor de música." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_IMAGE, + "Arquivo de imagem." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_IMAGE_OPEN_WITH_VIEWER, + "Imagem. Selecione para abrir este arquivo com o reprodutor de imagem." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CORE_SELECT_FROM_COLLECTION, + "Núcleo Libretro. Selecionar isto irá associar este núcleo ao jogo." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CORE, + "Núcleo Libretro. Selecione este arquivo para que o RetroArch carregue este núcleo." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_DIRECTORY, + "Diretório. Selecione-o para abrir este diretório." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, "Aceleração de fotogramas" @@ -1246,12 +1498,44 @@ MSG_HASH( ) /* Core option category placeholders for icons */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MAPPING_SETTINGS, + "Mapeamento" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MEDIA_SETTINGS, "Mídia" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PERFORMANCE_SETTINGS, + "Desempenho" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SOUND_SETTINGS, + "Som" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SPECS_SETTINGS, + "Especificações" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STORAGE_SETTINGS, + "Armazenamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_SETTINGS, + "Sistema" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMING_SETTINGS, + "Temporizador" + ) #ifdef HAVE_MIST +MSG_HASH( + MENU_ENUM_SUBLABEL_STEAM_SETTINGS, + "Alterar configurações relacionadas à Steam." + ) #endif /* Settings > Drivers */ @@ -1268,10 +1552,22 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_INPUT_DRIVER_UDEV, "O driver udev lê eventos evdev para suporte de teclado. Ele também suporta callback de teclado, ratos e touchpads.\nPor padrão na maioria das distribuições, os nós /dev/input são apenas para root (modo 600). Pode configurar uma regra udev que os torna acessíveis a quem não é root." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_INPUT_DRIVER_LINUXRAW, + "O driver de entrada linuxraw requer uma TTY. Os eventos do teclado são lidos diretamente do TTY, o que o torna mais simples, mas não tão flexível quanto o udev. \"Mice, etc, não é suportado. Este driver usa a API mais antiga do joystick (/dev/input/js*)." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_INPUT_DRIVER_NO_DETAILS, + "Controlador de entrada. Dependendo do controlador de vídeo, pode forçá-lo a um controlador de entrada diferente." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, "Comando" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, + "Controlador para usar. (Requerer reiniciar)" + ) MSG_HASH( MENU_ENUM_LABEL_HELP_JOYPAD_DRIVER_DINPUT, "Controlador de DirectInput." @@ -1309,6 +1605,98 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_DRIVER, "Driver de vídeo a ser usado." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_GL1, + "Driver OpenGL 1.x. Versão mínima necessária: OpenGL 1.1. Não suporta shaders. Use drivers OpenGL mais antigos, se possível." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_GL, + "Driver OpenGL 2.x. Este driver permite que núcleos de libretro GL sejam utilizados além de núcleos renderizados por software. Versão mínima necessária: OpenGL 2.0 ou OpenGLES 2.0. Suporta o formato de shader GLSL. Use o driver glcore em vez disso, se possível." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_GL_CORE, + "Driver OpenGL 3.x. Este driver permite que núcleos de libretro GL sejam utilizados além de núcleos renderizados por software. Versão mínima necessária: OpenGL 3.2 ou OpenGLES 3.0. Suporta o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_VULKAN, + "Driver Vulkan. Este driver permite que núcleos de libretro Vulkan sejam utilizados além de núcleos renderizados por software. Versão mínima necessária: Vulkan 1.0. Suporta HDR e shaders Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_SDL1, + "Driver renderizado para o SDL 1.2. Desempenho é considerado como abaixo do ideal. Considere usá-lo apenas como último recurso." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_SDL2, + "Driver renderizado para o SDL 2. Performance para implementações libretro core renderizado é dependente da implementação de SDL da sua plataforma." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_METAL, + "Driver Metal para plataformas Apple. Suporta o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D8, + "Driver Direct3D 8 sem suporte de shader." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D9_CG, + "Driver Direct3D 9 com suporte para o formato antigo de shader Cg." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D9_HLSL, + "Driver Direct3D 9 com suporte para o formato shader HLSL." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D10, + "Driver Direct3D 10 com suporte para o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D11, + "Driver Direct3D 11 com suporte para o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D12, + "Driver Direct3D 12 com suporte para HDR e o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_DISPMANX, + "Driver DispmanX. Usa a API DispmanX para o Videocore IV GPU no Raspberry Pi 0..3. Não há suporte para sobreposição ou shader." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_CACA, + "Driver LibCACA. Produz a saída de caracteres em vez de gráficos. Não recomendado para uso prático." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_EXYNOS, + "Um driver de vídeo Exynos de baixo nível que usa o bloco G2D em Samsung Exynos SoC para operações blit. O desempenho para núcleos renderizados de software deve ser ideal." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_DRM, + "Driver de vídeo DRM simples. Este é um driver de vídeo de baixo nível usando libdrm para escalar hardware usando camadas de GPU." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_SUNXI, + "Um driver de vídeo Sunxi de baixo nível que usa o bloco G2D em Allwinner SoCs." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_WIIU, + "Driver Wii U. Suporta shaders Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_SWITCH, + "Driver Switch. Suporta o formato de shader GLSL." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_VG, + "Driver OpenVG. Usa API de gráficos para vetores 2D acelerados por hardware OpenVG." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_GDI, + "Driver GDI. Usa uma interface legada para Windows. Não recomendado." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_NO_DETAILS, + "Driver de vídeo atual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, "Áudio" @@ -1317,6 +1705,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_DRIVER, "Driver de áudio a ser usado." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_RSOUND, + "Driver RSound para sistemas de áudio em rede." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_OSS, + "Driver de Sistema de Som Aberto Legado." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_ALSA, + "Driver ALSA padrão." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_SL, "Driver OpenSL." @@ -1442,10 +1842,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, "Inserção de frame preto" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Inserir fotograma(s) preto(s) entre fotogramas. Pode reduzir significativamente a desfocagem de movimento ao emular a varrimento CRT, mas à custa do brilho. Não combinar com Intervalo de troca > 1, subfotogramas, Atraso de fotogramas ou Sincronizar com a frequência exata do conteúdo." - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, "Insere fotograma(s) preto(s) entre os fotogramas para maior nitidez do movimento. Utilize apenas a opção designada para a taxa de atualização do seu ecrã atual. Não deve ser utilizada em taxas de atualização que não sejam múltiplos de 60 Hz, como 144 Hz, 165 Hz, etc. Não combinar com Intervalo de troca > 1, subfotogramas, Atraso de fotogramas, ou Sincronizar com a frequência de fotogramas exata do conteúdo. Deixar o VRR do sistema ligado é aceitável, mas não esta definição. Se [...]" @@ -1526,10 +1922,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES, "Subfotogramas de sombreamento" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Insere fotograma(s) de sombreador extra entre fotogramas. Permite que os sombreadores façam efeitos que funcionem a um fps mais elevado do que a taxa de conteúdo atual. Deve ser definido para o Hz do ecrã atual. Não combinar com Intervalo de troca > 1, BFI, Atraso de fotogramas ou Sincronizar com a frequência de fotogramas exata do conteúdo." - ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, "Insere fotograma(s) de sombreador extra entre fotogramas para quaisquer efeitos de sombreador possíveis que tenham sido concebidos para serem executados mais rapidamente do que a taxa de conteúdo. Utilize apenas a opção designada para a taxa de atualização do seu ecrã atual. Não deve ser usada em taxas de atualização que não sejam múltiplos de 60 Hz, como 144 Hz, 165 Hz, etc. Não combinar com Intervalo de troca > 1, BFI, Atraso de fotogramas ou Sincronizar com a frequência de fotog[...]" @@ -2249,6 +2641,7 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, "Quantidade de segundos a aguardar até que seja feita uma nova associação." ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Período do turbo" @@ -2499,10 +2892,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT, "Botão direcional (direita) da pistola" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "Ativar Turbo" - ) /* Settings > Latency */ @@ -2645,14 +3034,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Extensões de filtro desconhecidas" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usar o reprodutor multimédia integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrar pelo núcleo atual" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Usar o reprodutor multimédia integrado" + ) /* Settings > Frame Throttle */ @@ -2865,10 +3254,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "Tamanho das notificações no ecrã" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Especifique o tamanho da fonte em pontos." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, "Notificação no ecrã da posição X" @@ -3352,7 +3737,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Explorador de ficheiros" + "Pasta inicial" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, @@ -3551,10 +3936,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "Retomar" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Retomar a execução do conteúdo atual e deixar o 'Menu rápido'." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, "Reiniciar" @@ -3603,18 +3984,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, "Se o estado foi sobrescrito, ele voltará ao estado de gravação anterior." ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Altera as opções para a execução de conteúdo atual." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "Mapeamento de teclas" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Altera as teclas para a execução de conteúdo atual." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Batota" @@ -4231,6 +4604,8 @@ MSG_HASH( "Quando ativado, cada item de metadados de conteúdo apresentado na barra lateral direita das listas de reprodução (núcleo associado, tempo de reprodução) ocupará uma única linha, e as cadeias que excedam a largura disponível serão automaticamente deslocadas. Quando desativado, cada item de metadados será exibido estaticamente, ocupando tantas linhas quantas forem necessárias." ) + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -4561,14 +4936,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Selecionar da Lista de Reprodução" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Retomar" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Retomar a execução do conteúdo atual e sair do 'Menu rápido'." - ) MSG_HASH( /* FIXME Still exists in a comment about being removed */ MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, "Opacidade do rodapé" @@ -4835,10 +5202,6 @@ MSG_HASH( MSG_AUTODETECT, "Auto-detetar" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto-carregar estado da gravação de" - ) MSG_HASH( MSG_CAPABILITIES, "Funcionalidades" @@ -5555,6 +5918,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "Falha no cálculo do tamanho da janela de visualização! Continuarão a serem utilizados dados em bruto. Provavelmente, irão surgir erros ..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Auto-carregar estado da gravação de" + ) MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, "Não configurado" @@ -5860,3 +6227,10 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "parado." ) +#ifdef HAVE_GAME_AI + + + + + +#endif diff --git a/intl/msg_hash_ro.h b/intl/msg_hash_ro.h index b960f0acc4..ec36df9ebe 100644 --- a/intl/msg_hash_ro.h +++ b/intl/msg_hash_ro.h @@ -134,6 +134,7 @@ #ifdef ANDROID #endif + /* Settings > Input > Haptic Feedback/Vibration */ @@ -415,6 +416,8 @@ /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -463,4 +466,11 @@ #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index 0b2dbe3ed3..851fca550e 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Выберите ядро для запуска." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Выгрузить ядро" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Выгружает загруженное ядро." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Выбор ядра libretro. Браузер открывает путь, заданный для каталога 'Ядра'. Если он пуст, обзор начинается в корне.\nЕсли каталог ядер является директорией, она исп. как папка верхнего уровня. Если каталог ядер это абсолютный путь, то браузер открывает папку расположения файла." @@ -914,6 +922,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Поддержка Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Поддержка SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Поддержка libusb" @@ -1454,11 +1466,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_SETTINGS, - "AI-сервис" + "ИИ-сервис" ) MSG_HASH( MENU_ENUM_SUBLABEL_AI_SERVICE_SETTINGS, - "Настройки AI-сервиса (перевод, синтез речи и т.д.)." + "Настройки ИИ-сервиса (перевод, синтез речи и др.)." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCESSIBILITY_SETTINGS, @@ -1968,7 +1980,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Вставляет чёрный кадр(ы) между кадрами. Может существенно уменьшить размытие путём эмуляции развёртки ЭЛТ, но снижает яркость. Не включайте одновременно с интервалом обновления > 1, подкадрами, задержкой кадра или синхронизацией с кадровой частотой контента." + "ВНИМАНИЕ: быстрое мерцание на некоторых дисплеях может приводить к остаточному изображению. Используйте с осторожностью // Вставляет между кадрами кадр(ы) чёрного цвета. Может существенно уменьшить размытие, эмулируя развёртку ЭЛТ, но снижает яркость." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2052,7 +2064,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Вставляет между кадрами дополнительный кадр(ы) шейдера. Позволяет шейдерам выводить эффекты с кадровой частотой выше исходной частоты контента. Значение должно соответствовать действующей частоте экрана. Не включайте одновременно с интервалом обновления > 1, вставкой чё[...]" + "ВНИМАНИЕ: быстрое мерцание на некоторых дисплеях может приводить к остаточному изображению. Используйте с осторожностью // Имитирует простую плавающую строку развёртки поверх нескольких подкадров, разделяя экран по вертикали и отрисовывая каждую часть исходя из числа п[...]" ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2128,7 +2140,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Имитирует простую плавающую строку развёртки поверх нескольких подкадров путём деления экрана по вертикали и отрисовки каждой его части исходя из количества подкадров." + "ВНИМАНИЕ: быстрое мерцание на некоторых дисплеях может приводить к остаточному изображению. Используйте с осторожностью // Имитирует простую плавающую строку развёртки поверх нескольких подкадров, разделяя экран по вертикали и отрисовывая каждую часть исходя из числа п[...]" ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2563,7 +2575,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Изменять масштаб только по высоте или по высоте и ширине. Значения в полшага применяются к источникам высокого разрешения." + "Изменять масштаб по высоте, ширине или по высоте и ширине. Значения в полшага применяются только к источникам высокого разрешения." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2661,11 +2673,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Установка смещения области просмотра по горизонтали (если ширина превышает высоту контента). 0.0 соответствует левому краю, 1.0 - правому." + "Положение контента по горизонтали, если область вывода превышает ширину контента. 0.0 слева, 0.5 по центру, 1.0 справа." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Установка смещения области просмотра по вертикали (если высота превышает высоту контента). 0.0 соответствует левому краю, 1.0 - правому." + "Положение контента по вертикали, если область вывода превышает высоту контента. 0.0 сверху, 0.5 по центру, 1.0 снизу." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2686,11 +2698,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Установка смещения области просмотра по горизонтали (если ширина превышает высоту контента). 0.0 соответствует левому краю, 1.0 - правому. Для портретного режима." + "Положение контента по горизонтали, если область вывода превышает ширину контента. 0.0 слева, 0.5 по центру, 1.0 справа (портретная ориентация)." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Установка смещения области просмотра по вертикали (если высота превышает высоту контента). 0.0 соответствует левому краю, 1.0 - правому. Для портретного режима." + "Положение контента по вертикали, если область вывода превышает высоту контента. 0.0 сверху, 0.5 по центру, 1.0 снизу (портретная ориентация)." ) #endif MSG_HASH( @@ -2934,23 +2946,31 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE, - "Приглушать все звуки в беззвучном режиме." + "Заглушать аудио в беззвучном режиме." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Заглушать при ускорении" + "Заглушать звук при перемотке вперёд" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, - "Автоматически заглушать звук при ускоренной перемотке." + "Автоматически заглушать аудио при перемотке вперёд." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Ускорять при перемотке вперёд" + "Ускорять звук при перемотке вперёд" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, - "Ускорять звук при перемотке вперёд. Предотвращает искажения, но смещает высоту звука." + "Ускорять аудио при использовании перемотки вперёд. Предотвращает треск, но изменяет высоту звука." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Заглушать звук при перемотке назад" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Автоматически заглушать аудио при обратной перемотке." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, @@ -3497,21 +3517,34 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Удерживайте" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Турбо-кнопки" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "При отключении действие всех турбо-кнопок остановлено." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Период турбо" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Длительность нажатия турбо-кнопок (в кадрах)." + "Интервал в кадрах, в течение которого турбо-кнопки нажаты." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, "Цикл действия турбо" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Количество кадров в периоде турборежима, в течение которых кнопки будут нажаты. Если данное значение больше или равно периоду турбо, кнопки будут нажаты постоянно." + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, + "Количество кадров в периоде турборежима, когда кнопки остаются нажатыми. Если это значение больше или равно периоду турбо, кнопки будут нажаты постоянно." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Полпериода" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, @@ -3539,35 +3572,43 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Классический режим, две кнопки для срабатывания. Удерживая кнопку действия однократно нажмите кнопку Турбо, чтобы запустить цикл нажать-отпустить. Кнопку Турбо можно назначить в Настройки/Ввод/Привязки порта 1." + "Классический режим, две кнопки для срабатывания. Однократно нажмите активатор турбо, удерживая кнопку действия для запуска цикла нажать-отпустить. Активатор турбо можно назначить в Настройки/Ввод/Привязки порта X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Классический режим, две кнопки для срабатывания. Удерживая кнопку действия однократно нажмите кнопку Турбо. Повторно нажмите кнопку Турбо, удерживая кнопку действия для откл. турбо. Кнопку Турбо можно назначить в Настройки/Ввод/Привязки порта 1." + "Классический режим переключения, две кнопки для срабатывания. Однократно нажмите активатор турбо, удерживая кнопку действия. Для отключения повторно нажмите активатор турбо, удерживая кнопку действия. Активатор турбо можно назначить в Настройки/Ввод/Привязки порта X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Режим переключения. Однократно нажмите кнопку Турбо, чтобы запустить цикл нажать-отпустить для выбранной по умолчанию кнопки. Для откл. нажмите кнопку Турбо повторно. Кнопку Турбо можно назначить в Настройки/Ввод/Привязки порта 1." + "Режим переключения. Однократно нажмите активатор турбо, чтобы запустить цикл нажать-отпустить для выбранной по умолчанию турбо-кнопки. Нажмите повторно для отключения. Активатор турбо можно назначить в Настройки/Ввод/Привязки порта X." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Режим с удержанием. Пока зажата кнопка Турбо, для кнопки по умолчанию действует цикл нажать-отпустить. Кнопку Турбо можно назначить в Настройки/Ввод/Привязки порта 1. Для эмуляции автом. огня привяжите Турбо и кнопку по умолчанию к одной кнопке стрельбы геймпада." + "Режим удержания. Цикл нажать-отпустить для выбранной по умолчанию кнопки действует до тех пор, пока удерживается турбо-кнопка. Активатор турбо можно назначить в Настройки/Ввод/Привязки порта X. Для эмуляции автом. огня назначьте активатор и турбо-кнопку на одну и ту же кноп[...]" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Турбо-кнопка по умолчанию" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Активатор турбо" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Кнопка действия, используемая с режимами турбо 'Одна кнопка'." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "Привязка RetroPad для активации турбо-режима. При пустом значении используется привязка, заданная для порта." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Разрешать турбо для диагоналей D-Pad" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Турбо-кнопка" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, - "При включении разрешает турбо для нажатий цифровых диагоналей." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "Целевая турбо-кнопка, используемая в режимах 'Одна кнопка'." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Разрешить турбо для d-pad" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, + "При включении позволяет использовать турбо для цифровых кнопок направлений (известных как d-pad или крестовина)." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, @@ -3575,7 +3616,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Настройки турбо-кнопок.\nПримечание: для работы функции требуется привязать турбо-кнопку к устройству ввода в соответствующем меню 'Привязки порта X'." + "Настройка параметров турбо." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3772,7 +3813,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Переключает экран между отображением меню и запущенным контентом." + "Переключение между отображением меню и контентом." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3852,7 +3893,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Приостанавливает или возобновляет текущий контент." + "Переключение между приостановкой и выполнением контента." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -4060,6 +4101,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Понижает номер текущего слота повтора." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Турбо (переключение)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Включает/выключает режим турбо." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Захват мыши (переключение)" @@ -4152,11 +4201,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE, - "AI-сервис" + "ИИ-сервис" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE, - "Захватывает изображение текущего контента для перевода и/или озвучивает любой текст на экране. 'AI-сервис' должен быть включен и настроен." + "Захватывает изображение запущенного контента для перевода и/или озвучивает текст на экране. ИИ-сервис должен быть включен и настроен." ) MSG_HASH( @@ -4448,7 +4497,7 @@ MSG_HASH( "Пистолет D-Pad вправо" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, "Турбо" ) @@ -4581,7 +4630,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Разрешить обход возможностей быстрых сохранений в свойствах ядра, позволяя экспериментировать со связанными функциями (забегание, обратная перемотка и т.д.)." + "Разрешает игнорировать возможности быстрых сохранений в описании ядер, позволяя экспериментировать со связанными функциями (забегание, обратная перемотка и т.д.)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4825,7 +4874,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Автоматически создавать сохранение при закрытии контента. RetroArch будет автоматически загружать данное сохранение, если включена 'Автозагрузка сохранений'." + "Автоматически сохранять состояние при закрытии контента. Данное сохранение будет загружено при запуске, если включена опция 'Автозагрузка сохранения'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -5005,14 +5054,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Фильтровать файлы в браузере файлов по поддерживаемым расширениям." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Встроенный медиаплеер" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Фильтрация по текущему ядру" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Фильтровать отображаемые в браузере файлы по текущему ядру." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Запоминать путь к начальному каталогу" @@ -5021,6 +5070,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "При загрузке контента открывать браузер файлов в последнем использованном каталоге. Путь будет сброшен к стандартному значению при перезапуске RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Встроенный медиаплеер" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Встроенный просмотр изображений" + ) /* Settings > Frame Throttle */ @@ -5829,6 +5886,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Уведомление о подключении устройства ввода" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Уведомление об ошибке настройки устройств ввода" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Уведомление о загрузке чит-кодов" @@ -5839,7 +5900,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_PATCH_APPLIED, - "Уведомление о патче" + "Уведомление о применении патча" ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_PATCH_APPLIED, @@ -5849,6 +5910,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Отображать сообщение при подключении/отключении устройств ввода." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Отображать сообщение при невозможности настроить устройство ввода." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Уведомление о загрузке раскладок управления" @@ -5983,7 +6048,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Установка размера шрифта уведомлений." + "Устанавливает размер шрифта в пунктах. При включении виджетов значение размера применяется только для отображаемой на экране статистики." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6140,7 +6205,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Приостанавливать запущенный контент при вызове меню." + "Приостанавливать контент при вызове меню." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6501,7 +6566,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Показывать плейлисты (требуется перезапуск для Ozone/XMB)" + "Показывать опцию 'Плейлисты' в главном меню. Игнорируется в GLUI, если включены вкладки плейлистов и панель навигации." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Показывать вкладки плейлистов" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Показывать плейлисты на вкладках. Не влияет на RGUI. Для GLUI должна быть включена панель навигации. Требуется перезапуск для Ozone/XMB." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6931,11 +7004,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_AI_SERVICE, - "Показывать 'AI-сервис'" + "Показывать 'ИИ-сервис'" ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_AI_SERVICE, - "Показывать настройки 'AI-сервиса'." + "Показывать настройки 'ИИ-сервиса'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_ACCESSIBILITY, @@ -6981,14 +7054,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Показывать 'Пользователь'" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Значки в плейлистах" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Тип иконки, отображаемый для плейлиста." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Показать настройки 'Пользователя'." @@ -7118,7 +7183,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_MODE, - "Режим вывода для AI-сервиса" + "Режим вывода ИИ-сервиса" ) MSG_HASH( MENU_ENUM_SUBLABEL_AI_SERVICE_MODE, @@ -7126,7 +7191,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_URL, - "Сетевой адрес AI-сервиса" + "Сетевой адрес ИИ-сервиса" ) MSG_HASH( MENU_ENUM_SUBLABEL_AI_SERVICE_URL, @@ -7134,11 +7199,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_ENABLE, - "Вкл. AI-сервис" + "Вкл. ИИ-сервис" ) MSG_HASH( MENU_ENUM_SUBLABEL_AI_SERVICE_ENABLE, - "Запуск AI-сервиса при нажатии горячей клавиши." + "Включает запуск ИИ-сервиса при нажатии горячей клавиши." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_PAUSE, @@ -7396,7 +7461,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_LBOARD_SUBMIT, - "Показывать значение, отправленное при успешной попытке войти в таблицу лидеров." + "Показывает значение, отправляемое при успешном занесении в таблицу лидеров." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_LBOARD_CANCEL, @@ -7953,11 +8018,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "Сверять CRC при сканировании возможных дублей" + "Сканировать с CRC для исключения повторов" ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, - "Иногда серийные номера образов дублируются, в частности для игр PSP/PSN. При сканировании только по серийным номерам возможна привязка контента к неправильной системе. Опция добавляет проверку CRC, которая ощутимо замедляет сканирование, но повышает его точность." + "Некоторые образы могут иметь одинаковый серийный номер, в частности игры PSP/PSN. Сканирование только по серийным номерам может соотносить контент с неправильной системой. Опция добавляет проверку CRC, которая существенно замедляет сканирование, но делает его точней." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LIST, @@ -8059,11 +8124,11 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, - "Конфиденциальность" + "Приватность" ) MSG_HASH( MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, - "Настройки конфиденциальности." + "Настройки приватности." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, @@ -8216,7 +8281,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Браузер файлов" + "Начальный каталог" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8461,7 +8526,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Выбор передаваемой информации о запущенном контенте." + "Выбор передаваемой информации о контенте." ) MSG_HASH( @@ -9061,7 +9126,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Закрыть быстрое меню и возобновить текущий контент." + "Закрыть быстрое меню и возобновить контент." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -9077,7 +9142,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Закрывает текущий контент. Несохранённые данные могут быть утеряны." + "Закрыть контент. Может привести к потере несохранённых данных." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9213,7 +9278,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Настройка опций для загруженного контента." + "Изменение настроек для контента." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9221,7 +9286,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Настройка управления для текущего контента." + "Изменение управления для контента." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9319,11 +9384,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Сбросить опции" + "Сбросить опции ядра" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Возврат опций ядра к стандартным значениям." + "Сброс всех опций текущего ядра к значениям по умолчанию." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9847,7 +9912,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Отслеживать изменения в файлах шейдера. После сохранения изменений шейдера в память, он будет автоматически перекомпилирован и применён к запущенному контенту." + "Отслеживать изменения в файлах шейдера. При сохранении изменений шейдера в память он автоматически будет повторно скомпилирован и применён к контенту." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10184,11 +10249,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_ACHIEVEMENT_SERVER_UNREACHABLE, - "Одно или несколько открытых достижений не были обработаны сервером. Попытки будут продолжаться до выхода из приложения." + "Одно или более открытых достижений не были переданы на сервер. Попытки будут продолжены до выхода из приложения." ) MSG_HASH( MENU_ENUM_LABEL_CHEEVOS_SERVER_DISCONNECTED, - "Нет связи с сервером RetroAchievements. Попытки будут продолжаться до выхода из приложения." + "Сервер RetroAchievements недоступен. Попытки будут продолжены до успешной отправки или до закрытия приложения." ) MSG_HASH( MENU_ENUM_LABEL_CHEEVOS_SERVER_RECONNECTED, @@ -10312,6 +10377,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Переключить эскизы" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Случайный выбор" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Назад" @@ -11072,7 +11141,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Отображать в фоне запущенный контент при вызове быстрого меню. Отключение прозрачности может изменить цвета темы." + "Включить отображение контента в фоне при вызове быстрого меню. Отключение прозрачности может влиять на цвета темы." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11368,6 +11437,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Тип миниатюры для отображения слева." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Иконка миниатюр" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Тип отображаемой в плейлистах иконки миниатюр." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Динамические обои" @@ -11635,6 +11712,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDGAR, "Мидгар" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Тёмно-серая" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Светло-серая" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11662,46 +11747,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Плейлисты будут пересортированы в алфавитном порядке после удаления названий компаний." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, - "Цветовая тема" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, - "Выбор другой цветовой темы." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_WHITE, - "Базовая белая" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_BLACK, - "Базовая чёрная" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRUVBOX_DARK, - "Gruvbox тёмная" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, - "Селен" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, - "Solarized тёмная" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_LIGHT, - "Solarized светлая" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRAY_DARK, - "Тёмно-серая" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRAY_LIGHT, - "Светло-серая" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, "Дополнительный эскиз" @@ -11727,6 +11772,48 @@ MSG_HASH( "Изменяет размер области миниатюр." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, + "Цветовая тема" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_MENU_COLOR_THEME, + "Выбор другой цветовой темы." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_WHITE, + "Базовая белая" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BASIC_BLACK, + "Базовая чёрная" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRUVBOX_DARK, + "Gruvbox тёмная" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, + "Solarized тёмная" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_LIGHT, + "Solarized светлая" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRAY_DARK, + "Тёмно-серая" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRAY_LIGHT, + "Светло-серая" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "Селен" + ) + + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -12690,10 +12777,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Клавиатура" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Встроенный просмотр изображений" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Максимум изображений в свопчейне" @@ -12829,14 +12912,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Выбрать из плейлиста" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Продолжить" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Закрыть быстрое меню и возобновить текущий контент." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Просмотр списка %u совпадений" @@ -13308,7 +13383,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_NOT_RETROARCH, - "Попытка соединения не удалась, т.к. у пользователя не запущен RetroArch или используется устаревшая версия RetroArch." + "Попытка соединения не удалась, т.к. на стороне peer'а не запущен RetroArch или используется устаревшая версия." ) MSG_HASH( MSG_NETPLAY_OUT_OF_DATE, @@ -13431,10 +13506,6 @@ MSG_HASH( MSG_AUTODETECT, "Автоопределение" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Автозагрузка сохранения из" - ) MSG_HASH( MSG_CAPABILITIES, "Возможности" @@ -13833,7 +13904,7 @@ MSG_HASH( ) MSG_HASH( MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, - "Не удалось выделить память для пропатченного содержимого ..." + "Не удалось выделить память для пропатченного контента..." ) MSG_HASH( MSG_FAILED_TO_APPLY_SHADER, @@ -14527,6 +14598,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Не удалось закрыть лоток виртуального cd-привода." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Автозагрузка сохранения из" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Ошибка автоматической загрузки сохранения состояния из \"%s\"." @@ -14835,6 +14910,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Активирован чит-код. Режим харкдора для достижений в текущем сеансе отключен." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Режим хардкора для достижений изменён хостом." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "Требуется обновить хост сетевой игры. Режим хардкора для достижений отключен в текущем сеансе." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Завершено %s" @@ -15779,7 +15862,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Показывает шрифт нижнего меню. Включите для отображения описания кнопок на нижнем экране. Не включает даты сохранений." + "Показывать шрифт нижнего меню. Включите для отображения описания кнопок на нижнем экране. Не включает даты быстрых сохранений." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, @@ -15848,3 +15931,50 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "остановлен." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "Замещение игрока ИИ" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "Игровой ИИ" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Заменить Игрока 1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Заменить Игрока 1" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Заменить Игрока 2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Заменить Игрока 2" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Показать отладку" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Показать отладку" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Показывать 'Игровой ИИ'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Показывать опцию 'Игровой ИИ'." + ) +#endif diff --git a/intl/msg_hash_si.h b/intl/msg_hash_si.h index 4469f73e4c..3763addca7 100644 --- a/intl/msg_hash_si.h +++ b/intl/msg_hash_si.h @@ -198,6 +198,7 @@ MSG_HASH( #ifdef ANDROID #endif + /* Settings > Input > Haptic Feedback/Vibration */ @@ -491,6 +492,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -555,4 +558,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_sk.h b/intl/msg_hash_sk.h index eec0aa6173..3cc45e8c21 100644 --- a/intl/msg_hash_sk.h +++ b/intl/msg_hash_sk.h @@ -2401,22 +2401,15 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Držať" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Rýchlo streľba" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbo režim" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Čas (v snímkoch), keď sú stlačené tlačidlá s funkciou turbo." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Prevádzkový cyklus turba" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Počet snímok z režimu Turbo, počas ktorého sa tlačidlá držia stlačené. Ak je toto číslo rovné alebo väčšie ako interval Turbo, tlačidlá sa nikdy neuvoľnia." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Turbo mód" @@ -2437,14 +2430,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, "Jedno tlačidlo (držať)" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Predvolené tlačidlo Turbo" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Predvolené tlačidlo pre režim Turbo \"Jedno tlačidlo\"." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, "Rýchlo streľba" @@ -2538,10 +2523,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, "Pauza" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Zapína/vypína pozastavenie bežiaceho obsahu." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, @@ -4128,7 +4109,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Správca súborov" + "Hlavný adresár" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, @@ -4653,10 +4634,6 @@ MSG_HASH( /* Quick Menu > Options > Manage Core Options */ -MSG_HASH( - MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Vynulovať voľby" - ) /* - Legacy (unused) */ @@ -5547,9 +5524,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_FAMICOM_RED, "Rodinná červená" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Šedá tmavá" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Šedá svetlá" + ) /* Ozone: Settings > User Interface > Appearance */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Sekundárna miniatúra" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Mierka zväčšenia miniatúry" + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Farebná téma" @@ -5578,14 +5572,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRAY_LIGHT, "Šedá svetlá" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Sekundárna miniatúra" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Mierka zväčšenia miniatúry" - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -6165,10 +6152,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, "Vynútiť pomer strán" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Pokračovať" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, "Vymazať túto zhodu" @@ -6923,4 +6906,11 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, "Skenovanie je dokončené.

\nAk chcete, aby bol obsah správne naskenovaný, musíte:\n
  • mať už stiahnuté kompatibilné jadro
  • \n
  • mať aktualizované „Informačné súbory o jadre“ cez Online Updater
  • \n
  • aktualizovať \"Databázy\" cez Online Updater
  • \n
  • reštartovať RetroArch, ak ste práve vykonali čokoľvek z vyššie uvedeného
\nNakoniec, obsah sa musí zhodovať s existujúcimi databázami z nachádyajúcimi sa tu. Ak to stále nefunguje, odošlite hlásenie o chybe." ) +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_sr.h b/intl/msg_hash_sr.h index 4b2c6ff032..b5095eb486 100644 --- a/intl/msg_hash_sr.h +++ b/intl/msg_hash_sr.h @@ -1906,6 +1906,7 @@ MSG_HASH( #ifdef ANDROID #endif + /* Settings > Input > Haptic Feedback/Vibration */ @@ -2104,7 +2105,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Pregledač datoteka" + "Početni direktorijum" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, @@ -2271,6 +2272,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -2411,4 +2414,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_sv.h b/intl/msg_hash_sv.h index 5f996ad58f..0ed2cd79cc 100644 --- a/intl/msg_hash_sv.h +++ b/intl/msg_hash_sv.h @@ -42,11 +42,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENTLESS_CORES_TAB, - "Innehållslösa Kärnor" + "Innehållslösa kärnor" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TAB, - "Importera Innehåll" + "Importera innehåll" ) /* Main Menu */ @@ -61,11 +61,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_LIST, - "Ladda Kärna" + "Läs in kärna" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, - "Välj vilken Kärna som ska användas." + "Välj vilken kärna som ska användas." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Läs ur kärna" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Frigör inläst kärna." ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, @@ -89,7 +97,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_LOAD_DISC, - "Ladda en fysisk medieskiva. Välj först Kärnan (Ladda Kärna) att använda med skivan." + "Läs in en fysisk medieskiva. Välj först kärnan (Läs in kärna) att använda med skivan." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DUMP_DISC, @@ -119,7 +127,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, - "Importera Innehåll" + "Importera innehåll" ) MSG_HASH( MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, @@ -127,7 +135,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_WIMP, - "Visa Skrivbordsmeny" + "Visa skrivbordsmeny" ) MSG_HASH( MENU_ENUM_SUBLABEL_SHOW_WIMP, @@ -135,7 +143,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_DISABLE_KIOSK_MODE, - "Inaktivera Kioskläge (omstart krävs)" + "Inaktivera kioskläge (omstart krävs)" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_DISABLE_KIOSK_MODE, @@ -147,7 +155,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_ONLINE_UPDATER, - "Laddar ner tillägg, komponenter och innehåll för RetroArch." + "Hämtar ner tillägg, komponenter och innehåll för RetroArch." ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY, @@ -218,11 +226,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_LIST, - "Installera/Återställ Kärna" + "Installera/Återställ kärna" ) MSG_HASH( MENU_ENUM_SUBLABEL_SIDELOAD_CORE_LIST, - "Installera eller återställ en Kärna från 'Nerladdningar'-katalogen." + "Installera eller återställ en kärna från 'Hämtningar'-katalogen." ) MSG_HASH( /* FIXME Maybe add a description? */ MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, @@ -241,15 +249,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, - "Nedladdningar" + "Hämtningar" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, - "Utforska arkiv" + "Bläddra i arkiv" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, - "Ladda Arkiv" + "Läs in arkiv" ) /* Main Menu > Load Content > Playlists */ @@ -296,11 +304,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_GOTO_CONTENTLESS_CORES, - "Innehållslösa Kärnor" + "Innehållslösa kärnor" ) MSG_HASH( MENU_ENUM_SUBLABEL_GOTO_CONTENTLESS_CORES, - "Visar Kärnor som kan drivas utan att ladda en Innehålls-fil." + "Installerade kärnor som kan fungera utan att läsa in innehåll visas här." ) /* Main Menu > Online Updater */ @@ -311,7 +319,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_INSTALLED_CORES, - "Uppdatera installerade Kärnor" + "Uppdatera installerade kärnor" ) MSG_HASH( MENU_ENUM_SUBLABEL_UPDATE_INSTALLED_CORES, @@ -319,11 +327,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_INSTALLED_CORES_PFD, - "Byt Kärnor till Play Butik-versioner" + "Byt kärnor till Play-butiksversioner" ) MSG_HASH( MENU_ENUM_SUBLABEL_SWITCH_INSTALLED_CORES_PFD, - "Ersätt alla äldre och manuellt installerade Kärnor med de senaste versionerna från Play Butik, om möjligt." + "Ersätt alla äldre och manuellt installerade kärnor med de senaste versionerna från Play-butik, om möjligt." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, @@ -359,27 +367,27 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, - "Uppdatera Kärninfofiler" + "Uppdatera kärninfofiler" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, - "Uppdatera Tillgångar" + "Uppdatera resurser" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "Uppdatera Spelkontroll-profiler" + "Uppdatera spelkontrollsprofiler" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, - "Uppdatera Fusk" + "Uppdatera fusk" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, - "Uppdatera Databaser" + "Uppdatera databaser" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, - "Uppdatera Överlager" + "Uppdatera överlager" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, @@ -473,7 +481,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, - "Skapare" + "Upphovsperson" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, @@ -517,7 +525,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_IN_CONTENT_DIRECTORY, - "- Observera: 'Systemfiler är i Innehållskatalog' är för närvarande aktiverat." + "- Observera: 'Systemfiler är i innehållskatalog' är för närvarande aktiverat." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_PATH, @@ -541,7 +549,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_LOCK, - "Lås installerad Kärna" + "Lås installerad kärna" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LOCK, @@ -549,27 +557,27 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_SET_STANDALONE_EXEMPT, - "Uteslut från 'Innehållslösa Kärnor' menyn" + "Uteslut från 'Innehållslösa kärnor'-menyn" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_SET_STANDALONE_EXEMPT, - "Förhindra att denna kärna visas i fliken/menyn 'Innehållslösa Kärnor'. Gäller endast när visningsläget är inställt på 'Anpassat'." + "Förhindra att denna kärna visas i fliken/menyn 'Innehållslösa kärnor'. Gäller endast när visningsläget är inställt på 'Anpassat'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_DELETE, - "Radera Kärna" + "Ta bort kärna" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_DELETE, - "Radera den här kärna från disken." + "Ta bort denna kärna från disken." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CREATE_BACKUP, - "Säkerhetskopiera Kärna" + "Säkerhetskopiera kärna" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_CREATE_BACKUP, - "Skapa en arkiverad säkerhetskopia av den aktuella installerade Kärnan." + "Spara en säkerhetskopia av den aktuella installerade kärnan." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_RESTORE_BACKUP_LIST, @@ -577,11 +585,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_RESTORE_BACKUP_LIST, - "Installera en tidigare version av Kärnan från en lista över arkiverade säkerhetskopior." + "Installera en tidigare version av kärnan från en lista över sparade säkerhetskopior." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_DELETE_BACKUP_LIST, - "Radera säkerhetskopia" + "Ta bort säkerhetskopia" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_DELETE_BACKUP_LIST, @@ -644,15 +652,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, - "Skärm bredd (mm)" + "Skärmbredd (mm)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT, - "Skärm höjd (mm)" + "Skärmhöjd (mm)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI, - "Skärm DPI" + "Skärmens DPI" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT, @@ -702,6 +710,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "SDL 2-stöd" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Direct3D 8-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Direct3D 9-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Direct3D 10-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Direct3D 11-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Direct3D 12-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "GDI-stöd" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Vulkan-stöd" @@ -782,6 +814,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "PulseAudio-stöd" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "PipeWire-stöd" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "CoreAudio-stöd" @@ -862,6 +898,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2-stöd" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL-stöd" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb-stöd" @@ -934,7 +974,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SETTING, - "Scensättning" + "Inställning" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_VISUAL, @@ -1071,16 +1111,20 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, - "Scrolla upp" + "Rulla upp" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, - "Scrolla ner" + "Rulla ner" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, "Bekräfta" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, + "Starta" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, "Visa/dölj meny" @@ -1138,7 +1182,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_SETTINGS, - "Ändra inställningar för Kärna." + "Ändra inställningar för kärna." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, @@ -1158,7 +1202,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SETTINGS, - "Molnsynk" + "Molnsynkronisering" ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOUD_SYNC_SETTINGS, @@ -1166,7 +1210,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_ENABLE, - "Aktivera Molnsynk" + "Aktivera molnsynkronisering" ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOUD_SYNC_ENABLE, @@ -1342,7 +1386,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, - "Bildrutereglage" + "Bildfrekvensstrypning" ) MSG_HASH( MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, @@ -1354,7 +1398,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "Ändra inställningar för Inspelning." + "Ändra inställningar för inspelning." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, @@ -1378,7 +1422,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AI_SERVICE_SETTINGS, - "Ändra inställningar för AI-tjänsten (Translation/TTS/Misc)." + "Ändra inställningar för AI-tjänsten (Översättning/TTT/Diverse)." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCESSIBILITY_SETTINGS, @@ -1386,7 +1430,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_ACCESSIBILITY_SETTINGS, - "Ändra inställningar för Tillgänglighetsberättaren." + "Ändra inställningar för hjälpmedelsberättaren." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_POWER_MANAGEMENT_SETTINGS, @@ -1402,7 +1446,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "Ändra inställningar för Prestationer." + "Ändra inställningar för prestationer." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, @@ -1418,7 +1462,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, - "Ändra inställningar för Spellistor." + "Ändra inställningar för spellistor." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USER_SETTINGS, @@ -1673,6 +1717,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PULSE, "PulseAudio-drivrutin. Om systemet använder PulseAudio, se till att använda denna drivrutin istället för t.ex. ALSA." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PIPEWIRE, + "PipeWire-drivrutin. Om systemet använder PipeWire, se till att använda den här drivrutinen istället för t.ex. PulseAudio." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_JACK, "Drivrutinen för Jack Audio anslutningssats." @@ -1844,7 +1892,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, - "Trådad Video" + "Trådad video" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_THREADED, @@ -1858,10 +1906,166 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, "Insättning av svart bildruta" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, + "VARNING: Snabbt flimmer kan orsaka kvarstående bild på vissa skärmar. Använd på egen risk // Infoga svarta ramar mellan bildrutorna. Kan kraftigt minska rörelseoskärpa genom att emulera CRT-scanning, men på bekostnad av ljusstyrkan." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, + "Infogar svart(a) ram(ar) mellan bildrutorna för ökad rörelseklarhet. Använd endast det alternativ som är avsett för din aktuella bildskärms uppdateringsfrekvens. Används inte vid uppdateringsfrekvenser som inte är multiplar av 60 Hz, t. ex. 144 Hz, 165 Hz osv. Kombinera inte med Swap Interval > 1, subframes, Frame Delay eller Sync to Exact Content Framerate. Att låta systemets VRR vara på är ok, men inte med den inställningen. Om du märker - någon - tillfällig bildretention bör [...]" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_120, + "1 - För 120Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_180, + "2 - För 180Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_240, + "3 - För 240Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_300, + "4 - För 300Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_360, + "5 - För 360Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_420, + "6 - För 420Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_480, + "7 - För 480Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_540, + "8 - För 540Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_600, + "9 - För 600Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_660, + "10 - För 660Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_720, + "11 - För 720Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_780, + "12 - För 780Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_840, + "13 - För 840Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_900, + "14 - För 900Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_960, + "15 - För 960Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_BFI_DARK_FRAMES, + "Infoga svart bildruta - Mörka bildrutor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_BFI_DARK_FRAMES, + "Justera antalet svarta bildrutor i den totala BFI-sekvensen för utskanning. Fler motsvarar högre rörelseklarhet, färre motsvarar högre ljusstyrka. Inte tillämpligt vid 120 Hz eftersom det bara finns totalt 1 BFI-bildruta att arbeta med. Inställningar som är högre än möjligt begränsar dig till det högsta möjliga för din valda uppdateringsfrekvens." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_BFI_DARK_FRAMES, + "Justerar antalet svarta bildrutor som visas i BFI-sekvensen. Fler svarta bildrutor ökar rörelseklarheten men minskar ljusstyrkan. Inte tillämpligt vid 120 Hz eftersom det bara finns en enda extra 60 Hz-bildruta, så den måste vara svart, annars skulle BFI inte vara aktiv alls." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, + "VARNING: Snabbt flimmer kan orsaka bildbeständighet på vissa skärmar. Använd på egen risk // Simulerar en grundläggande rullande scanline över flera underrutor genom att dela upp skärmen vertikalt och rendera varje del av skärmen beroende på hur många underrutor det finns." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, + "Infogar extra shader-ram(ar) mellan bildrutorna för eventuella shader-effekter som är utformade för att köras snabbare än innehållshastigheten. Använd endast det alternativ som är avsett för din aktuella bildskärmsuppdateringsfrekvens. Används inte vid uppdateringsfrekvenser som inte är multiplar av 60 Hz, t. ex. 144 Hz, 165 Hz osv. Kombinera inte med Swap Interval > 1, BFI, Frame Delay eller Sync to Exact Content Framerate. Att låta systemets VRR vara på är ok, men inte den inst[...]" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_120, + "2 - För 120Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_180, + "3 - För 180Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_240, + "4 - För 240Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_300, + "5 - För 300Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_360, + "6 - För 360Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_420, + "7 - För 420Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_480, + "8 - För 480Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_540, + "9 - För 540Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_600, + "10 - För 600Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_660, + "11 - För 660Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_720, + "12 - För 720Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_780, + "13 - För 780Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_840, + "14 - För 840Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_900, + "15 - För 900Hz skärmuppdateringsfrekvens" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_960, + "16 - För 960Hz skärmuppdateringsfrekvens" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, "GPU-skärmdump" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, + "VARNING: Snabbt flimmer kan orsaka bildbeständighet på vissa skärmar. Använd på egen risk // Simulerar en grundläggande rullande scanline över flera underrutor genom att dela upp skärmen vertikalt och rendera varje del av skärmen beroende på hur många underrutor det finns." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, + "Simulerar en grundläggande rullande scanline över flera subframes genom att dela upp skärmen vertikalt och rendera varje del av skärmen enligt hur många subframes det finns från toppen av skärmen och nedåt." + ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT, "Skärmdumpar fångar GPU-skuggat material om det finns." @@ -2100,15 +2304,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_AUTOSWITCH_REFRESH_RATE_EXCLUSIVE_FULLSCREEN, - "Endast i exklusivt Helskärmsläge" + "Endast i exklusivt helskärmsläge" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_AUTOSWITCH_REFRESH_RATE_WINDOWED_FULLSCREEN, - "Endast i fönster med Helskärmsläge" + "Endast i fönster med helskärmsläge" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_AUTOSWITCH_REFRESH_RATE_ALL_FULLSCREEN, - "Alla Helskärmslägen" + "Alla helskärmslägen" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_AUTOSWITCH_PAL_THRESHOLD, @@ -2157,7 +2361,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_X, - "Helskärm Bredd" + "Bredd för helskärm" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_X, @@ -2165,7 +2369,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN_Y, - "Helskärm Höjd" + "Höjd för helskärm" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN_Y, @@ -2192,7 +2396,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_OPACITY, - "Fönster Opacitet" + "Fönsteropacitet" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_OPACITY, @@ -2200,7 +2404,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_SHOW_DECORATIONS, - "Visa Fönsterdekorationer" + "Visa fönsterdekorationer" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SHOW_DECORATIONS, @@ -2232,7 +2436,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, - "Fönster Bredd" + "Fönsterbredd" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, @@ -2240,7 +2444,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, - "Fönster Höjd" + "Fönsterhöjd" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, @@ -2248,7 +2452,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_AUTO_WIDTH_MAX, - "Max Bredd fönster" + "Maximal fönsterbredd" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_AUTO_WIDTH_MAX, @@ -2256,7 +2460,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_AUTO_HEIGHT_MAX, - "Max Höjd fönster" + "Maximal fönsterhöjd" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WINDOW_AUTO_HEIGHT_MAX, @@ -2269,6 +2473,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, "Heltalsskala" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, + "Skala video endast i heltalssteg. Basstorleken beror på core-rapporterad geometri och bildförhållande." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, + "Skala antingen höjd eller bredd, eller både höjd och bredd. Halva steg gäller endast för källor med hög upplösning." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_SCALING, + "Avrunda nedåt eller uppåt till nästa heltal. ”Smart” sjunker till underskala när bilden beskärs för mycket." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_UNDERSCALE, "Underskala" @@ -2341,6 +2557,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, "Anpassad visningsporthöjd som används om bildformatet är inställt på 'Anpassa bildformat'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, + "Beskär överskanning (omstart krävs)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, "Beskär några pixlar runt skärmens kant, som vanligen lämnas tomma av utvecklare och som ibland också innehåller skräppixlar." @@ -2393,7 +2613,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, - "Vertikal Synk (VSynk)" + "Vertikal synkronisering (Vsync)" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VSYNC, @@ -2415,6 +2635,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_ADAPTIVE_VSYNC, "VSynk är aktiverat tills prestandan faller under måluppdateringsfrekvensen. Kan minimera lagg när prestandan sjunker under realtid och vara mer energieffektiv." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, + "Bildrutefördröjning" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, + "Minskar latensen på bekostnad av en högre risk för att videon hackar." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_FRAME_DELAY, + "Ställer in hur många millisekunder som ska sovas innan kärnan körs efter videopresentation. Minskar latensen på bekostnad av högre risk för stuttering.\nVärden 20 och högre behandlas som procentandelar för bildtid." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTO, "Automatisk bildfördröjning" @@ -2447,6 +2679,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VRR_RUNLOOP_ENABLE, "Ingen avvikelse från kärnans efterfrågade timing. Använd för skärmar med variabel uppdateringsfrekvens (G-sync, FreeSync, HDMI 2.1 VRR)." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VRR_RUNLOOP_ENABLE, + "Synkronisera till exakt innehållsframerate. Det här alternativet motsvarar att tvinga fram x1-hastighet samtidigt som snabbspolning tillåts. Ingen avvikelse från den begärda uppdateringsfrekvensen, inget ljud Dynamic Rate Control." + ) /* Settings > Audio */ @@ -2514,11 +2750,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, - "Stäng av mixer ljudet." + "Stäng av ljudet från mixer." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_RESPECT_SILENT_MODE, - "Respektera Tyst läge" + "Respektera tyst läge" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE, @@ -2526,7 +2762,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Tyst vid Snabbspola framåt" + "Tyst ljud vid snabbspolning" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2534,12 +2770,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Fortare vid Snabbspola framåt" + "Uppsnabbat ljud vid snabbspolning" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Snabba upp ljudet vid snabbspolning framåt. Förhindrar knastrande men ändrar tonhöjd." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Tyst ljud vid tillbakaspolning" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Tysta ljudet automatiskt vid tillbakaspolning." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Volymökning (dB)" @@ -2554,7 +2798,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, - "Mixer Volymökning (dB)" + "Mixer-volymförstärkning (dB)" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, @@ -2566,11 +2810,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, - "Ljud-plugin som bearbetar ljud innan det skickas till drivrutinen." + "Insticksmodul för DSP-ljud som bearbetar ljud innan det skickas till drivrutinen." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN_REMOVE, - "Ta bort DSP-plugin" + "Ta bort DSP-insticksmodulen" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN_REMOVE, @@ -2631,6 +2875,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DEVICE_OSS, "Anpassat sökvägsvärde för OSS-drivrutinen (t.ex. /dev/dsp)." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DEVICE_JACK, + "Anpassat portnamnsvärde för JACK-drivrutinen (t.ex. system:playback1,system:playback_2)." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DEVICE_RSOUND, "Anpassad IP-adress för en RSound-server för RSound-drivrutinen." @@ -2639,6 +2887,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, "Ljudfördröjning (ms)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_LATENCY, + "Maximal ljudfördröjning i millisekunder. Drivrutinen strävar efter att hålla den faktiska latensen på 50 % av detta värde. Det kan hända att värdet inte uppfylls om ljuddrivrutinen inte kan tillhandahålla den angivna latensen." + ) #ifdef HAVE_MICROPHONE /* Settings > Audio > Input */ @@ -2646,6 +2898,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_ENABLE, "Mikrofon" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MICROPHONE_ENABLE, + "Aktivera ljudinmatning i kärnor som stöds. Har ingen overhead om kärnan inte använder en mikrofon." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_DEVICE, "Enhet" @@ -2686,10 +2942,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_WASAPI_EXCLUSIVE_MODE, "WASAPI Exklusivt läge" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MICROPHONE_WASAPI_EXCLUSIVE_MODE, + "Tillåt RetroArch att ta exklusiv kontroll över mikrofonenheten när WASAPI-mikrofondrivrutinen används. Om inaktiverad kommer RetroArch att använda delat läge istället." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_WASAPI_FLOAT_FORMAT, "WASAPI Float-format" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MICROPHONE_WASAPI_FLOAT_FORMAT, + "Använd inmatning med flyttal för WASAPI-drivrutinen, om detta stöds av din ljudenhet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MICROPHONE_WASAPI_SH_BUFFER_LENGTH, "WASAPI delad buffertlängd" @@ -2729,6 +2993,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SYNC, "Synkronisera ljud. Rekommenderas." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, + "Den maximala förändringen i ljudinmatningshastighet. Om du ökar detta möjliggörs mycket stora förändringar i timing på bekostnad av en felaktig ljudtonhöjd (t.ex. körning av PAL-kärnor på NTSC-skärmar)." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_MAX_TIMING_SKEW, + "Maximum audio timing skew.\nDefinierar den maximala förändringen i ingångshastighet. Du kanske vill öka detta för att möjliggöra mycket stora förändringar i timing, till exempel att köra PAL-kärnor på NTSC-skärmar, på bekostnad av felaktig ljudhöjd.\nIngångshastighet definieras som:\ninput rate * (1,0 +/- (max timing skew))" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, "Dynamisk ljudfrekvenskontroll" @@ -2737,6 +3009,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, "Hjälper till att jämna ut brister i timing när ljud och video synkroniseras. Tänk på att korrekt synkronisering är nästan omöjlig att få till om den är inaktiverad." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_RATE_CONTROL_DELTA, + "Om detta värde sätts till 0 inaktiveras hastighetskontrollen. Alla andra värden styr delta för ljudfrekvensreglering.\nDefinierar hur mycket ingångsfrekvensen kan justeras dynamiskt. Inmatningshastigheten definieras som:\\inmatningshastighet * (1,0 +/- (hastighetskontroll delta))" + ) /* Settings > Audio > MIDI */ @@ -2827,6 +3103,26 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, "Justera volymen på ljudströmmen." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_NONE, + "Tillstånd: Inte tillgängligt" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_STOPPED, + "Tillstånd: Stoppad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING, + "Tillstånd: Spelar" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_LOOPED, + "Tillstånd: Spelar (slinga)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL, + "Tillstånd: Spelar (sekventiellt)" + ) /* Settings > Audio > Menu Sounds */ @@ -2865,6 +3161,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, "Maximalt antal användare som stöds av RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, + "Pollningsbeteende (omstart krävs)" + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_INPUT_POLL_TYPE_BEHAVIOR, + "Påverkar hur input polling utförs i RetroArch.\nEarly - Input polling utförs innan ramen bearbetas.\nNormal - Input polling utförs när polling begärs.\nLate - Input polling utförs vid första begäran om inputstatus per ram.\nAtt ställa in den på 'Early' eller 'Late' kan resultera i mindre latens, beroende på din konfiguration. Kommer att ignoreras när du använder netplay." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, "Mappa om kontroller för denna kärna" @@ -2882,6 +3186,10 @@ MSG_HASH( "Konfigurerar automatiskt spelkontroller som har en profil, Plug-and-Play-stil." ) #if defined(HAVE_DINPUT) || defined(HAVE_WINRAWINPUT) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_NOWINKEY_ENABLE, + "Inaktivera Windows-snabbtangenter (omstart krävs)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_NOWINKEY_ENABLE, "Behåll kombinationer med Win-tangenten inuti programmet." @@ -2997,14 +3305,27 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Håll in" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo-avfyrning" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turboperiod" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Halv period" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Turboläge" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_MODE, + "Välj det allmänna beteendet för turbo-läget." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_MODE_CLASSIC, "Klassisk" @@ -3021,6 +3342,46 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD, "Singel knapp (Intryckt)" ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, + "Klassiskt läge, manövrering med två knappar. Håll in en knapp och tryck på Turbo-knappen för att aktivera tryck-släpp-sekvensen.\nTurbo-bindning kan tilldelas i Inställningar/Inmatning/Port X Controls." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, + "Klassiskt växlingsläge, tvåknappsmanövrering. Håll in en knapp och tryck på Turbo-knappen för att aktivera turbo för den knappen. För att inaktivera turbo: håll in knappen och tryck på Turbo-knappen igen.\nTurbo-bindning kan tilldelas i Inställningar/Inmatning/Port X Controls." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, + "Växlingsläge. Tryck en gång på Turbo-knappen för att aktivera trycksekvensen för den valda standardknappen, tryck en gång till för att stänga av den.\nTurbo-bindning kan tilldelas i Inställningar/Inmatning/Port X Controls." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, + "Håll-läge. Tryck-släpp-sekvensen för den valda standardknappen är aktiv så länge som Turbo-knappen hålls nedtryckt.\nTurbo-bindning kan tilldelas i Inställningar/Inmatning/Port X Controls.\nFör att efterlikna autofire-funktionen från hemdatortiden, ställ in Bindning och Knapp på samma styrspaksavfyrningsknapp." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Turbo-bindning" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "Turbo aktiverar RetroPad-bindning. Tom använder den portspecifika bindningen." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Turbo-knapp" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, + "Om den är aktiverad kan digitala riktningsinmatningar (även kända som d-pad eller ”hatswitch”) vara turbo." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS, + "Turbo-avfyrning" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, + "Ändra inställningar för turboavtryckare." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, "Haptisk feedback/vibration" @@ -3073,6 +3434,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ANDROID_INPUT_DISCONNECT_WORKAROUND, "Åtgärd för Android kopplas från" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ANDROID_INPUT_DISCONNECT_WORKAROUND, + "Lösning för kontroller som kopplas bort och återansluts. Förhindrar 2 spelare med identiska kontroller." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUIT_PRESS_TWICE, "Bekräfta Avsluta" @@ -3127,6 +3492,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_DISABLE_SEARCH_BUTTON, "Aktiverad kommer Sök-knapp tryckningar att ignoreras." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DISABLE_LEFT_ANALOG_IN_MENU, + "Inaktivera vänster analog i meny" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DISABLE_LEFT_ANALOG_IN_MENU, + "Förhindra vänster analog spak från menynavigering." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DISABLE_RIGHT_ANALOG_IN_MENU, + "Inaktivera höger analog i meny" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DISABLE_RIGHT_ANALOG_IN_MENU, + "Förhindra höger analog spak från menynavigering." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, "Skifta OK/Avbryt-knappen" @@ -3188,7 +3569,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Växlar den aktuella visningen mellan meny och innehåll som körs." + "Växlar den aktuella skärmen mellan meny och innehåll." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3202,6 +3583,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, "Avsluta" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_QUIT_KEY, + "Stänger RetroArch och ser till att alla sparade data och konfigurationsfiler sparas på hårddisken." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_CLOSE_CONTENT_KEY, "Stäng Innehåll" @@ -3264,7 +3649,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Växlar innehåll som körs mellan pausat och icke pausat läge." + "Växlar innehåll mellan pausade och icke-pausade tillstånd." ) MSG_HASH( @@ -3296,6 +3681,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, "Läs in tillstånd" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_LOAD_STATE_KEY, + "Läser in sparat tillstånd från aktuellt vald plats." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, "Spara status" @@ -3595,6 +3984,38 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, "Enhetindex" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DEVICE_INDEX, + "Den fysiska kontrollern som den känns igen av RetroArch." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_RESERVED_DEVICE_NAME, + "Reserverad enhet för denna spelare" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DEVICE_RESERVED_DEVICE_NAME, + "Den här kontrollenheten kommer att tilldelas den här spelaren, enligt reservationsläget." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_NONE, + "Ingen reservation" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_PREFERRED, + "Föredragen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DEVICE_RESERVATION_RESERVED, + "Reserverad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_RESERVATION_TYPE, + "Typ av enhetsreservation" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DEVICE_RESERVATION_TYPE, + "Föredragen: om angiven enhet finns, kommer den att allokeras till denna spelare. Reserverad: ingen annan styrenhet kommer att tilldelas för denna spelare." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_REMAP_PORT, "Mappad Port" @@ -3603,18 +4024,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, "Ställ in alla kontroller" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_ALL, + "Tilldela alla riktningar och knappar, en efter en, i den ordning de visas i den här menyn." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, "Återställ grund kontroller" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_DEFAULTS, + "Nollställ bindningsinställningar för inmatningar till deras standardvärden." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, "Spara spelkontrolls-profil" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_SAVE_AUTOCONFIG, + "Spara en autokonfigurationsfil som kommer att användas automatiskt när den här styrenheten upptäcks igen." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, "Musindex" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_MOUSE_INDEX, + "Den fysiska musen som den identifieras av RetroArch." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, "B-knapp (Nedre)" @@ -3762,8 +4199,24 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RUN_AHEAD_FRAMES, "Antal bildrutor att köra före" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUNAHEAD_MODE, + "Kör ytterligare kärnlogik för att minska latenstiden. Single Instance körs till en framtida bildruta och laddar sedan om det aktuella tillståndet. Second Instance behåller en kärninstans för enbart video i en framtida bildruta för att undvika problem med ljudstatus. Preemptive Frames kör tidigare bildrutor med ny indata när det behövs, för effektivitet." + ) #if !(defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUNAHEAD_MODE_NO_SECOND_INSTANCE, + "Kör ytterligare kärnlogik för att minska latenstiden. Single Instance körs till en framtida frame och laddar sedan om det aktuella tillståndet. Preemptive Frames kör tidigare ramar med ny indata när det behövs, för effektivitet." + ) #endif +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUNAHEAD_MODE_SINGLE_INSTANCE, + "Enstaka instansläge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUNAHEAD_MODE_SECOND_INSTANCE, + "Läge för andra instans" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RUN_AHEAD_HIDE_WARNINGS, "Dölj Run-Ahead Varningar" @@ -3775,6 +4228,10 @@ MSG_HASH( /* Settings > Core */ +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, + "Ge hårdvarurenderade kärnor en egen privat kontext. Undviker att behöva anta att hårdvaran ändrar tillstånd mellan bildrutor." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DRIVER_SWITCH_ENABLE, "Tillåt kärnor att byta videodrivrutin" @@ -3815,13 +4272,17 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTION_CATEGORY_ENABLE, "Tillåter kärnor att visa alternativ i kategoribaserade undermenyer. OBS: Kärnan måste laddas om för att ändringar ska börja gälla." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INFO_CACHE_ENABLE, + "Behåller en ihållande lokal cache av installerad kärninformation. Minskar inläsningstiderna avsevärt på plattformar med långsam diskåtkomst." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "Kringgå kärninformationens funktioner för sparad status" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Anger om kärninformationens spara status-möjligheter ska ignoreras, vilket gör det möjligt att experimentera med relaterade funktioner (run ahead, spola tillbaka, etc.)." + "Anger om funktioner för att spara kärninformation ska ignoreras, vilket gör det möjligt att experimentera med relaterade funktioner (köra framåt, spola tillbaka etc.)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -3843,7 +4304,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_MANAGER_LIST, - "Hantera Kärnor" + "Hantera kärnor" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_MANAGER_LIST, @@ -3852,7 +4313,7 @@ MSG_HASH( #ifdef HAVE_MIST MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_MANAGER_STEAM_LIST, - "Hantera Kärnor" + "Hantera kärnor" ) MSG_HASH( @@ -3862,26 +4323,26 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_STEAM_INSTALL, - "Installera Kärna" + "Installera kärna" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_STEAM_UNINSTALL, - "Avinstallera Kärna" + "Avinstallera kärna" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_MANAGER_STEAM, - "Visa 'Hantera Kärnor'" + "Visa 'Hantera kärnor'" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_MANAGER_STEAM, - "Visa alternativet 'Hantera Kärnor' i huvudmenyn." + "Visa alternativet 'Hantera kärnor' i huvudmenyn." ) MSG_HASH( MSG_CORE_STEAM_INSTALLING, - "Installerar Kärna: " + "Installerar kärna: " ) MSG_HASH( @@ -3920,6 +4381,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, "Ladda Innehållsspecifika Kärnalternativ automatiskt" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, + "Läs in anpassade kärnalternativ som standard vid uppstart." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, + "Läs automatiskt in åsidosättningsfiler" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, + "Läs in anpassad konfiguration vid uppstart." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, "Ladda Ommappningsfiler automatiskt" @@ -3999,6 +4472,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, "Spara automatiskt icke-flyktigt SaveRAM vid fasta intervaller (i sekunder)." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUTOSAVE_INTERVAL, + "Autosparar det icke-flyktiga SRAM-minnet med jämna mellanrum. Detta är inaktiverat som standard om inget annat anges. Intervallet mäts i sekunder. Ett värde på 0 inaktiverar autosparning." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REPLAY_CHECKPOINT_INTERVAL, + "Automatisk bokmärkning av speltillstånd under uppspelning av inspelning med ett regelbundet intervall (i sekunder)." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_REPLAY_CHECKPOINT_INTERVAL, + "Sparar automatiskt speltillståndet under inspelning av repriser med ett regelbundet intervall. Detta är inaktiverat som standard om inget annat anges. Intervallet mäts i sekunder. Ett värde på 0 avaktiverar inspelning av kontrollpunkter." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, "Öka sparstatus-index automatiskt" @@ -4016,12 +4501,12 @@ MSG_HASH( "Begränsa antalet sparstatusar som kommer att skapas när 'Öka statusindex automatiskt' är aktiverat. Om gränsen överskrids vid sparande av en ny status kommer den befintliga statusen med lägst index att raderas. Ett värde av '0' innebär att obegränsade statusar kommer att sparas." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, - "Autospara status" + MENU_ENUM_SUBLABEL_REPLAY_MAX_KEEP, + "Begränsa antalet uppspelningar som skapas när ”Increment Replay Index Automatically” är aktiverat. Om gränsen överskrids vid inspelning av en ny uppspelning raderas den befintliga uppspelningen med lägst index. Ett värde på ”0” innebär att obegränsat antal repriser spelas in." ) MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Sparar din status automatiskt när innehållet avslutas. RetroArch kommer kunna ladda in status filen automatiskt om 'Spara din status automatiskt' är aktiverat." + MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, + "Autospara status" ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, @@ -4039,6 +4524,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_FILE_COMPRESSION, "Kompression för SaveRAM" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_FILE_COMPRESSION, + "Skriv icke-flyktiga SaveRAM-filer i ett arkiverat format. Minskar filstorleken dramatiskt på bekostnad av (försumbart) ökade spar-/inläsningstider.\nGäller endast kärnor som möjliggör sparande via standardgränssnittet libretro SaveRAM." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_FILE_COMPRESSION, "Komprimera din sparstatus" @@ -4091,10 +4580,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_RUNTIME_LOG, "Spara körtidslogg (per kärna)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_RUNTIME_LOG, + "Håll reda på hur länge varje innehållspost har körts, med poster separerade efter kärna." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_RUNTIME_LOG_AGGREGATE, "Spara körtidslogg (aggregerat)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_RUNTIME_LOG_AGGREGATE, + "Håll reda på hur länge varje innehållsobjekt har körts, registrerat som den sammanlagda summan över alla kärnor." + ) /* Settings > Logging */ @@ -4116,12 +4613,16 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, - "Loggningsnivå för Kärna" + "Loggningsnivå för kärna" ) MSG_HASH( MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, "Ange loggnivå för kärnor. Om en loggnivå som utfärdats av en kärna är under detta värde ignoreras den." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_LIBRETRO_LOG_LEVEL, + "Ställer in loggnivån för libretro-kärnor (GET_LOG_INTERFACE). Om en loggnivå som utfärdas av en libretro-kärna är lägre än libretro_log-nivån ignoreras den. DEBUG-loggar ignoreras alltid om inte verbose-läget är aktiverat (--verbose).\nDEBUG = 0\nINFO = 1\nWARN = 2\nERROR = 3" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY_DEBUG, "0 (Felsök)" @@ -4178,17 +4679,29 @@ MSG_HASH( "Filtrera filer som visas i filbläddraren till filändelser som stöds." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Använd intern mediaspelare" + MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "Filtrera efter kärna" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, - "Filtrera efter Kärna" + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtrera filer som visas i filbläddraren efter aktuell kärna." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Kom ihåg senaste använda startkatalog" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, + "Öppna filbläddraren på den senast använda platsen när du laddar innehåll från startkatalogen. Obs: Platsen återställs till standard när RetroArch startas om." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Använd intern mediaspelare" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Använd inbyggd bildvisare" + ) /* Settings > Frame Throttle */ @@ -4204,6 +4717,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, "Snabbspola framåt-hastighet" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, + "Den maximala hastighet med vilken innehållet körs när snabbspolning används (t.ex. 5.0x för innehåll med 60 bilder/s= 300 bildfrekvensgräns). Om den är inställd på 0.0x är snabbspolningsförhållandet obegränsat (ingen bildfrekvensgräns)." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FASTFORWARD_RATIO, + "Den maximala hastighet med vilken innehållet körs när snabbspolning används. (T.ex. 5.0 för 60 fps innehåll => 300 fps tak).\nRetroArch kommer att gå i viloläge för att säkerställa att den maximala hastigheten inte överskrids. Lita inte på att detta tak är helt korrekt." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FASTFORWARD_FRAMESKIP, "Snabbspola framåt-bildrutshopp" @@ -4212,6 +4733,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, "Slow motion hastighet" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, + "Den hastighet som innehållet spelas upp i när slowmotion används." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, + "Säkerställer att bildfrekvensen begränsas när du är inne i menyn." + ) /* Settings > Frame Throttle > Rewind */ @@ -4219,13 +4748,33 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_REWIND_ENABLE, "Spola tillbaka-stöd" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_ENABLE, + "Återgå till en tidigare punkt i den senaste spelningen. Detta orsakar en allvarlig prestandaförlust när du spelar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, + "Antalet bildrutor som ska spolas tillbaka per steg. Högre värden ökar återspolningshastigheten." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE, "Spola tillbaka Buffertstorlek (MB)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_BUFFER_SIZE, + "Den minnesmängd (i MB) som ska reserveras för återspolningsbufferten. Om du ökar detta kommer mängden återspolningshistorik att öka." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REWIND_BUFFER_SIZE_STEP, + "Stegstorlek för återspolningsbuffert (MB)" + ) /* Settings > Frame Throttle > Frame Time Counter */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_RESET_AFTER_FASTFORWARDING, + "Nollställ efter snabbspolning" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_RESET_AFTER_SAVE_STATE, "Återställ efter sparad status" @@ -4269,6 +4818,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_THREADS, "Inspelnings-trådar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, + "Fånga bilden efter att filter (men inte shaders) har tillämpats. Videon kommer att se lika snygg ut som det du ser på din skärm." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, "Använd GPU-inspelning" @@ -4394,6 +4947,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_INPUTS, "Visa inmatningar på överlager" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_INPUTS, + "Visa registrerade ingångar på överlägget på skärmen. ”Touched” markerar överläggselement som trycks/klickas på. ”Fysisk (styrenhet)” visar faktiska indata som skickas till kärnorna, vanligtvis från en ansluten styrenhet/tangentbord." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_INPUTS_PHYSICAL, "Fysiska (spelkontroller)" @@ -4422,18 +4979,150 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_AUTO_SCALE, "Justera automatiskt överlagringsskalan och avståndet mellan element i användargränssnittet för att matcha skärmens bildförhållande. Ger bästa resultat med överkontrollör." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY, + "Diagonal känslighet för riktningsknappar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY, + "Justera storleken på de diagonala zonerna. Ställ in på 100% för 8-vägssymmetri." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, + "Överlappningskänslighet för ABXY" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, + "Justera storleken på överlappningszonerna i handlingsknappens diamant. Ställ in på 100% för 8-vägssymmetri." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analog återställningszon" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Inmatningen för den analoga spaken kommer att vara relativ till första beröringen om den trycks in inom denna zon." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Överlager" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_AUTOLOAD_PREFERRED, + "Föredra inläsning av överlägg baserat på systemnamn innan det återgår till standardförinställningen. Ignoreras om en åsidosättning har angetts för förinställningen för överlägg." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, "Överlager opacitet" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, + "Opacitet för alla användargränssnittselement i överlägget." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, "Förinställt Överlager" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_PRESET, + "Välj ett överlägg från filbläddraren." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE_LANDSCAPE, + "(Liggande) Skala för överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_SCALE_LANDSCAPE, + "Skala för alla användargränssnittselement i överlägget när du använder liggande bildskärmsorientering." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_ASPECT_ADJUST_LANDSCAPE, + "(Liggande) Justera överläggsförhållande" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_ASPECT_ADJUST_LANDSCAPE, + "Tillämpa en korrigeringsfaktor för bildförhållande på överlägget när du använder liggande bildskärmsorientering. Positiva värden ökar (medan negativa värden minskar) den effektiva överlagringsbredden." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_X_SEPARATION_LANDSCAPE, + "(Liggande) Horisontell separation för överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_X_SEPARATION_LANDSCAPE, + "Om det stöds av det aktuellt förvalet, justera avståndet mellan elementen i användargränssnittet i den vänstra och högra halvan av ett överlägg när du använder liggande visningsorienteringar. Positiva värden ökar (medan negativa värden minskar) separationen mellan de två halvorna." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_Y_SEPARATION_LANDSCAPE, + "(Liggande) Vertikal separation för överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_Y_SEPARATION_LANDSCAPE, + "Om det stöds av den aktuella förinställningen, justera avståndet mellan användargränssnittselementen i den övre och nedre halvan av ett överlägg när du använder liggande bildskärmsorientering. Positiva värden ökar (medan negativa värden minskar) separationen mellan de två halvorna." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_X_OFFSET_LANDSCAPE, + "(Liggande) X-förskjutning överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_X_OFFSET_LANDSCAPE, + "Horisontell förskjutning av överlägget när du använder liggande bildskärmsorientering. Positiva värden flyttar överlägget till höger, negativa värden till vänster." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_Y_OFFSET_LANDSCAPE, + "(Liggande) Y-förskjutning överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_Y_OFFSET_LANDSCAPE, + "Vertikal förskjutning av överlägget vid användning av liggande bildskärmsorientering. Positiva värden flyttar överlägget uppåt; negativa värden nedåt." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE_PORTRAIT, + "(Stående) Skala för överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_SCALE_PORTRAIT, + "Skala för alla användargränssnittselement i överlägget när du använder stående bildskärmsorientering." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_ASPECT_ADJUST_PORTRAIT, + "(Stående) Justera överläggsförhållande" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_ASPECT_ADJUST_PORTRAIT, + "Tillämpa en korrigeringsfaktor för bildförhållande på överlägget när du använder stående bildskärmsorientering. Positiva värden ökar (medan negativa värden minskar) den effektiva höjden på överlägget." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_X_SEPARATION_PORTRAIT, + "(Stående) Horisontell separation för överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_X_SEPARATION_PORTRAIT, + "Om det stöds av den aktuella förinställningen, justera avståndet mellan användargränssnittselementen i den vänstra och högra halvan av ett överlägg när du använder stående bildskärmsorientering. Positiva värden ökar (medan negativa värden minskar) separationen mellan de två halvorna." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_Y_SEPARATION_PORTRAIT, + "(Stående) Vertikal separation för överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_Y_SEPARATION_PORTRAIT, + "Om det stöds av den aktuella förinställningen, justera avståndet mellan användargränssnittselementen i den övre och nedre halvan av ett överlägg när du använder stående bildskärmsorientering. Positiva värden ökar (medan negativa värden minskar) separationen mellan de två halvorna." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_X_OFFSET_PORTRAIT, + "(Stående) X-förskjutning överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_X_OFFSET_PORTRAIT, + "Horisontell förskjutning av överlägget när du använder stående bildskärmsorientering. Positiva värden flyttar överlägget till höger, negativa värden till vänster." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERLAY_Y_OFFSET_PORTRAIT, + "(Stående) Y-förskjutning överlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_Y_OFFSET_PORTRAIT, + "Vertikal förskjutning av överlägget vid användning av stående bildskärmsorientering. Positiva värden flyttar överlägget uppåt; negativa värden nedåt." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_SETTINGS, "Tangentbordsöverlager" @@ -4442,14 +5131,30 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OSK_OVERLAY_SETTINGS, "Välj och justera ett tangentbordsöverlager." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_POINTER_ENABLE, + "Aktivera överlägg för ljuspistol, mus och pekare" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_POINTER_ENABLE, + "Använd alla pekinmatningar som inte trycker på överläggskontroller för att skapa pekenhetsinmatningar för kärnan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_LIGHTGUN_SETTINGS, "Överlägg ljuspistol" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_LIGHTGUN_SETTINGS, + "Konfigurera ljuspistolens inmatning som skickas från överlägget." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_MOUSE_SETTINGS, "Överlägg mus" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_MOUSE_SETTINGS, + "Konfigurera musinmatning som skickas från överlägget. Obs: 1-, 2- och 3-fingertryckningar skickar vänster-, höger- och mittknappsklick." + ) /* Settings > On-Screen Display > On-Screen Overlay > Keyboard Overlay */ @@ -4457,6 +5162,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_PRESET, "Förinställt tangentbordsöverlager" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OSK_OVERLAY_PRESET, + "Välj ett tangentbordsöverlägg från filbläddraren." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OSK_OVERLAY_AUTO_SCALE, "Auto-skala tangentbordsöverlager" @@ -4465,6 +5174,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OSK_OVERLAY_AUTO_SCALE, "Justera tangentbordsöverlägret till dess ursprungliga bildformat. Inaktivera för att fylla skärmen." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_OPACITY, + "Opacitet för tangentbordsöverlägg" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OSK_OVERLAY_OPACITY, + "Opacitet för alla användargränssnittselement i tangentbordsöverlägget." + ) /* Settings > On-Screen Display > On-Screen Overlay > Overlay Lightgun */ @@ -4472,6 +5189,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_PORT, "Port för ljuspistol" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_PORT_ANY, + "Alla" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_LIGHTGUN_FOUR_TOUCH_INPUT, + "Välj den inmatning som ska skickas när fyra pekare visas på skärmen. Utlösarfördröjningen bör vara inte vara noll för att skilja den från andra inmatningar." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_ALLOW_OFFSCREEN, + "Tillåt utanför skärmen" + ) /* Settings > On-Screen Display > On-Screen Overlay > Overlay Mouse */ @@ -4479,6 +5208,42 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_SPEED, "Mushastighet" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_SPEED, + "Justera markörens rörelsehastighet." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_HOLD_TO_DRAG, + "Långt tryck för att dra" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_HOLD_TO_DRAG, + "Tryck länge på skärmen för att börja hålla en knapp." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_HOLD_MSEC, + "Tröskelvärde för lång tryckning (ms)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_HOLD_MSEC, + "Justera den hålltid som krävs för en lång tryckning." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_DTAP_TO_DRAG, + "Dubbeltryck för att dra" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_DTAP_TO_DRAG, + "Dubbeltryck på skärmen för att börja hålla en knapp vid det andra trycket. Lägger till latens till musklick." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_DTAP_MSEC, + "Tröskelvärde för dubbeltryckning (ms)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_MOUSE_DTAP_MSEC, + "Justera den tillåtna tiden mellan tryckningarna när en dubbeltryckning upptäcks." + ) /* Settings > On-Screen Display > Video Layout */ @@ -4486,10 +5251,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_ENABLE, "Aktivera videolayout" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_LAYOUT_ENABLE, + "Videolayouter används för ramar och annan grafik." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_PATH, + "Sökväg för videolayout" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_LAYOUT_PATH, + "Välj en videolayout från filbläddraren." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_SELECTED_VIEW, "Vald vy" ) +MSG_HASH( /* FIXME Unused */ + MENU_ENUM_SUBLABEL_VIDEO_LAYOUT_SELECTED_VIEW, + "Välj en vy inom den inlästa layouten." + ) /* Settings > On-Screen Display > On-Screen Notifications */ @@ -4505,10 +5286,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_WIDGETS_ENABLE, "Grafikwidgets" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WIDGETS_ENABLE, + "Använd dekorerade animationer, meddelanden, indikatorer och kontroller." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_WIDGET_SCALE_AUTO, "Auto-skala Grafikwidgets" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WIDGET_SCALE_AUTO, + "Ändra automatiskt storlek på dekorerade meddelanden, indikatorer och kontroller baserat på aktuell menyskala." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WIDGET_SCALE_FACTOR_FULLSCREEN, + "Tillämpa en manuell skalningsfaktor när du ritar grafikwidgets i helskärmsläge. Gäller endast när ”Skala grafikwidgets automatiskt” är inaktiverat. Kan användas för att öka eller minska storleken på dekorerade meddelanden, indikatorer och kontroller oberoende av själva menyn." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WIDGET_SCALE_FACTOR_WINDOWED, + "Använd en manuell skalningsfaktor när du ritar displaywidgets i fönsterläge. Gäller endast när ”Skala grafikwidgets automatiskt” är inaktiverat. Kan användas för att öka eller minska storleken på dekorerade meddelanden, indikatorer och kontroller oberoende av själva menyn." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FPS_SHOW, "Visa bildhastighet" @@ -4541,6 +5338,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MEMORY_SHOW, "Visa systemets använd och total mängd minne på skärmen." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MEMORY_UPDATE_INTERVAL, + "Uppdateringsintervall för minnesanvändning (i bildrutor)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_PING_SHOW, "Visa Netplay Ping" @@ -4551,7 +5352,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CONTENT_ANIMATION, - "\"Ladda Innehåll\" notis vid start" + "\"Läs in innehåll\"-notifiering vid uppstart" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, @@ -4575,15 +5376,23 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, - "Ommappning laddad Notiser" + "Notifieringar vid inlästa inmatningsommappningar" ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_REMAP_LOAD, - "Visa ett meddelande på skärmen när ommappningsfiler för spelkontroller laddas." + "Visa ett meddelande på skärmen vid inläsning av ommappningsfiler för inmatning." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_SET_INITIAL_DISK, + "Visa ett meddelande på skärmen när du automatiskt återställer den senast använda skivan vid start av flerskivsinnehåll som lästs in via M3U-spellistor." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_DISK_CONTROL, + "Visar ett meddelande på skärmen när du matar in och tar ut skivor." ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_SAVE_STATE, - "Visa ett meddelande på skärmen när du sparar och laddar spelstatus." + "Visa ett meddelande på skärmen när du sparar och läser in sparade tillstånd." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_FAST_FORWARD, @@ -4675,7 +5484,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Ange typsnittsstorleken i punkter." + "Ange teckenstorleken i punkter. När widgetar används har denna storlek endast effekt på statistikvisningen på skärmen." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -4749,6 +5558,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_BGCOLOR_BLUE, "Ställer in det blåa värdet för bakgrundsfärgen för skärm-notiser. Giltiga värden är mellan 0 och 255." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_BGCOLOR_OPACITY, + "Ställer in opaciteten för OSD-bakgrundsfärgen. Giltiga värden ligger mellan 0,0 och 1,0." + ) /* Settings > User Interface */ @@ -4768,6 +5581,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SETTINGS, "Ändra inställningar för menyskärmens utseende." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_APPICON_SETTINGS, + "Programikon" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_APPICON_SETTINGS, + "Ändra programikon." + ) #ifdef _3DS MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_BOTTOM_SETTINGS, @@ -4808,7 +5629,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Pausa innehållet som körs för närvarande om menyn är aktiv." + "Pausa innehållet om menyn är aktiv." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -4816,7 +5637,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SAVESTATE_RESUME, - "Stäng automatiskt menyn och återuppta innehållet efter att ha sparat eller laddat en status. Inaktivering kan förbättra prestandan för sparad status på mycket långsamma enheter." + "Stäng automatiskt menyn och återuppta innehållet efter att ha sparat eller läst in ett tillstånd. Inaktivering kan förbättra prestandan för sparad status på mycket långsamma enheter." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_INSERT_DISK_RESUME, @@ -4824,7 +5645,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_INSERT_DISK_RESUME, - "Stäng automatiskt menyn och återuppta innehållet efter att matat in eller laddat en ny skiva." + "Stäng automatiskt menyn och återuppta innehållet efter att matat in eller läst in en ny skiva." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUIT_ON_CLOSE_CONTENT, @@ -4906,14 +5727,38 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, "Inaktivera skrivbordskomposition" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, + "Fönsterhanterare använder komposition för att tillämpa visuella effekter, upptäcka fönster som inte svarar och mycket annat." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DISABLE_COMPOSITION, + "Inaktivera komposition med tvång. Inaktivering är endast giltig på Windows Vista/7 för tillfället." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SCROLL_FAST, "Scrollhastighet i meny" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SCROLL_FAST, + "Markörens maximala hastighet när du håller en riktning för att rulla." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SCROLL_DELAY, "Scrollfördröjning i meny" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SCROLL_DELAY, + "Initial fördröjning i millisekunder när du håller en riktning för att rulla." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, + "Starta UI Companion vid uppstart" + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_UI_COMPANION_START_ON_BOOT, + "Starta User Interface companion-drivrutinen vid uppstart (om tillgänglig)." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DESKTOP_MENU_ENABLE, "Skrivbordsmeny (omstart krävs)" @@ -4943,27 +5788,27 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CORE, - "Visa 'Ladda Kärna'" + "Visa 'Läs in kärna'" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CORE, - "Visa alternativet 'Ladda Kärna' i huvudmenyn." + "Visa alternativet 'Läs in kärna' i huvudmenyn." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_CONTENT, - "Visa 'Ladda Innehåll'" + "Visa 'Läs in innehåll'" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_CONTENT, - "Visa alternativet 'Ladda Innehåll' i huvudmenyn." + "Visa alternativet 'Läs in innehåll' i huvudmenyn." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_LOAD_DISC, - "Visa 'Ladda skiva'" + "Visa 'Läs in skiva'" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SHOW_LOAD_DISC, - "Visa alternativet 'Ladda skiva' i huvudmenyn." + "Visa alternativet 'Läs in skiva' i huvudmenyn." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_DUMP_DISC, @@ -4993,7 +5838,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, - "Visa 'Ladda ner Kärna'" + "Visa 'Hämta ner kärna'" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, @@ -5043,30 +5888,58 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS, "Visa 'Inställningar'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS, + "Visa menyn ”Inställningar”. (Omstart krävs på Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_SETTINGS_PASSWORD, "Ange lösenord för 'Inställningar'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_SETTINGS_PASSWORD, + "Om du anger ett lösenord när du döljer inställningsfliken kan du senare återställa den från menyn genom att gå till fliken Huvudmeny, välja ”Aktivera inställningsfliken” och ange lösenordet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_FAVORITES, "Visa 'Favoriter'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_FAVORITES, + "Visa menyn ”Favoriter”. (Omstart krävs på Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_IMAGES, "Visa 'Bilder'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_IMAGES, + "Visa menyn ”Bilder”. (Omstart krävs på Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_MUSIC, "Visa 'Musik'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_MUSIC, + "Visa menyn ”Musik”. (Omstart krävs på Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_VIDEO, "Visa 'Videor'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_VIDEO, + "Visa menyn ”Videor”. (Omstart krävs på Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_NETPLAY, "Visa 'Netplay'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_NETPLAY, + "Visa menyn ”Netplay”. (Omstart krävs på Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_HISTORY, "Visa 'Historik'" @@ -5075,6 +5948,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, "Visa 'Importera Innehåll'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_ADD, + "Visa menyn ”Importera innehåll”. (Omstart krävs på Ozone/XMB)" + ) MSG_HASH( /* FIXME can now be replaced with MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD */ MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD_ENTRY, "Visa 'Importera Innehåll'" @@ -5095,18 +5972,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, "Visa 'Spellistor'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, + "Visa spellistorna i huvudmenyn. Ignoreras i GLUI om flikar och navfält för spellistor är aktiverade." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Visa spellistflikar" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, "Visa 'Utforska'" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_CONTENTLESS_CORES, - "Visa 'Innehållslösa Kärnor'" + "Visa 'Innehållslösa kärnor'" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_CONTENTLESS_CORES_ALL, "Alla" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_CONTENTLESS_CORES_SINGLE_PURPOSE, + "En gång" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SHOW_CONTENTLESS_CORES_CUSTOM, "Anpassa" @@ -5123,6 +6012,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_TIMEDATE_STYLE, "Tid och datum-format" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TIMEDATE_STYLE, + "Ändra hur aktuellt datum och/eller aktuell tid visas inne i menyn." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TIMEDATE_DATE_SEPARATOR, "Datumseparator" @@ -5159,6 +6052,10 @@ MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, "Visa Startskärm" ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, + "Visa startskärmen i menyn. Detta sätts automatiskt till false när programmet startas för första gången." + ) /* Settings > User Interface > Menu Item Visibility > Quick Menu */ @@ -5196,11 +6093,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_LOAD_STATE, - "Visa 'Spara/Ladda status'" + "Visa 'Spara/Läs in tillstånd'" ) MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, - "Visa alternativen för att spara/ladda ett tillstånd." + "Visa alternativen för att spara/läs in ett tillstånd." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_REPLAY, @@ -5212,11 +6109,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, - "Visa 'Ångra Spara/Ladda status'" + "Visa 'Ångra Spara/Läs in tillstånd'" ) MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, - "Visa alternativen för att Ångra Spara/Ladda status." + "Visa alternativen för att Ångra Spara/Läs in tillstånd." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_OPTIONS, @@ -5226,6 +6123,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_OPTIONS, "Visa alternativet 'Kärnalternativ'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CORE_OPTIONS_FLUSH, + "Visa 'Skriv alternativ till disk'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CORE_OPTIONS_FLUSH, + "Visa posten ”Skriv alternativ till disk” i menyn ”Alternativ > Hantera kärnalternativ”." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CONTROLS, "Visa 'Spelkontroller'" @@ -5290,6 +6195,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_REWIND, "Visa alternativet 'Spola tillbaka'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, + "Visa 'Spara kärnåsidosättningar'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, + "Visa alternativet 'Spara kärnåsidosättningar' i menyn 'Åsidosättningar'." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_CHEATS, "Visa 'Fusk'" @@ -5314,6 +6227,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, "Visa alternativet 'Lägg till i favoriter'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_PLAYLIST, + "Visa 'Lägg till i spellista'" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SET_CORE_ASSOCIATION, "Visa 'Ställ in kärnassociation'" @@ -5332,11 +6249,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS, - "Visa 'Ladda ner miniatyrer'" + "Visa 'Hämta ner miniatyrer'" ) MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS, - "Visa alternativet 'Ladda ner miniatyrer' när innehåll inte körs." + "Visa alternativet 'Hämta ner miniatyrer' när innehåll inte körs." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_INFORMATION, @@ -5505,14 +6422,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Visa 'Användare'" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Spellistikoner" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Typ av miniatyrbild för spellistikonen att visa." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Visa inställningar för 'Användare'." @@ -5640,33 +6549,73 @@ MSG_HASH( /* Settings > AI Service */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AI_SERVICE_MODE, + "Utmatning från AI-tjänst" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AI_SERVICE_MODE, + "Visa översättningen som ett textöverlägg (Bildläge), spela upp som text-till-tal (Tal) eller använd en systemberättare som NVDA (Berättare)." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_URL, "AI-tjänst URL" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AI_SERVICE_URL, + "En http:// URL som pekar på den översättningstjänst som ska användas." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_ENABLE, "AI-tjänst aktiverad" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AI_SERVICE_ENABLE, + "Aktivera AI-tjänsten så att den körs när snabbtangenten AI-tjänst trycks in." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_PAUSE, "Pausa under översättning" ) MSG_HASH( MENU_ENUM_SUBLABEL_AI_SERVICE_PAUSE, - "Pausa Kärna medan skärmen översatts." + "Pausa kärnan medan skärmen översatts." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_SOURCE_LANG, "Källspråk" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AI_SERVICE_SOURCE_LANG, + "Det språk som tjänsten ska översätta från. Om den är inställd på ”Standard” försöker den automatiskt känna av språket. Om du ställer in det på ett specifikt språk blir översättningen mer exakt." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_TARGET_LANG, "Målspråk" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AI_SERVICE_TARGET_LANG, + "Det språk som tjänsten ska översätta till. ”Standard” är engelska." + ) /* Settings > Accessibility */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCESSIBILITY_ENABLED, + "Aktivera hjälpmedel" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCESSIBILITY_ENABLED, + "Aktivera text-till-tal för att underlätta navigering i menyn." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCESSIBILITY_NARRATOR_SPEECH_SPEED, + "Text-till-tal-hastighet" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED, + "Hastigheten för text-till-tal-rösten." + ) /* Settings > Power Management */ @@ -5682,12 +6631,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, - "Hardcore läge" + "Hardcore-läge" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, + "Inaktiverar fusk, spola tillbaka, slowmotion och läsa in sparade tillstånd. Prestationer som uppnås i hardcore-läget är unikt markerade så att du kan visa andra vad du har uppnått utan emulatorns hjälpfunktioner. Om du växlar den här inställningen under spelets gång startas spelet om." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, "Topplistor" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_RICHPRESENCE_ENABLE, + "Skickar regelbundet kontextuell spelinformation till RetroAchievements webbplats. Har ingen effekt om ”Hardcore-läge” är aktiverat." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_BADGES_ENABLE, "Prestationsemblem" @@ -5724,6 +6681,10 @@ MSG_HASH( /* suggestion for translators: translate as 'Play Again Mode' */ MENU_ENUM_LABEL_VALUE_CHEEVOS_START_ACTIVE, "Encore-läge" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_START_ACTIVE, + "Starta sessionen med alla prestationer aktiva (även de som tidigare har låsts upp)." + ) /* Settings > Achievements > Appearance */ @@ -5735,6 +6696,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_APPEARANCE_SETTINGS, "Ändra position och förskjutningar för prestationsnotiser på skärmen." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_APPEARANCE_ANCHOR, + "Ställ in det hörn/den kant på skärmen som meddelanden om prestationer ska visas från." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR_TOPLEFT, "Överkant Vänster" @@ -5759,10 +6724,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_ANCHOR_BOTTOMRIGHT, "Underkant Höger" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_PADDING_AUTO, + "Justerad utfyllnad" + ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_APPEARANCE_PADDING_AUTO, "Ange om prestationsnotiser ska överensstämma med andra typer av skärm-notiser. Inaktivera för att ställa in manuella utfyllnads-/positionsvärden." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_PADDING_H, + "Manuell horisontell utfyllnad" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_APPEARANCE_PADDING_H, + "Avstånd från vänster/höger skärmkant, vilket kan kompensera för skärmens overscan." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_APPEARANCE_PADDING_V, + "Manuell vertikal utfyllnad" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_APPEARANCE_PADDING_V, + "Avstånd från skärmens övre/nedre kant, vilket kan kompensera för skärmens overscan." + ) /* Settings > Achievements > Visibility */ @@ -5774,6 +6759,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_SETTINGS, "Ändra vilka meddelanden och element på skärmen som visas. Inaktiverar inte funktionalitet." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SUMMARY, + "Sammandrag av uppstart" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_SUMMARY, + "Visar information om spelet som laddas och användarens aktuella framsteg.\n”Alla identifierade spel” visar en sammanfattning för spel utan publicerade prestationer." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SUMMARY_ALLGAMES, "Alla identifierade spel" @@ -5814,6 +6807,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_PROGRESS_TRACKER, "Visa en indikationer på skärmen när framsteg görs mot vissa prestationer." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_LBOARD_START, + "Visar en beskrivning av en topplista när den blir aktiv." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_LBOARD_SUBMIT, + "Visar ett meddelande med det värde som skickas in när ett topplisteförsök har slutförts." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_ACCOUNT, "Inloggningsmeddelande" @@ -5833,6 +6834,26 @@ MSG_HASH( /* Settings > Network */ +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, + "Om netplay-spel ska annonseras offentligt. Om inställningen är avaktiverad måste klienter ansluta manuellt i stället för att använda den publika lobbyn." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, + "Använd reläserver" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER, + "Välj en specifik reläserver att använda. Geografiskt närmare platser tenderar att ha lägre latens." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_CUSTOM_MITM_SERVER, + "Anpassad adress för reläserver" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_CUSTOM_MITM_SERVER, + "Ange adressen till din anpassade reläserver här. Format: adress eller adress|port." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_1, "Nordamerika (östkusten, USA)" @@ -5877,10 +6898,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MAX_CONNECTIONS, "Max samtidiga anslutningar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_MAX_CONNECTIONS, + "Det maximala antalet aktiva anslutningar som värden accepterar innan nya anslutningar avvisas." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MAX_PING, "Ping begränsning" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_MAX_PING, + "Den maximala anslutningsfördröjningen (ping) som värden accepterar. Ställ in den på 0 för ingen gräns." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, "Serverlösenord" @@ -5925,10 +6954,42 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_PAUSING, "Tillåt spelare att pausa under Netplay." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ALLOW_SLAVES, + "Tillåt anslutningar i slavläge. Klienter i slavläge kräver mycket lite processorkraft på båda sidor, men kommer att drabbas avsevärt av nätverksfördröjning." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REQUIRE_SLAVES, + "Tillåt inte anslutningar som inte är i slavläge. Rekommenderas inte, utom för mycket snabba nätverk med mycket svaga maskiner." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_NETPLAY_CHECK_FRAMES, + "Frekvensen i bildrutor med vilken netplay kommer att verifiera att värden och klienten är synkroniserade. Med de flesta kärnor har detta värde ingen synlig effekt och kan ignoreras. Med icke-bestämbara kärnor avgör detta värde hur ofta netplay-peers kommer att synkroniseras. Med buggiga kärnor kommer det att orsaka allvarliga prestandaproblem om detta värde sätts till något annat än noll. Ställ in på noll för att inte utföra några kontroller. Detta värde används endast på ne[...]" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Antalet bildrutor med inmatningslatens som netplay ska använda för att dölja nätverkslatens. Minskar jitter och gör netplay mindre CPU-krävande, men på bekostnad av märkbar fördröjning i inmatningen." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Antalet bildrutor med inmatningsfördröjning som netplay ska använda för att dölja nätverksfördröjning.\nNär det här alternativet används i netplay fördröjer det lokal inmatning så att den bildruta som körs ligger närmare de bildrutor som tas emot från nätverket. Detta minskar jitter och gör netplay mindre CPU-intensivt, men till priset av en märkbar fördröjning av inmatningen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Det intervall av bildrutor med inmatningslatens som kan användas för att dölja nätverkslatens. Minskar jitter och gör netplay mindre CPU-krävande, men på bekostnad av oförutsägbar fördröjning i inmatningen." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Det intervall av bildrutor med inmatningslatens som kan användas av netplay för att dölja nätverkslatens.\nOm det är inställt kommer netplay att justera antalet bildrutor med inmatningslatens dynamiskt för att balansera CPU-tid, inmatningslatens och nätverkslatens. Detta minskar jitter och gör netplay mindre CPU-intensivt, men till priset av oförutsägbar inmatningsfördröjning." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICE_I, "Begär enhet %u" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_REQUEST_DEVICE_I, + "Begär att få spela med den angivna inmatningsenheten." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, "Nätverkskommandon" @@ -5949,28 +7010,60 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, "Spelare %d Nätverksspelkontroll" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, + "Kommandon för stdin" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, + "stdin kommandogränssnitt." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETWORK_ON_DEMAND_THUMBNAILS, + "Hämta automatiskt ner saknade miniatyrbilder när du bläddrar i spellistor. Har en stor prestandapåverkan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, "Inställningar för uppdaterare" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_UPDATER_SETTINGS, + "Åtkomst till inställningar för kärnuppdatering" + ) /* Settings > Network > Updater */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Packa automatiskt upp hämtade arkiv" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Efter hämtning så packas automatiskt filer upp som finns i de hämtade arkiven." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES, - "Visa experimentella Kärnor" + "Visa experimentella kärnor" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES, - "Inkludera 'experimentella' Kärnor i Ladda ner Kärnor-listan. Dessa är vanligen endast för utveckling/teständamål, och rekommenderas inte för allmän användning." + "Inkludera 'experimentella' kärnor i Hämta ner kärnor-listan. Dessa är vanligen endast för utveckling/teständamål, och rekommenderas inte för allmän användning." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_BACKUP, - "Säkerhetskopiera Kärnor vid uppdatering" + "Säkerhetskopiera kärnor vid uppdatering" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_BACKUP, - "Skapa automatiskt en säkerhetskopia av installerade Kärnor när en online-uppdatering utförs. Möjliggör enkel återställning till en fungerande Kärna om en uppdatering introducerar en försämring." + "Skapa automatiskt en säkerhetskopia av installerade kärnor när en online-uppdatering utförs. Möjliggör enkel återställning till en fungerande kärna om en uppdatering introducerar en försämring." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE, + "Storlek för säkerhetskopieringshistorik för kärnor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE, + "Ange hur många automatiskt genererade säkerhetskopior som ska sparas för varje installerad kärna. När denna gräns har uppnåtts kommer den äldsta säkerhetskopian att raderas när en ny säkerhetskopia skapas via en onlineuppdatering. Manuella säkerhetskopior av kärnor påverkas inte av denna inställning." ) /* Settings > Playlists */ @@ -5979,22 +7072,58 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, "Historik" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, + "Underhåll en spellista med nyligen använda spel, bilder, musik och videor." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, "Historik storlek" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, + "Begränsa antalet poster i den senaste spellistan för spel, bilder, musik och videor." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_FAVORITES_SIZE, "Favoriters storlek" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_FAVORITES_SIZE, + "Begränsa antalet poster i spellistan ”Favoriter”. När gränsen har nåtts förhindras nya poster att läggas till tills gamla poster har tagits bort. Om du ställer in ett värde på -1 tillåts ”obegränsade” poster.\nVARNING: Om du minskar värdet raderas befintliga poster!" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_RENAME, + "Tillåt att byta namn på poster" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_RENAME, + "Tillåt att poster i spellistan byter namn." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, + "Tillåt att ta bort poster" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, + "Tillåt att poster i spellistan tas bort." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_SORT_ALPHABETICAL, "Sortera spellistor alfabetiskt" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_SORT_ALPHABETICAL, + "Sortera innehållsspellistor i alfabetisk ordning, med undantag för spellistorna ”Historik”, ”Bilder”, ”Musik” och ”Videor”." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_USE_OLD_FORMAT, "Spara spellistor med gamla formatet" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_USE_OLD_FORMAT, + "Skriv spellistor med föråldrat klartextformat. När funktionen är inaktiverad formateras spellistorna med JSON." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_COMPRESSION, "Komprimera spellistor" @@ -6005,7 +7134,27 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_SHOW_INLINE_CORE_NAME, - "Visa associerade Kärnor i spellistor" + "Visa associerade kärnor i spellistor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_SHOW_INLINE_CORE_NAME, + "Ange när poster i spellistan ska taggas med den aktuella associerade kärnan (om någon).\nDen här inställningen ignoreras när underetiketter för spellistor är aktiverade." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SHOW_SUBLABELS, + "Visa underetiketter för spellista" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_SHOW_SUBLABELS, + "Visa ytterligare information för varje spellistepost, t. ex. aktuell kärnassociation och körtid (om tillgänglig). Har en varierande prestandapåverkan." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SHOW_HISTORY_ICONS, + "Visa innehållsspecifika ikoner i historik och favoriter" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_SHOW_HISTORY_ICONS, + "Visa specifika ikoner för varje post i historik- och favoritspellistan. Har en varierande prestandapåverkan." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_CORE, @@ -6080,8 +7229,16 @@ MSG_HASH( "sedan" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "Skanna kontrollerar CRC om det finns dubbletter" + MENU_ENUM_SUBLABEL_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE, + "Ställ in stilen för datum och tid som visas för tidsstämpelinformation för ”Senast spelad”. Alternativet ”(AM/PM)” har en liten påverkan på prestandan på vissa plattformar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_FUZZY_ARCHIVE_MATCH, + "Vid sökning i spellistor efter poster som är associerade med komprimerade filer matchas endast arkivets filnamn istället för [filnamn]+[innehåll]. Aktivera detta för att undvika dubbla poster i innehållshistoriken när du laddar komprimerade filer." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCAN_WITHOUT_CORE_MATCH, + "Tillåt att innehåll söks igenom och läggs till i en spellista utan att det finns en kärna installerad som stöder detta." ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, @@ -6091,14 +7248,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LIST, "Hantera Spellistor" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_LIST, + "Genomför underhållsåtgärder på spellistor." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_PORTABLE_PATHS, "Portabla spellistor" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_PORTABLE_PATHS, + "Om alternativet är aktiverat och ”Filbläddrare”-katalogen också är vald sparas det aktuella värdet för parametern ”Filbläddrare” i spellistan. När spellistan laddas på ett annat system där samma alternativ är aktiverat jämförs värdet på parametern ”Filbläddrare” med spellistans värde; om det skiljer sig åt fixas spellistans sökvägar automatiskt." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_USE_FILENAME, + "Använd filnamn för miniatyrbildsmatchning" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_USE_FILENAME, + "När den är aktiverad kommer miniatyrbilder att hittas utifrån postens filnamn, snarare än dess etikett." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_ALLOW_NON_PNG, "Tillåt alla bildtyper som stöds för miniatyrbilder" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_ALLOW_NON_PNG, + "När den är aktiverad kan lokala miniatyrbilder läggas till i alla bildtyper som stöds av RetroArch (t. ex. jpeg). Kan ha en mindre inverkan på prestandan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MANAGE, "Hantera" @@ -6110,26 +7287,50 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_DEFAULT_CORE, "Standard Kärna" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_DEFAULT_CORE, + "Ange vilken kärna som ska användas när innehåll startas via en spellistepost som inte har någon befintlig kärn-association." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_RESET_CORES, "Återställ kärnassociationer" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_RESET_CORES, + "Ta bort befintliga kärnassociationer för alla spellisteposter." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE, "Visningsläge för Titlar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE, + "Ändra hur innehållsetiketterna visas i den här spellistan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_SORT_MODE, "Sorteringsmetod" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_SORT_MODE, + "Bestäm hur posterna ska sorteras i den här spellistan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_CLEAN_PLAYLIST, "Rensa Spellista" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_CLEAN_PLAYLIST, + "Validera kärnassociationer och ta bort ogiltiga och duplicerade poster." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_REFRESH_PLAYLIST, "Uppdatera spellista" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_REFRESH_PLAYLIST, + "Lägg till nytt innehåll och ta bort ogiltiga poster genom att upprepa ”Manuell skanning” som senast användes för att skapa eller redigera spellistan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DELETE_PLAYLIST, "Radera Spellista" @@ -6153,6 +7354,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, "Konton" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, + "Hantera aktuella konfigurerade konton." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, "Användarnamn" @@ -6169,6 +7374,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USER_LANGUAGE, "Ställ in språket för användargränssnittet." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_USER_LANGUAGE, + "Lokalanpassar menyn och alla meddelanden på skärmen enligt det språk du har valt här. Kräver en omstart för att ändringarna ska träda i kraft.\nÖversättningens fullständighet visas bredvid varje alternativ. Om ett språk inte är implementerat för ett menyalternativ återgår vi till engelska." + ) /* Settings > User > Privacy */ @@ -6178,7 +7387,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CAMERA_ALLOW, - "Tillåt Kärnor att komma åt kameran." + "Tillåt kärnor att komma åt kameran." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISCORD_ALLOW, + "Tillåt Discord-appen att visa data om det innehåll som spelas upp. Endast tillgänglig med den inbyggda skrivbordsklienten." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, @@ -6186,7 +7399,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_LOCATION_ALLOW, - "Tillåt Kärnor att komma åt din plats." + "Tillåt kärnor att komma åt din plats." ) /* Settings > User > Accounts */ @@ -6195,6 +7408,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, "Samla prestationframgångar i klassiska spel. För mer information, besök 'https://retroachievements.org'." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_ACCOUNTS_RETRO_ACHIEVEMENTS, + "Inloggningsuppgifter för ditt RetroAchievements-konto. Besök retroachievements.org och registrera dig för ett gratis konto.\nNNär du är klar med registreringen måste du ange användarnamn och lösenord i RetroArch." + ) /* Settings > User > Accounts > RetroAchievements */ @@ -6202,54 +7419,110 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, "Användarnamn" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, + "Ange ditt användarnamn för RetroAchievements-kontot." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, "Lösenord" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, + "Ange lösenordet för ditt RetroAchievements-konto. Max längd: 255 tecken." + ) /* Settings > User > Accounts > YouTube */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_YOUTUBE_STREAM_KEY, + "Strömningsnyckel för YouTube" + ) /* Settings > User > Accounts > Twitch */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TWITCH_STREAM_KEY, + "Strömningsnyckel för Twitch" + ) /* Settings > User > Accounts > Facebook Gaming */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FACEBOOK_STREAM_KEY, + "Strömningsnyckel för Facebook Gaming" + ) /* Settings > Directory */ +MSG_HASH( + MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, + "BIOS-filer, uppstarts-ROMar och andra systemspecifika filer lagras i denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, - "Nedladdningar" + "Hämtningar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, + "Hämtade filer lagras i denna katalog." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, + "Resurser" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, + "Menyresurser som används av RetroArch lagras i denna katalog." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, "Dynamiska bakgrunder" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, + "Bakgrundsbilder som används i menyn lagras i denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, "Miniatyrer" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, + "Omslagsbilder, skärmbilder och miniatyrbilder för titelskärmar lagras i denna katalog." + ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Filhanterare" + "Start katalog" + ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, + "Ställ in startkatalog för filbläddraren." ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, "Konfigurationsfiler" ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, + "Standardkonfigurationsfilen lagras i denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, "Kärnor" ) MSG_HASH( MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, - "Libretro Kärnor lagras i denna katalog." + "Libretro-kärnor lagras i denna katalog." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, "Kärninformation" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, + "Informationsfiler för applikationer/kärnor lagras i denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, "Databaser" @@ -6298,6 +7571,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, "Inspelning Configs" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, + "Inspelningskonfigurationer lagras i denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, "Överlager" @@ -6314,10 +7591,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OSK_OVERLAY_DIRECTORY, "Tangentbordsöverlager lagras i denna katalog." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_DIRECTORY, + "Videolayouter" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_LAYOUT_DIRECTORY, + "Videolayouter lagras i denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, "Skärmdumpar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, + "Skärmbilder lagras i denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, "Spelkontrollsprofiler" @@ -6326,10 +7615,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, "Spelkontrollsprofiler som automatisk konfigurerar spelkontroller lagras i denna katalog." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, + "Ommappningar för inmatning" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, "Spellistor" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, + "Spellistor lagras i denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_FAVORITES_DIRECTORY, "Favoritspellista" @@ -6342,6 +7639,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_DIRECTORY, "Historikspellista" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_HISTORY_DIRECTORY, + "Spara historikspellistan till denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_IMAGE_HISTORY_DIRECTORY, "Bildspellista" @@ -6350,18 +7651,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_MUSIC_HISTORY_DIRECTORY, "Musikspellista" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_MUSIC_HISTORY_DIRECTORY, + "Spara musikspellistan till denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_VIDEO_HISTORY_DIRECTORY, "Videospellista" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_VIDEO_HISTORY_DIRECTORY, + "Spara videospellistan till denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RUNTIME_LOG_DIRECTORY, "Körningslogg" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUNTIME_LOG_DIRECTORY, + "Körtidsloggar lagras i den här katalogen." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, "Spara filer" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, + "Spara alla sparningsfiler till denna katalog. Om den inte är inställd försöker den spara i innehållsfilens arbetskatalog." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_SAVEFILE_DIRECTORY, "Spara alla filer (*.srm) till denna katalog. Detta inkluderar relaterade filer som .rt, .psrm, etc... Detta kommer att åsidosättas av explicita kommandoradsval." @@ -6374,6 +7691,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, "Dina sparstatusar och inspelningar lagras i denna mapp. Om den inte är inställd hit så kommer den att försöka spara filerna i mappen där spelinnehållet är placerat." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, + "Arkiverat innehåll kommer tillfälligt att extraheras till denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOG_DIR, "System händelselogg" @@ -6395,9 +7716,13 @@ MSG_HASH( "Dela din aktuella status i RetroArch på Steam." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STEAM_RICH_PRESENCE_FORMAT, + "Innehållsformat för Rich Presence" + ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Bestäm vilken information relaterad till innehållet som körs som ska delas." + "Bestäm vilken information som är relaterad till innehållet som ska delas." ) MSG_HASH( @@ -6434,10 +7759,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, "Lägg till i Mixer" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_MIXER, + "Lägg till det här ljudspåret i en tillgänglig ljudströmsplats.\nOm inga platser är tillgängliga för närvarande ignoreras det." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_PLAY, "Lägg till i Mixer och spela" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ADD_TO_MIXER_AND_PLAY, + "Lägg till det här ljudspåret i en tillgänglig ljudströmsplats och spela upp det.\nOm inga platser är tillgängliga för närvarande ignoreras det." + ) /* Netplay */ @@ -6471,11 +7804,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SHOW_ONLY_INSTALLED_CORES, - "Endast installerade Kärnor" + "Endast installerade kärnor" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SHOW_PASSWORDED, - "Lösenordade rum" + "Lösenordsskyddade rum" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, @@ -6603,7 +7936,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_CORE_NAME, - "Välj en standard kärna att använda vid start av skannat innehåll." + "Välj en standardkärna att använda vid start av genomsökt innehåll." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_FILE_EXTS, @@ -6617,14 +7950,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SEARCH_RECURSIVELY, "Sök igenom rekursivt" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_SEARCH_RECURSIVELY, + "När den är aktiverad kommer alla underkataloger i den angivna ”Innehållskatalog” att ingå i sökningen." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SEARCH_ARCHIVES, "Skanna inuti Arkiv" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_SEARCH_ARCHIVES, + "När detta är aktiverat kommer arkivfiler (.zip, .7z, etc.) att genomsökas efter giltigt/stödd innehåll. Kan ha en betydande inverkan på genomsökningsprestandan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_DAT_FILE, "Arkad DAT-fil" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_DAT_FILE, + "Välj en Logiqx eller MAME List XML DAT-fil för att möjliggöra automatisk namngivning av genomsökt arkadinnehåll (MAME, FinalBurn Neo, etc.)." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_DAT_FILE_FILTER, "Arkad DAT-filter" @@ -6633,10 +7978,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_OVERWRITE, "Skriv över befintlig spellista" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_VALIDATE_ENTRIES, + "Validera befintliga poster" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_VALIDATE_ENTRIES, + "När funktionen är aktiverad kommer poster i en befintlig spellista att verifieras innan nytt innehåll söks igenom. Poster som hänvisar till innehåll som saknas och/eller filer med ogiltiga tillägg tas bort." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_START, "Starta skanning" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_START, + "Sök igenom valt innehåll." + ) /* Explore tab */ MSG_HASH( @@ -6723,9 +8080,17 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_EXPLORE_BY_PLATFORM_EXCLUSIVE, "Efter Plattform exklusiv" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_EXPLORE_BY_RUMBLE, + "Efter rumble" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_EXPLORE_BY_SCORE, - "Efter Poäng" + "Efter poäng" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_EXPLORE_BY_MEDIA, + "Efter media" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_EXPLORE_BY_CONTROLS, @@ -6743,10 +8108,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_EXPLORE_BY_NARRATIVE, "Efter berättande" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_EXPLORE_BY_PACING, + "Efter takt" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_EXPLORE_BY_PERSPECTIVE, "Efter perspektiv" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_EXPLORE_BY_SETTING, + "Efter inställning" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_EXPLORE_BY_VISUAL, + "Efter visuellt" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_EXPLORE_BY_VEHICULAR, + "Efter motor" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_EXPLORE_BY_ORIGIN, "Efter ursprung" @@ -6763,6 +8144,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_EXPLORE_BY_SYSTEM_NAME, "Efter systemnamn" ) +MSG_HASH( + MENU_ENUM_LABEL_EXPLORE_RANGE_FILTER, + "Ställ in intervallfilter" + ) MSG_HASH( MENU_ENUM_LABEL_EXPLORE_VIEW, "Visa" @@ -6779,6 +8164,10 @@ MSG_HASH( MENU_ENUM_LABEL_EXPLORE_NEW_VIEW, "Ange namn för ny vy" ) +MSG_HASH( + MENU_ENUM_LABEL_EXPLORE_VIEW_EXISTS, + "Visa redan befintliga med samma namn" + ) MSG_HASH( MENU_ENUM_LABEL_EXPLORE_VIEW_SAVED, "Vy sparad" @@ -6802,10 +8191,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RENAME_ENTRY, "Byt namn" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RENAME_ENTRY, + "Byt namn på titeln för posten." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, "Ta bort" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DELETE_ENTRY, + "Ta bort denna post från spellistan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST, "Lägg till i Favoriter" @@ -6842,9 +8239,21 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RESET_CORE_ASSOCIATION, "Återställ kärnassociation" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESET_CORE_ASSOCIATION, + "Återställ kärnan som är kopplad till detta innehåll." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INFORMATION, + "Visa mer information om innehållet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DOWNLOAD_PL_ENTRY_THUMBNAILS, - "Ladda ner miniatyrer" + "Hämta ner miniatyrer" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS, + "Hämta ner miniatyrbilder för skärmdump/omslag/titelskärm för aktuellt innehåll. Uppdaterar eventuella befintliga miniatyrbilder." ) /* Playlist Item > Set Core Association */ @@ -6893,7 +8302,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Återupptar det pågående innehållet och lämnar Snabbmenyn." + "Återuppta innehållet och lämna snabbmenyn." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -6909,7 +8318,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Stäng det aktuella innehållet. Eventuella osparade ändringar kan gå förlorade." + "Stäng innehållet. Eventuella osparade ändringar kan gå förlorade." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -6937,11 +8346,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOAD_STATE, - "Ladda status" + "Läs in tillstånd" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOAD_STATE, + "Läs in ett sparat tillstånd från den aktuella valda platsen." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, - "Ångra Ladda status" + "Ångra Läs in tillstånd" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, @@ -7003,6 +8416,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_START_STREAMING, "Börja streama" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_START_STREAMING, + "Starta strömning till valt mål." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_STOP_STREAMING, + "Stoppa strömning" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_STOP_STREAMING, + "Avsluta ström." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_LIST, "Sparade statusar" @@ -7015,14 +8440,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "Kärnalternativ" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_OPTIONS, + "Ändra alternativen för innehållet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "Spelkontroller" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, + "Ändra kontrollerna för innehållet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Fusk" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, + "Konfigurera fuskkoder." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, "Skivhantering" @@ -7035,6 +8472,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_OVERRIDE_OPTIONS, "Åsidosätter" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_OVERRIDE_OPTIONS, + "Alternativ för att åsidosätta global konfiguration." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, "Prestationer" @@ -7050,6 +8491,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTION_OVERRIDE_LIST, "Hantera kärnalternativ" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_OPTION_OVERRIDE_LIST, + "Spara eller ta bort alternativåsidosättningar för aktuella innehållet." + ) /* Quick Menu > Options > Manage Core Options */ @@ -7057,21 +8502,57 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_CORE_OPTIONS_CREATE, "Spara spelalternativ" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_SPECIFIC_CORE_OPTIONS_CREATE, + "Spara kärnalternativ som tillämpas endast för det aktuella innehållet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_CORE_OPTIONS_REMOVE, "Ta bort spelalternativ" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_SPECIFIC_CORE_OPTIONS_REMOVE, + "Ta bort kärnalternativ som tillämpas endast för det aktuella innehållet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FOLDER_SPECIFIC_CORE_OPTIONS_CREATE, "Spara Innehålls-inställningar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FOLDER_SPECIFIC_CORE_OPTIONS_CREATE, + "Spara kärnalternativ som tillämpas för allt innehåll inläst från samma katalog som den aktuella filen." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FOLDER_SPECIFIC_CORE_OPTIONS_REMOVE, + "Ta bort alternativ för innehållskatalog" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FOLDER_SPECIFIC_CORE_OPTIONS_REMOVE, + "Ta bort kärnalternativ som tillämpas för allt innehåll inläst från samma katalog som den aktuella filen." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTION_OVERRIDE_INFO, - "Aktiv alternativ-fil" + "Aktiv alternativfil" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_OPTION_OVERRIDE_INFO, + "Den aktuella alternativfilen som används." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Återställ alternativ" + "Nollställ kärnalternativ" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, + "Ställ in alla alternativ för den aktuella kärnan till standardvärden." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, + "Skriv alternativ till disk" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_OPTIONS_FLUSH, + "Tvinga aktuella inställningar att skrivas till den aktiva alternativfilen. Säkerställer att alternativ bevaras i händelse av att en kärnbugg orsakar felaktig avstängning av frontend." ) /* - Legacy (unused) */ @@ -7089,6 +8570,10 @@ MSG_HASH( /* Quick Menu > Controls > Manage Remap Files */ +MSG_HASH( + MENU_ENUM_SUBLABEL_REMAP_FILE_LOAD, + "Läs in och ersätt nuvarande inmatningsmappningar." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, "Spara spelommappningsfil" @@ -7123,6 +8608,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, "Läs in en fuskfil och ersätt befintliga fusk." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD_APPEND, + "Läs in fuskfil (lägg till)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD_APPEND, + "Läs in en fuskfil och lägg till i befintliga fusk." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RELOAD_CHEATS, + "Läs om spelspecifika fusk" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, "Spara fuskfil som" @@ -7315,6 +8812,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DESC, "Beskrivning" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_HANDLER, + "Hanterare" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_MEMORY_SEARCH_SIZE, + "Sökstorlek för minne" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_TYPE, "Typ" @@ -7335,10 +8840,26 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_ADDRESS_BIT_POSITION, "Mask för minnesadress" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_ADDRESS_BIT_POSITION, + "Adressbitmask när minnesstorlek för sökning < 8-bitars." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_REPEAT_COUNT, "Antal iterationer" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_VALUE, + "Rumble-värde" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PORT, + "Rumble-port" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_RUMBLE_PRIMARY_STRENGTH, + "Primär Rumble-styrka" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_CODE, "Kod" @@ -7384,7 +8905,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, - "Ladda ny skiva" + "Läs in ny skiva" ) MSG_HASH( MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, @@ -7398,41 +8919,101 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_DISK_INDEX, "Aktuellt skivindex" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DISK_INDEX, + "Välj aktuell skiva från listan över tillgängliga avbilder. Skivan läses in när ”Mata in skiva” väljs." + ) /* Quick Menu > Shaders */ +MSG_HASH( + MENU_ENUM_SUBLABEL_SHADER_WATCH_FOR_CHANGES, + "Tillämpa automatiskt ändringar som gjorts i shader-filer på disken." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, + "Bevaka shader-filer för nya ändringar. När du har sparat ändringar i en shader på disken kommer den automatiskt att kompileras om och tillämpas på innehållet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, "Kom ihåg senast använda Shader-katalog" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_REMEMBER_LAST_DIR, + "Öppna filbläddrare vid senast använda katalog när shader-förval och pass läses in." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, - "Ladda förinställd" + "Läs in förinställd" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, - "Ladda en förinställd Shader. Shader pipelinen kommer automatiskt att konfigureras." + "Läs in en förinställd Shader. Shader pipelinen kommer automatiskt att konfigureras." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_SHADER_PRESET, + "Läs in en shader-förinställning direkt. Shader-menyn uppdateras i enlighet med detta.\nSkaleringsfaktorn som visas i menyn är tillförlitlig endast om förinställningen använder enkla skalningsmetoder (dvs. källskalning, samma skalningsfaktor för X/Y)." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_APPEND, + "Lägg till förval" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE, "Spara förinställning" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE, + "Spara aktuella shader-förvalet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE, "Ta bort förinställning" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_REMOVE, + "Ta bort ett automatiskt shader-förval." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, "Tillämpa ändringar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, + "Ändringar i shaderkonfigurationen träder i kraft omedelbart. Använd detta om du har ändrat antalet shaderpass, filtrering, FBO-skala etc." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_SHADER_APPLY_CHANGES, + "När du har ändrat shaderinställningar, t.ex. antal shaderpass, filtrering, FBO-skala, använder du detta för att tillämpa ändringarna.\nAtt ändra dessa shaderinställningar är en ganska dyr operation så det måste göras uttryckligen.\nNär du tillämpar shaders sparas shaderinställningarna i en tillfällig fil (retroarch.slangp/.cgp/.glslp) och läses in. Filen finns kvar efter att RetroArch har avslutats och sparas i Shader-katalogen." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, "Shader parametrar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, + "Modifiera den aktuella shadern direkt. Ändringar sparas inte i den förinställda filen." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_SHADER_NUM_PASSES, + "RetroArch gör det möjligt att blanda och matcha olika shaders med godtyckliga shaderpass, med anpassade hårdvarufilter och skalfaktorer.\nDetta alternativ anger antalet shaderpass som ska användas. Om du ställer in det på 0 och använder Apply Shader Changes använder du en ”tom” shader." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_SHADER_PASS, + "Sökväg till shader. Alla shaders måste vara av samma typ (t.ex. Cg, GLSL eller Slang). Ställ in Shader Directory för att ange var webbläsaren börjar leta efter shaders." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_SHADER_FILTER_PASS, + "Hårdvarufilter för detta pass. Om ”Default” är inställt kommer filtret att vara antingen ”Linear” eller ”Nearest” beroende på inställningen ”Bilinear Filtering” under Video settings." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCALE, "Skala" ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SCALE_PASS, + "Skala för detta pass. Skalfaktorn ackumuleras, dvs. 2x för första passet och 2x för andra passet ger dig en total skala på 4x.\nOm det finns en skalfaktor för sista passet sträcks resultatet till skärmen med standardfiltret, beroende på inställningen Bilineär filtrering under Videoinställningar.\nOm ”Standard” är inställt används antingen 1x skala eller sträckning till fullskärm beroende på om det inte är sista passet eller inte." + ) /* Quick Menu > Shaders > Save */ @@ -7441,25 +9022,89 @@ MSG_HASH( "Enkla förinställningar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_REFERENCE, + "Spara en shader-förinställning som har en länk till den ursprungliga förinställningen och som endast innehåller de parameterändringar som du har gjort." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, "Spara förinställd Shader som" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_AS, + "Spara de aktuella shaderinställningarna som en ny shaderförinställning." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GLOBAL, "Spara globalt förval" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GLOBAL, + "Spara de aktuella shaderinställningarna som global standardinställning." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, "Spara kärnförval" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, + "Spara de aktuella shaderinställningarna som standard för den här kärnan." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT, + "Spara förval för innehållskatalog" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_PARENT, + "Spara de aktuella shaderinställningarna som standard för alla filer i den aktuella innehållskatalogen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, + "Spara de aktuella shaderinställningarna som standardinställningar för innehållet." + ) /* Quick Menu > Shaders > Remove */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PRESETS_FOUND, + "Inga automatiska shader-förinställningar hittades" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_GLOBAL, + "Ta bort globalt förval" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_REMOVE_GLOBAL, + "Ta bort den globala förinställningen, som används av allt innehåll och alla kärnor." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_CORE, + "Ta bort kärnförval" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_REMOVE_CORE, + "Ta bort förinställningen för kärna, som används av allt innehåll som körs med den för närvarande inlästa kärnan." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_PARENT, + "Ta bort förval för innehållskatalog" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_GAME, + "Ta bort spelförval" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_REMOVE_GAME, + "Ta bort förinställningen för spel, som endast används för det specifika spelet i fråga." + ) /* Quick Menu > Shaders > Shader Parameters */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, + "Inga shader-parametrar" + ) /* Quick Menu > Overrides */ @@ -7487,6 +9132,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OVERRIDE_FILE_SAVE_AS, "Spara aktuell konfiguration som en ny åsidosättningsfil." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Spara en åsidosatt konfigurationsfil som kommer att gälla för allt innehåll som laddas med denna kärna. Kommer att ha företräde framför huvudkonfigurationen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR, + "Spara en överordnad konfigurationsfil som kommer att gälla för allt innehåll som laddas från samma katalog som den aktuella filen. Kommer att ha företräde framför huvudkonfigurationen." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERRIDE_UNLOAD, + "Läs ur åsidosättning" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERRIDE_UNLOAD, + "Nollställ alla alternativ till globala konfigurationsvärden." + ) /* Quick Menu > Achievements */ @@ -7494,6 +9155,50 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY, "Inga prestationer att visa" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE_CANCEL, + "Lämna hardcore-läget för prestationer aktiverat för den aktuella sessionen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME_CANCEL, + "Avbryt återupptagning av hardcore-läget för prestationer" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME_CANCEL, + "Lämna hardcore-läget för prestationer inaktiverat för den aktuella sessionen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE, + "Pausa hardcore-läget för prestationer" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE, + "Pausa hardcore-läget för prestationer för den aktuella sessionen. Den här åtgärden aktiverar fusk, spola tillbaka, slowmotion och läsa in sparade tillstånd." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME, + "Återuppta hardcore-läget för prestationer" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, + "Återuppta hardcore-läget för prestationer för den aktuella sessionen. Den här åtgärden inaktiverar fusk, spola tillbaka, slowmotion och ladda sparade tillstånd och återställer det aktuella spelet." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_SERVER_UNREACHABLE, + "RetroAchievements-servern går inte att nå" +) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACHIEVEMENT_SERVER_UNREACHABLE, + "En eller flera upplåsningar av prestationer nådde inte fram till servern. Upplåsningarna kommer att försöka igen så länge du lämnar appen öppen." +) +MSG_HASH( + MENU_ENUM_LABEL_CHEEVOS_SERVER_DISCONNECTED, + "RetroAchievements server går inte att nå. Kommer att försöka igen tills det lyckas eller appen stängs." +) +MSG_HASH( + MENU_ENUM_LABEL_CHEEVOS_SERVER_RECONNECTED, + "Alla väntande förfrågningar har synkroniserats till RetroAchievements-servern." +) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_IDENTIFYING_GAME, "Identifierar spelet" @@ -7525,16 +9230,28 @@ MSG_HASH( /* Quick Menu > Information */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_INFO_CHEEVOS_HASH, + "Kontrollsumma för RetroAchievements" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DETAIL, + "Databaspost" + ) MSG_HASH( MENU_ENUM_SUBLABEL_RDB_ENTRY_DETAIL, "Visa databasinformation för aktuellt innehåll." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, + "Inga poster att visa" + ) /* Miscellaneous UI Items */ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, - "Inga Kärnor tillgängliga" + "Inga kärnor tillgängliga" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, @@ -7596,6 +9313,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SEARCH, "Sök" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Välj slumpmässigt" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Tillbaka" @@ -7671,6 +9392,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NONE, "Ingen" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NO_PREFERENCE, + "Ingen inställning" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_TICKER_TYPE_BOUNCE, "Studsa vänster/höger" @@ -7683,6 +9408,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AI_SERVICE_IMAGE_MODE, "Bildläge" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AI_SERVICE_SPEECH_MODE, + "Talläge" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AI_SERVICE_NARRATOR_MODE, + "Berättarläge" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE_ENABLE_HIST_FAV, "Historik & Favoriter" @@ -7697,7 +9430,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_INLINE_CORE_DISPLAY_HIST_FAV, - "Historik & Favoriter" + "Historik och favoriter" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_INLINE_CORE_DISPLAY_ALWAYS, @@ -7709,7 +9442,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_RUNTIME_PER_CORE, - "Per Kärna" + "Per kärna" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED, @@ -7775,6 +9508,14 @@ MSG_HASH( MENU_ENUM_LABEL_RUMBLE_TYPE_DECREASE, "Minskar" ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_LT_VALUE, + "< Rumble-värde" + ) +MSG_HASH( + MENU_ENUM_LABEL_RUMBLE_TYPE_GT_VALUE, + "> Rumble-värde" + ) MSG_HASH( MENU_ENUM_LABEL_RUMBLE_PORT_16, "Alla" @@ -7887,6 +9628,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, "Titelskärm" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_LOGOS, + "Innehållslogotyp" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCROLL_FAST, "Snabb" @@ -7967,10 +9712,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NEAREST, "Närmsta" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MAIN, + "Huvudsaklig" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT, "Innehåll" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_CORE_NAME_DETECT, + "" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, "Vänster Analog" @@ -8106,10 +9859,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_MENU_COLOR_THEME, "Färgtema" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_MENU_COLOR_THEME, + "Välj ett annat färgtema. Om du väljer ”Anpassad” kan du använda förinställda filer för menyteman." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_MENU_THEME_PRESET, "Anpassat temaförval" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RGUI_MENU_THEME_PRESET, + "Välj ett förinställt menytema från filbläddraren." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_TRANSPARENCY, "Genomskinlighet" @@ -8126,10 +9887,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_PARTICLE_EFFECT, "Animerad bakgrund" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_PARTICLE_EFFECT, + "Aktivera animeringseffekt för bakgrundspartiklar. Har en betydande prestandapåverkan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_PARTICLE_EFFECT_SPEED, "Animerad bakgrunds hastighet" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_PARTICLE_EFFECT_SPEED, + "Justera hastigheten på animationseffekterna för bakgrundspartiklar." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_PARTICLE_EFFECT_SCREENSAVER, + "Bakgrundsanimering för skärmsläckare" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_INLINE_THUMBNAILS, + "Visa miniatyrbilder för spellista" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_INLINE_THUMBNAILS, + "Aktivera visning av nedskalade miniatyrbilder inline när du visar spellistor. Växlingsbar med RetroPad Select. När funktionen är inaktiverad kan miniatyrbilderna fortfarande växlas till helskärm med RetroPad Start." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAILS_RGUI, "Övre miniatyrbild" @@ -8142,6 +9923,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SWAP_THUMBNAILS, "Växla miniatyrbilder" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_THUMBNAIL_DELAY, + "Tillämpar en tidsfördröjning mellan valet av en spellistepost och laddningen av dess tillhörande miniatyrbilder. Om du ställer in detta till ett värde på minst 256 ms möjliggörs snabb och fördröjningsfri rullning även på de långsammaste enheterna." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_EXTENDED_ASCII, "Utökat ASCII-stöd" @@ -8336,18 +10121,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS, "Sekundär miniatyrbild" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Miniatyrbild för ikon" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Dynamisk bakgrund" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, + "Läs in en ny bakgrundsbild dynamiskt beroende på kontext." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, "Horisontell animering" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_HORIZONTAL_ANIMATION, + "Aktivera horisontell animering för menyn. Detta kommer att påverka prestandan." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_FONT, "Typsnitt" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_FONT, + "Välj ett annat huvudsakligt teckensnitt som ska användas av menyn." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_RED, "Teckenfärg (röd)" @@ -8360,10 +10161,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_FONT_COLOR_BLUE, "Teckenfärg (blå)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_LAYOUT, + "Välj en annan layout för XMB-gränssnittet." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_THEME, "Ikontema" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_THEME, + "Välj ett annat ikontema för RetroArch." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_SWITCH_ICONS, "Skifta ikoner/text" @@ -8376,6 +10185,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, "Skuggeffekter" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, + "Välj en animerad bakgrundseffekt. Kan vara GPU-intensiv beroende på effekten. Om prestandan är otillfredsställande kan du antingen stänga av den eller återgå till en enklare effekt." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, "Färgtema" @@ -8511,6 +10324,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Iskall" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Grå Mörk" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Grå Ljus" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -8530,6 +10351,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_TRUNCATE_PLAYLIST_NAME, "Ta bort tillverkarens namn från spellistorna. Till exempel, 'Sony - PlayStation' blir 'PlayStation'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, + "Sortera spellistor efter avkortat namn (omstart krävs)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, + "Spellistorna kommer att sorteras om i alfabetisk ordning efter att tillverkarkomponenten i deras namn har tagits bort." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Sekundär miniatyrbild" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "När den är aktiverad kommer varje metadataobjekt som visas i spellistornas högra sidofält (associerad kärna, speltid) att uppta en enda rad; strängar som överskrider sidofältets bredd kommer att visas som rullande tickertext. När den är inaktiverad visas varje innehållsmetadata statiskt, omslaget så att det upptar så många rader som krävs." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Miniatyrskalfaktor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Skala storleken på miniatyrfältet." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Färgtema" @@ -8566,18 +10412,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRAY_LIGHT, "Grå Ljus" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Sekundär miniatyrbild" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Miniatyrskalfaktor" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Skala storleken på miniatyrfältet." - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -8597,6 +10432,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_SWITCH_ICONS, "Använd ikoner istället för PÅ/AV-text för att representera 'omkopplare' menyinställningar." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_PLAYLIST_ICONS_ENABLE, + "Spellistikoner (omstart krävs)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_PLAYLIST_ICONS_ENABLE, "Visa systemspecifika ikoner i spellistorna." @@ -8821,7 +10660,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_LOAD_CORE, - "&Ladda Kärna..." + "&Läs in kärna..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_UNLOAD_CORE, + "Läs &ur kärna" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_EXIT, @@ -8859,6 +10702,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, "Kom ihåg fönstergeometri:" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB, + "Kom ihåg senaste filk i innehållsbläddraren:" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME, "Tema:" @@ -8897,11 +10744,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_LOAD_CORE, - "Ladda Kärna" + "Läs in kärna" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_LOADING_CORE, - "Laddar kärna..." + "Läser in kärna..." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_NAME, @@ -8939,6 +10786,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, "Titelskärm" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_LOGO, + "Logotyp" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, "Alla spellistor" @@ -9045,7 +10896,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST, - "Föreslå laddad kärna först:" + "Föreslå inläst kärna först:" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_VIEW, @@ -9111,6 +10962,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ADDING_FILES_TO_PLAYLIST, "Lägger till filer i spellista..." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY, + "Spellistpost" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_NAME, "Namn:" @@ -9131,10 +10986,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS, "Tillägg:" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS_PLACEHOLDER, + "(blankstegsseparerade; inkluderar alla som standard)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_FILTER_INSIDE_ARCHIVES, "Filtrera inuti arkiv" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS, + "(används för att hitta miniatyrbilder)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM, "Är du säker på att du vill radera objektet \"%1\"?" @@ -9147,6 +11010,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DELETE, "Radera" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY, + "Lägg till post..." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ADD_FILES, "Lägg till fil(er)..." @@ -9167,6 +11034,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_SELECT_FOLDER, "Välj mapp" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE, + "" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_COULD_NOT_UPDATE_PLAYLIST_ENTRY, + "Fel vid uppdatering av spellistepost." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS, "Fyll i alla nödvändiga fält." @@ -9175,6 +11050,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY, "Uppdatera RetroArch (nightly)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED, + "RetroArch uppdaterades. Starta om programmet för att ändringarna ska ta effekt." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, "Uppdateringen misslyckades." @@ -9197,7 +11076,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_LOAD, - "Ladda" + "Läs in" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_SAVE, @@ -9207,10 +11086,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_REMOVE, "Ta bort" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_REMOVE_PASSES, + "Ta bort pass" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_APPLY, "Tillämpa" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + "Lägg till pass" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + "Töm alla pass" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, + "Inga shader-pass." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_PASS, + "Nollställ pass" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES, + "Nollställ alla pass" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER, "Återställ parameter" @@ -9223,6 +11126,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_ALREADY_IN_PROGRESS, "En hämtning pågår redan." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST, + "Starta med spellista:" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THUMBNAIL_TYPE, "Miniatyrbild" @@ -9258,10 +11165,26 @@ MSG_HASH( /* Unsorted */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, + "Inställningar för kärnuppdateraren" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, + "Turbo/Dödzon" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, + "Kärnräknare" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_DISK, "Ingen skiva vald" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, + "Frontend-räknare" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, "Horisontell meny" @@ -9274,6 +11197,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, "Historik" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOAD_CONTENT_HISTORY, + "Välj innehåll från spellistan med senaste historik." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_LOAD_CONTENT_HISTORY, + "När innehåll läses in sparas innehåll och libretro core-kombinationer i historiken.\nHistoriken sparas i en fil i samma katalog som konfigurationsfilen för RetroArch. Om ingen konfigurationsfil lästs in vid uppstart sparas eller läses inte historiken in och den finns inte i huvudmenyn." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SUBSYSTEM_SETTINGS, "Delsystem" @@ -9290,6 +11221,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_NETPLAY_CLIENTS_FOUND, "Inga netplay-klienter hittades." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, + "Inga prestandaräknare." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, "Inga spellistor." @@ -9320,7 +11255,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_START_CORE, - "Starta Kärna" + "Starta kärna" ) MSG_HASH( MENU_ENUM_SUBLABEL_START_CORE, @@ -9343,13 +11278,21 @@ MSG_HASH( "Tgb" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Använd inbyggd bildvisare" + MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Säger till videodrivrutinen att uttryckligen använda ett specificerat buffringsläge." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Maximalt antal swapchain-bilder. Detta kan tala om för videodrivrutinen att den ska använda ett specifikt videobuffringsläge.\nEnkel buffring - 1\nDubbel buffring - 2\nTrippel buffring - 3\nAtt välja rätt buffringsläge kan ha stor inverkan på latensen." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WAITABLE_SWAPCHAINS, "Hårdsynkronisera CPU och GPU. Minskar latens på bekostnad av prestanda." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_MAX_FRAME_LATENCY, + "Säger till videodrivrutinen att uttryckligen använda ett specificerat buffringsläge." + ) MSG_HASH( MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, "Förinställd Shader" @@ -9370,6 +11313,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_URL, "URL-sökväg" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BROWSE_START, + "Starta" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, "Nicknamn: %s" @@ -9386,6 +11333,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_NO_PLAYLISTS, "Inga spellistor hittades" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, + "Kompatibelt innehåll hittades" + ) /* Unused (Only Exist in Translation Files) */ @@ -9405,6 +11356,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, "Inspelning-stöd" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_PATH, + "Spara utdatainspelning som..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, + "Spara inspelningar i utdatakatalog" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_MATCH_IDX, "Visa träff #" @@ -9417,18 +11376,18 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Välj från en spellista" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Återuppta" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Återupptar det pågående innehållet och lämnar Snabbmenyn." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Visa listan över %u träffar" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_CREATE_OPTION, + "Skapa kod från denna matchning" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, + "Ta bort denna matchning" + ) MSG_HASH( /* FIXME Still exists in a comment about being removed */ MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, "Sidfots opacitet" @@ -9449,6 +11408,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, "Starta innehåll" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_PATH, + "Sökväg för innehållshistorik" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CRT_SWITCH_RESOLUTION_OUTPUT_DISPLAY_ID, + "Välj utgångsporten som är ansluten till CRT-skärmen." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HELP, "Hjälp" @@ -9457,9 +11424,13 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CLEAR_SETTING, "Rensa" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, + "Felsökning för ljud/video" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, - "Laddar innehåll" + "Läser in innehåll" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, @@ -9501,6 +11472,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, "Beskrivning" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_START_SEARCH, + "Starta sökning efter ny fuskkod" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_START_SEARCH, + "Starta sökning efter ett nytt fusk. Antal bitar kan ändras." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_CONTINUE_SEARCH, "Fortsätt sök" @@ -9517,10 +11496,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_DETAILS, "Fuskdetaljer" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_DETAILS, + "Hanterar inställningar för fuskdetaljer." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_SEARCH, "Starta eller fortsätt fusksökning" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_SEARCH, + "Starta eller fortsätt en sökning efter fuskkoder." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, + "Öka eller minska antalet fusk." + ) /* Unused (Needs Confirmation) */ @@ -9544,6 +11535,54 @@ MSG_HASH( MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS, "Starta eller fortsätt fusksökning" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, + "Databas - Filter: Utvecklare" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, + "Databas - Filter: Utgivare" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ORIGIN, + "Databas - Filter: Ursprung" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_FRANCHISE, + "Databas - Filter: Franchise" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ESRB_RATING, + "Databas - Filter: ESRB-betyg" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ELSPA_RATING, + "Databas - Filter: ELSPA-betyg" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PEGI_RATING, + "Databas - Filter: PEGI-betyg" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_CERO_RATING, + "Databas - Filter: CERO-betyg" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_BBFC_RATING, + "Databas - Filter: BBFC-betyg" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_MAX_USERS, + "Databas - Filter: Max användare" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_MONTH, + "Databas - Filter: Lanseringsdatum efter månad" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, + "Databas - Filter: Lanseringsdatum efter år" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, "Databasinformation" @@ -9554,7 +11593,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Seems related to MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, possible duplicate */ MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, - "Nedladdningar" + "Hämtningar" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, @@ -9590,7 +11629,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, - "Scrolla upp" + "Rulla upp" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, @@ -9638,13 +11677,21 @@ MSG_HASH( MSG_NETPLAY_NEED_CONTENT_LOADED, "Innehållet måste läsas in innan netplay kan startas." ) +MSG_HASH( /* FIXME Should be MSG_ */ + MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, + "Kunde inte hitta en lämplig kärna eller innehållsfil, läs in manuellt." + ) +MSG_HASH( /* FIXME Should be MSG_ */ + MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER_FALLBACK, + "Din grafikdrivrutin är inte kompatibel med aktuella videodrivrutinen i RetroArch, faller tillbaka på drivrutinen %s. Starta om RetroArch för att ändringen ska ta effekt." + ) MSG_HASH( /* FIXME Should be MSG_ */ MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_SUCCESS, - "Kärninstallation lyckad" + "Kärninstallation lyckades" ) MSG_HASH( /* FIXME Should be MSG_ */ MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_ERROR, - "Kärninstallation misslyckad" + "Kärninstallation misslyckades" ) MSG_HASH( MSG_CHEAT_DELETE_ALL_INSTRUCTIONS, @@ -9666,14 +11713,34 @@ MSG_HASH( MSG_SENT_DEBUG_INFO, "Skicka felsökningsinformation lyckad. Ditt ID-nummer är %u." ) +MSG_HASH( + MSG_PRESS_TWO_MORE_TIMES_TO_SEND_DEBUG_INFO, + "Tryck två gånger till för att skicka diagnostikinformation till RetroArch-teamet." + ) +MSG_HASH( + MSG_PRESS_ONE_MORE_TIME_TO_SEND_DEBUG_INFO, + "Tryck en gång till för att skicka diagnostikinformation till RetroArch-teamet." + ) MSG_HASH( MSG_AUDIO_MIXER_VOLUME, "Global ljudmixervolym" ) +MSG_HASH( + MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, + "Tyvärr, inte implementerat: kärnor som inte efterfrågar innehåll kan inte delta i netplay." + ) MSG_HASH( MSG_NATIVE, "Inbyggd" ) +MSG_HASH( + MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, + "Okänt netplay-kommando togs emot" + ) +MSG_HASH( + MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, + "Filen finns redan. Sparar till reservbuffert" + ) MSG_HASH( MSG_GOT_CONNECTION_FROM, "Fick anslutning från: \"%s\"" @@ -9682,6 +11749,18 @@ MSG_HASH( MSG_GOT_CONNECTION_FROM_NAME, "Fick anslutning från: \"%s (%s)\"" ) +MSG_HASH( + MSG_PRIVATE_OR_SHARED_ADDRESS, + "Externt nätverk har en privat eller delad adress. Överväg att använda en reläserver." + ) +MSG_HASH( + MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, + "Inga argument angavs och ingen meny inbyggd, visar hjälp..." + ) +MSG_HASH( + MSG_SETTING_DISK_IN_TRAY, + "Matar in skiva i släden" + ) MSG_HASH( MSG_WAITING_FOR_CLIENT, "Väntar på klient..." @@ -9714,6 +11793,34 @@ MSG_HASH( MSG_NETPLAY_S_HAS_JOINED_WITH_INPUT_DEVICES_S, "%.*s är ansluten, med inmatningsenheter %.*s" ) +MSG_HASH( + MSG_NETPLAY_NOT_RETROARCH, + "Ett försök till Netplay-anslutning misslyckades eftersom motparten inte kör RetroArch eller kör en gammal version av RetroArch." + ) +MSG_HASH( + MSG_NETPLAY_OUT_OF_DATE, + "En netplay-peer kör en gammal version av RetroArch. Det går inte att ansluta." + ) +MSG_HASH( + MSG_NETPLAY_DIFFERENT_VERSIONS, + "VARNING: En netplay-peer kör en annan version av RetroArch. Om problem uppstår, använd samma version." + ) +MSG_HASH( + MSG_NETPLAY_DIFFERENT_CORES, + "En netplay-peer kör en annan kärna. Det går inte att ansluta." + ) +MSG_HASH( + MSG_NETPLAY_DIFFERENT_CORE_VERSIONS, + "VARNING: En netplay-peer kör en annan version av kärnan. Om problem uppstår ska du använda samma version." + ) +MSG_HASH( + MSG_NETPLAY_ENDIAN_DEPENDENT, + "Denna kärna stöder inte netplay mellan dessa plattformar" + ) +MSG_HASH( + MSG_NETPLAY_PLATFORM_DEPENDENT, + "Denna kärna stöder inte netplay mellan olika plattformar" + ) MSG_HASH( MSG_NETPLAY_ENTER_PASSWORD, "Ange Netplay-serverlösenord:" @@ -9750,10 +11857,18 @@ MSG_HASH( MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, "Detfinns inga lediga spelarplatser" ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY_NOT_AVAILABLE, + "De begärda inmatningsenheterna är inte tillgängliga" + ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY, "Kan inte växla till spelläget" ) +MSG_HASH( + MSG_NETPLAY_PEER_PAUSED, + "Netplay-peer ”%s” pausad" + ) MSG_HASH( MSG_NETPLAY_CHANGED_NICK, "Ditt nicknamn ändrades till \"%s\"" @@ -9790,6 +11905,10 @@ MSG_HASH( MSG_NETPLAY_CHAT_SUPPORTED, "Chatt stöds" ) +MSG_HASH( + MSG_NETPLAY_SLOWDOWNS_CAUSED, + "Fördröjningar orsakade" + ) MSG_HASH( MSG_AUDIO_VOLUME, @@ -9799,10 +11918,6 @@ MSG_HASH( MSG_AUTODETECT, "Autoupptäck" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto ladda sparad status från" - ) MSG_HASH( MSG_CAPABILITIES, "Förmågor" @@ -9837,7 +11952,7 @@ MSG_HASH( ) MSG_HASH( MSG_DOWNLOADING_CORE, - "Laddar ner kärna: " + "Hämtar ner kärna: " ) MSG_HASH( MSG_EXTRACTING_CORE, @@ -9853,7 +11968,7 @@ MSG_HASH( ) MSG_HASH( MSG_SCANNING_CORES, - "Skannar Kärnor..." + "Söker igenom kärnor..." ) MSG_HASH( MSG_CHECKING_CORE, @@ -9861,11 +11976,11 @@ MSG_HASH( ) MSG_HASH( MSG_ALL_CORES_UPDATED, - "Alla installerade Kärnor på senaste version" + "Alla installerade kärnor är senaste versionen" ) MSG_HASH( MSG_ALL_CORES_SWITCHED_PFD, - "Alla Kärnor som stöds ersatta till Play Butik-versioner" + "Alla kärnor som stöds ersatta till Play-butiksversioner" ) MSG_HASH( MSG_NUM_CORES_UPDATED, @@ -9875,6 +11990,10 @@ MSG_HASH( MSG_NUM_CORES_LOCKED, "Kärnor ignorerade: " ) +MSG_HASH( + MSG_CORE_UPDATE_DISABLED, + "Kärnuppdatering inaktiverad - kärnan är låst: " + ) MSG_HASH( MSG_PLAYLIST_MANAGER_RESETTING_CORES, "Återställer kärnor: " @@ -9891,6 +12010,14 @@ MSG_HASH( MSG_PLAYLIST_MANAGER_PLAYLIST_CLEANED, "Spellista rensad: " ) +MSG_HASH( + MSG_PLAYLIST_MANAGER_REFRESH_INVALID_SYSTEM_NAME, + "Uppdatering misslyckades - ogiltigt/saknat systemnamn: " + ) +MSG_HASH( + MSG_PLAYLIST_MANAGER_REFRESH_INVALID_CORE, + "Uppdatering misslyckades - ogiltig kärna: " + ) MSG_HASH( MSG_ADDED_TO_FAVORITES, "Tillagd i favoriter" @@ -9903,6 +12030,18 @@ MSG_HASH( MSG_ADDED_TO_PLAYLIST, "Lades till i spellistan" ) +MSG_HASH( + MSG_ADD_TO_PLAYLIST_FAILED, + "Misslyckades med att lägga till i spellista: spellistan är full" + ) +MSG_HASH( + MSG_SET_CORE_ASSOCIATION, + "Kärnuppsättning: " + ) +MSG_HASH( + MSG_APPENDED_DISK, + "Lade till skivan på slutet" + ) MSG_HASH( MSG_FAILED_TO_APPEND_DISK, "Misslyckades med att lägga till skivan" @@ -9911,6 +12050,10 @@ MSG_HASH( MSG_APPLICATION_DIR, "Programkatalog" ) +MSG_HASH( + MSG_APPLYING_CHEAT, + "Tillämpar fuskändringar." + ) MSG_HASH( MSG_APPLYING_PATCH, "Tillämpar patch: %s" @@ -9931,30 +12074,70 @@ MSG_HASH( MSG_AUTOCONFIG_FILE_ERROR_SAVING, "Fel vid sparande av handkontrollerprofil." ) +MSG_HASH( + MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, + "Kontrollerprofilen sparades." + ) +MSG_HASH( + MSG_AUTOSAVE_FAILED, + "Kunde inte initiera automatisk sparning." + ) MSG_HASH( MSG_AUTO_SAVE_STATE_TO, "Spara status automatiskt till" ) +MSG_HASH( + MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, + "Tar upp kommandogränssnitt på port" + ) +MSG_HASH( + MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, + "Jämför med kända magic numbers..." + ) MSG_HASH( MSG_COMPILED_AGAINST_API, "Kompilerad mot API" ) +MSG_HASH( + MSG_CONFIG_DIRECTORY_NOT_SET, + "Konfigurationskatalog inte inställd. Kan inte spara ny konfiguration." + ) MSG_HASH( MSG_CONNECTED_TO, "Ansluten till" ) +MSG_HASH( + MSG_CONTENT_CRC32S_DIFFER, + "Innehållets CRC32 skiljer sig. Kan inte använda olika spel." + ) MSG_HASH( MSG_CONTENT_NETPACKET_CRC32S_DIFFER, "Värden kör ett annat spel." ) +MSG_HASH( + MSG_PING_TOO_HIGH, + "Din pingtid är för hög för denna värd." + ) MSG_HASH( MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "Kärnan har inget stöd för Spara Statusar." + "Kärnan har inget stöd för sparat tillstånd." + ) +MSG_HASH( + MSG_CORE_OPTIONS_RESET, + "Alla kärnalternativ nollställda till standard." + ) +MSG_HASH( + MSG_CORE_OPTIONS_FLUSHED, + "Kärnalternativ sparades till:" ) MSG_HASH( MSG_CORE_OPTIONS_FLUSH_FAILED, "Misslyckades med att spara kärnalternativen till:" ) +MSG_HASH( + MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, + "Kunde inte hitta någon nästa drivrutin" + ) MSG_HASH( MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, "Kunde inte hitta ett kompatibelt system." @@ -9967,26 +12150,86 @@ MSG_HASH( MSG_COULD_NOT_OPEN_DATA_TRACK, "Kunde inte öppna dataspåret" ) +MSG_HASH( + MSG_COULD_NOT_READ_CONTENT_FILE, + "Kunde inte läsa innehållsfilen" + ) +MSG_HASH( + MSG_COULD_NOT_READ_STATE_FROM_MOVIE, + "Kunde inte läsa tillstånd från film." + ) +MSG_HASH( + MSG_CRC32_CHECKSUM_MISMATCH, + "CRC32-kontrollsumman stämmer inte överens mellan innehållsfilen och kontrollsumman för sparat innehåll i uppspelningsfilens huvud. Uppspelningen kommer med stor sannolikhet att desynkroniseras vid uppspelning." + ) +MSG_HASH( + MSG_CUSTOM_TIMING_GIVEN, + "Anpassad timing angiven" + ) +MSG_HASH( + MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, + "Dekomprimering pågår redan." + ) MSG_HASH( MSG_DECOMPRESSION_FAILED, "Dekomprimeringen misslyckades." ) +MSG_HASH( + MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, + "Hittade inte någon giltig innehållspatch." + ) +MSG_HASH( + MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, + "Koppla från enhet från en giltig port." + ) +MSG_HASH( + MSG_DISK_CLOSED, + "Stängde virtuell skivsläde." + ) +MSG_HASH( + MSG_DISK_EJECTED, + "Matade ut virtuell skivsläde." + ) MSG_HASH( MSG_DOWNLOADING, - "Laddar ner" + "Hämtar ner" ) MSG_HASH( MSG_DOWNLOAD_FAILED, - "Nedladdningen misslyckades" + "Hämtningen misslyckades" ) MSG_HASH( MSG_ERROR, "Fel" ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, + "Libretros kärna kräver innehåll men ingenting tillhandahölls." + ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, + "Libretros kärna kräver speciellt innehåll men ingenting tillhandahölls." + ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_VFS, + "Kärnan har inte stöd för VFS och inläsning från lokal kopia misslyckades" + ) MSG_HASH( MSG_ERROR_PARSING_ARGUMENTS, "Fel vid tolkning av argument." ) +MSG_HASH( + MSG_ERROR_SAVING_CORE_OPTIONS_FILE, + "Fel vid sparning av kärnans alternativfil." + ) +MSG_HASH( + MSG_ERROR_REMOVING_CORE_OPTIONS_FILE, + "Fel vid borttagning av kärnans alternativfil." + ) +MSG_HASH( + MSG_EXTERNAL_APPLICATION_DIR, + "Extern programkatalog" + ) MSG_HASH( MSG_EXTRACTING, "Extraherar" @@ -10015,6 +12258,10 @@ MSG_HASH( MSG_FAILED_TO_APPLY_SHADER_PRESET, "Misslyckades med att tillämpa shader förinställning:" ) +MSG_HASH( + MSG_FAILED_TO_BIND_SOCKET, + "Misslyckades med att binda uttag." + ) MSG_HASH( MSG_FAILED_TO_CREATE_THE_DIRECTORY, "Misslyckades med att skapa katalogen." @@ -10023,18 +12270,30 @@ MSG_HASH( MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, "Misslyckades med att extrahera innehåll från komprimerad fil" ) +MSG_HASH( + MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, + "Misslyckades med att få smeknamn från klient." + ) MSG_HASH( MSG_FAILED_TO_LOAD, - "Misslyckades att ladda" + "Misslyckades att läsa in" ) MSG_HASH( MSG_FAILED_TO_LOAD_CONTENT, - "Misslyckades att ladda Innehåll" + "Misslyckades att läsa in innehåll" ) MSG_HASH( MSG_FAILED_TO_LOAD_MOVIE_FILE, "Misslyckades med att läsa filmfilen" ) +MSG_HASH( + MSG_FAILED_TO_LOAD_OVERLAY, + "Misslyckades med att läsa in överlägg." + ) +MSG_HASH( + MSG_OSK_OVERLAY_NOT_SET, + "Tangentbordsöverlägg är inte inställt." + ) MSG_HASH( MSG_FAILED_TO_LOAD_STATE, "Misslyckades med att läsa in tillstånd från" @@ -10065,7 +12324,7 @@ MSG_HASH( ) MSG_HASH( MSG_FAILED_TO_LOAD_SRAM, - "Det gick inte att ladda SRAM" + "Det gick inte att läsa in SRAM" ) MSG_HASH( MSG_FAILED_TO_SAVE_STATE_TO, @@ -10107,6 +12366,10 @@ MSG_HASH( MSG_FAILED_TO_TAKE_SCREENSHOT, "Misslyckades med att ta skärmbild." ) +MSG_HASH( + MSG_FAILED_TO_UNDO_LOAD_STATE, + "Misslyckades med att ångra inläst tillstånd." + ) MSG_HASH( MSG_FAILED_TO_UNDO_SAVE_STATE, "Misslyckades att få sparad status ogjord." @@ -10131,10 +12394,30 @@ MSG_HASH( MSG_FOUND_FIRST_DATA_TRACK_ON_FILE, "Hittade första dataspåret på fil" ) +MSG_HASH( + MSG_FOUND_LAST_STATE_SLOT, + "Hittade senaste tillståndsplats" + ) +MSG_HASH( + MSG_REPLAY_LOAD_STATE_FAILED_INCOMPAT, + "Inte från aktuell inspelning" + ) +MSG_HASH( + MSG_FOUND_SHADER, + "Hittade shader" + ) MSG_HASH( MSG_FRAMES, "Bildrutor" ) +MSG_HASH( + MSG_GOT_INVALID_DISK_INDEX, + "Fick ogiltigt skivindex." + ) +MSG_HASH( + MSG_GRAB_MOUSE_STATE, + "Tillstånd för musfångst" + ) MSG_HASH( MSG_GAME_FOCUS_ON, "Game Focus aktiv" @@ -10143,10 +12426,30 @@ MSG_HASH( MSG_GAME_FOCUS_OFF, "Game Focus inaktiv" ) +MSG_HASH( + MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, + "Libretro core är hårdvarurenderad. Måste använda post-shaded inspelning också." + ) MSG_HASH( MSG_INPUT_CHEAT, "Mata in fusk" ) +MSG_HASH( + MSG_INPUT_CHEAT_FILENAME, + "Filnamn för inmatningsfusk" + ) +MSG_HASH( + MSG_INPUT_PRESET_FILENAME, + "Filnamn för inmatningsförval" + ) +MSG_HASH( + MSG_INPUT_OVERRIDE_FILENAME, + "Filnamn för inmatningsåsidosättning" + ) +MSG_HASH( + MSG_INPUT_REMAP_FILENAME, + "Filnamn för inmatningsommappning" + ) MSG_HASH( MSG_INPUT_RENAME_ENTRY, "Döp om titel" @@ -10187,9 +12490,13 @@ MSG_HASH( MSG_LIBRETRO_FRONTEND, "Frontend för libretro" ) +MSG_HASH( + MSG_LOADED_STATE_FROM_SLOT, + "Läste in tillstånd från plats #%d." + ) MSG_HASH( MSG_LOADING, - "Laddar" + "Läser in" ) MSG_HASH( MSG_FIRMWARE, @@ -10197,15 +12504,15 @@ MSG_HASH( ) MSG_HASH( MSG_LOADING_CONTENT_FILE, - "Laddar innehållsfil" + "Läser in innehållsfil" ) MSG_HASH( MSG_LOADING_HISTORY_FILE, - "Laddar historikfil" + "Läser in historikfil" ) MSG_HASH( MSG_LOADING_FAVORITES_FILE, - "Laddar favoriterfil" + "Läser in favoriterfil" ) MSG_HASH( MSG_LOADING_STATE, @@ -10239,6 +12546,18 @@ MSG_HASH( MSG_NO_STATE_HAS_BEEN_LOADED_YET, "Inget tillstånd har lästs in än." ) +MSG_HASH( + MSG_OVERRIDES_ERROR_SAVING, + "Fel vid sparning av åsidosättningar." + ) +MSG_HASH( + MSG_OVERRIDES_NOT_SAVED, + "Inget att spara. Åsidosättningar inte sparade." + ) +MSG_HASH( + MSG_OVERRIDES_ACTIVE_NOT_SAVING, + "Sparar inte. Åsidosättningar aktiva." + ) MSG_HASH( MSG_PAUSED, "Pausad." @@ -10255,10 +12574,22 @@ MSG_HASH( MSG_REDIRECTING_CHEATFILE_TO, "Dirigerar om fuskfil till" ) +MSG_HASH( + MSG_REDIRECTING_SAVEFILE_TO, + "Omdirigerar sparad fil till" + ) MSG_HASH( MSG_REDIRECTING_SAVESTATE_TO, "Omdirigerar sparad status till" ) +MSG_HASH( + MSG_REMOVED_DISK_FROM_TRAY, + "Tog bort skiva från släde." + ) +MSG_HASH( + MSG_REMOVING_TEMPORARY_CONTENT_FILE, + "Tar bort temporär innehållsfil" + ) MSG_HASH( MSG_RESET, "Återställ" @@ -10287,14 +12618,26 @@ MSG_HASH( MSG_SAVED_STATE_TO_SLOT_AUTO, "Sparade status till plats #-1 (Auto)." ) +MSG_HASH( + MSG_SAVED_SUCCESSFULLY_TO, + "Sparades till" + ) MSG_HASH( MSG_SAVING_RAM_TYPE, "Sparar RAM-typ" ) +MSG_HASH( + MSG_SAVING_STATE, + "Sparar tillstånd" + ) MSG_HASH( MSG_SCANNING, "Skannar" ) +MSG_HASH( + MSG_SCANNING_OF_DIRECTORY_FINISHED, + "Genomsökning av katalog färdig." + ) MSG_HASH( MSG_SENDING_COMMAND, "Skickar kommando" @@ -10303,6 +12646,10 @@ MSG_HASH( MSG_FAST_FORWARD, "Snabbspolning." ) +MSG_HASH( + MSG_SRAM_WILL_NOT_BE_SAVED, + "SRAM kommer inte att sparas." + ) MSG_HASH( MSG_STARTING_MOVIE_PLAYBACK, "Startar uppspelning av film." @@ -10311,6 +12658,14 @@ MSG_HASH( MSG_STARTING_MOVIE_RECORD_TO, "Startar filminspelning till" ) +MSG_HASH( + MSG_STATE_SIZE, + "Tillståndsstorlek" + ) +MSG_HASH( + MSG_STATE_SLOT, + "Tillståndsplats" + ) MSG_HASH( MSG_TAKING_SCREENSHOT, "Tar skärmdump." @@ -10323,6 +12678,10 @@ MSG_HASH( MSG_ACHIEVEMENT_UNLOCKED, "Prestation upplåst" ) +MSG_HASH( + MSG_RARE_ACHIEVEMENT_UNLOCKED, + "Sällsynt prestation upplåst" + ) MSG_HASH( MSG_LEADERBOARD_SUBMISSION, "Skickade in %s för %s" /* Submitted [value] for [leaderboard name] */ @@ -10347,6 +12706,10 @@ MSG_HASH( MSG_NO_THUMBNAIL_AVAILABLE, "Ingen miniatyrbild tillgänglig" ) +MSG_HASH( + MSG_NO_THUMBNAIL_DOWNLOAD_POSSIBLE, + "Alla möjliga hämtningar av miniatyrbilder har redan provats för den här spellisteposten." + ) MSG_HASH( MSG_PRESS_AGAIN_TO_QUIT, "Tryck igen för att avsluta..." @@ -10367,10 +12730,22 @@ MSG_HASH( MSG_UNPAUSED, "Opausad." ) +MSG_HASH( + MSG_UNRECOGNIZED_COMMAND, + "Okänt kommando \"%s\" togs emot.\n" + ) +MSG_HASH( + MSG_USING_CORE_NAME_FOR_NEW_CONFIG, + "Använder kärnnamnet för ny konfiguration." + ) MSG_HASH( MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, "Anslut enhet från en giltig port." ) +MSG_HASH( + MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, + "Kopplar bort enheten från porten" + ) MSG_HASH( MSG_VALUE_REBOOTING, "Startar om..." @@ -10383,9 +12758,13 @@ MSG_HASH( MSG_VERSION_OF_LIBRETRO_API, "Version av libretro API" ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Läs automatiskt in sparade tillstånd från" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, - "Misslyckades med att automatiskt ladda in sparad status från \"%s\"." + "Misslyckades med att automatiskt läsa in sparat tillstånd från \"%s\"." ) MSG_HASH( MSG_DEVICE_CONFIGURED_IN_PORT, @@ -10411,6 +12790,14 @@ MSG_HASH( MSG_DEVICE_NOT_CONFIGURED_NR, "%s (%u/%u) är inte konfigurerad" ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "inte konfigurerad, faller tillbaka" + ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK_NR, + "%s (%u/%u) inte konfigurerad, faller tillbaka" + ) MSG_HASH( MSG_BLUETOOTH_SCAN_COMPLETE, "Bluetooth-skanning slutförd." @@ -10479,18 +12866,94 @@ MSG_HASH( MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, "Run-Ahead har inaktiverats för att denna Kärna saknar stöd för Spara Statusar." ) +MSG_HASH( + MSG_SCANNING_OF_FILE_FINISHED, + "Genomsökning av fil genomförd." + ) +MSG_HASH( + MSG_CHEAT_INIT_SUCCESS, + "Startade sökning efter fusk." + ) +MSG_HASH( + MSG_CHEAT_INIT_FAIL, + "Misslyckades med att starta sökning efter fusk." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_NOT_INITIALIZED, + "Sökningen har inte initierats/startats." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_FOUND_MATCHES, + "Nya matchantal = %u" + ) MSG_HASH( MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, "Lade till %u matchningar." ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL, + "Misslyckades med att lägga till matchningar." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS, + "Skapade kod från matchning." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, + "Misslyckades med att skapa kod." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS, + "Tog bort matchning." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY, + "Slut på plats. Maximalt antal samtidiga fusk är 100." + ) +MSG_HASH( + MSG_CHEAT_ADD_TOP_SUCCESS, + "Nytt fusk lades till överst i listan." + ) +MSG_HASH( + MSG_CHEAT_ADD_BOTTOM_SUCCESS, + "Nytt fusk lades till nederst i listan." + ) MSG_HASH( MSG_CHEAT_DELETE_ALL_SUCCESS, "Alla fusk borttagna." ) +MSG_HASH( + MSG_CHEAT_ADD_BEFORE_SUCCESS, + "Nytt fusk lades till före denna." + ) +MSG_HASH( + MSG_CHEAT_ADD_AFTER_SUCCESS, + "Nytt fusk lades till efter denna." + ) +MSG_HASH( + MSG_CHEAT_COPY_BEFORE_SUCCESS, + "Fusk kopierat till före denna." + ) +MSG_HASH( + MSG_CHEAT_COPY_AFTER_SUCCESS, + "Fusk kopierat till efter denna." + ) MSG_HASH( MSG_CHEAT_DELETE_SUCCESS, "Fusk raderat." ) +MSG_HASH( + MSG_FAILED_TO_SET_DISK, + "Misslyckades med att ställa in skiva." + ) +MSG_HASH( + MSG_FAILED_TO_SET_INITIAL_DISK, + "Misslyckades med att ställa in sista använda skiva." + ) +MSG_HASH( + MSG_FAILED_TO_CONNECT_TO_CLIENT, + "Misslyckades med att ansluta till klient." + ) MSG_HASH( MSG_FAILED_TO_CONNECT_TO_HOST, "Misslyckades med att ansluta till värd." @@ -10503,10 +12966,34 @@ MSG_HASH( MSG_NETPLAY_BANNED, "Du är bannlyst från denna värd." ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_HEADER_FROM_HOST, + "Misslyckades med att ta bort rubrik från värd." + ) MSG_HASH( MSG_CHEEVOS_LOGGED_IN_AS_USER, "RetroAchievements: Inloggad som \"%s\"." ) +MSG_HASH( + MSG_CHEEVOS_LOAD_STATE_PREVENTED_BY_HARDCORE_MODE, + "Du måste pausa eller inaktivera Hardcore-läget för prestationer för att läsa in tillstånd." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_DISABLED, + "Ett sparat tillstånd lästes in. Hardcore-läget för prestationer inaktiverades för aktuell session." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, + "Ett fusk aktiverades. Hardcore-läget för prestationer inaktiverades för aktuell session." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Hardcore-läget för prestationer ändrades av värden." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "Netplay-värden behöver uppdateras. Hardcore-läget för prestationer inaktiverades för aktuell session." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Bemästrat: %s" @@ -10515,6 +13002,10 @@ MSG_HASH( MSG_CHEEVOS_COMPLETED_GAME, "Klarade av %s" ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_ENABLE, + "Hardcore-läget för prestationer aktiverades, sparade tillstånd och tillbakaspolning inaktiverades." + ) MSG_HASH( MSG_CHEEVOS_GAME_HAS_NO_ACHIEVEMENTS, "Detta spel har inga prestationer." @@ -10539,6 +13030,26 @@ MSG_HASH( MSG_CHEEVOS_RICH_PRESENCE_SPECTATING, "Åskådarläge för %s" ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_MANUAL_FRAME_DELAY, + "Hardcore pausad. Manuell inställning av fördröjning av bildrutor för video är inte tillåten." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_VSYNC_SWAP_INTERVAL, + "Hardcore pausad. vsync swap-intervall över 1 tillåts inte." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_BLACK_FRAME_INSERTION, + "Hardcore pausad. Infogning av svarta bildrutor är inte tillåtet." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_SETTING_NOT_ALLOWED, + "Hardcore pausat. Inställningen tillåts inte: %s=%s" + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_PAUSED_SYSTEM_NOT_FOR_CORE, + "Hardcore pausat. Du kan inte tjäna hardcore-prestationer för %s med %s" + ) MSG_HASH( MSG_CHEEVOS_GAME_NOT_IDENTIFIED, "RetroAchievements: Spelet kunde inte identifieras." @@ -10559,6 +13070,14 @@ MSG_HASH( MSG_RESAMPLER_QUALITY_HIGHEST, "Högsta" ) +MSG_HASH( + MSG_MISSING_ASSETS, + "Varning: Saknade resurser, använd online-uppdateraren om tillgänglig." + ) +MSG_HASH( + MSG_RGUI_MISSING_FONTS, + "Varning: Saknade typsnitt för valt språk, använd online-uppdateraren om tillgänglig." + ) MSG_HASH( MSG_RGUI_INVALID_LANGUAGE, "Varning: Språket stöds inte - använder engelska." @@ -10587,34 +13106,70 @@ MSG_HASH( MSG_NO_DISC_INSERTED, "Ingen skiva har matats in i enheten." ) +MSG_HASH( + MSG_ERROR_REMOVING_SHADER_PRESET, + "Fel vid borttagning av shader-förval." + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_INVALID_CONTENT, + "Inget giltigt innehåll hittades." + ) MSG_HASH( MSG_MANUAL_CONTENT_SCAN_START, "Skannar innehåll: " ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_PLAYLIST_CLEANUP, + "Kontrollerar aktuella poster: " + ) MSG_HASH( MSG_MANUAL_CONTENT_SCAN_IN_PROGRESS, "Skannar: " ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_M3U_CLEANUP, + "Städar upp M3U-poster: " + ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_END, + "Genomsökning färdig: " + ) MSG_HASH( MSG_CORE_BACKUP_SCANNING_CORE, - "Skannar kärna: " + "Söker igenom kärna: " + ) +MSG_HASH( + MSG_CORE_BACKUP_ALREADY_EXISTS, + "Säkerhetskopia av installerad kärna finns redan: " ) MSG_HASH( MSG_BACKING_UP_CORE, "Säkerhetskopierar kärna: " ) +MSG_HASH( + MSG_PRUNING_CORE_BACKUP_HISTORY, + "Tar bort föråldrade säkerhetskopior: " + ) +MSG_HASH( + MSG_CORE_BACKUP_COMPLETE, + "Säkerhetskopiering av kärna slutförd: " + ) MSG_HASH( MSG_RESTORING_CORE, "Återställer kärna: " ) MSG_HASH( MSG_INSTALLING_CORE, - "Installerar Kärna: " + "Installerar kärna: " ) MSG_HASH( MSG_CORE_RESTORATION_INVALID_CONTENT, "Ogiltig kärnfil vald: " ) +MSG_HASH( + MSG_CORE_INSTALLATION_FAILED, + "Installation av kärna misslyckades: " + ) MSG_HASH( MSG_CORE_LOCK_FAILED, "Misslyckades med att låsa kärnan: " @@ -10625,11 +13180,23 @@ MSG_HASH( ) MSG_HASH( MSG_CORE_SET_STANDALONE_EXEMPT_FAILED, - "Misslyckades att ta bort Kärna från listan 'Innehållslösa Kärnor': " + "Misslyckades att ta bort kärna från listan 'Innehållslösa kärnor': " ) MSG_HASH( MSG_CORE_UNSET_STANDALONE_EXEMPT_FAILED, - "Misslyckades att lägga till Kärna i listan 'Innehållslösa Kärnor': " + "Misslyckades att lägga till kärna i listan 'Innehållslösa kärnor': " + ) +MSG_HASH( + MSG_UNSUPPORTED_VIDEO_MODE, + "Videoläget stöds inte" + ) +MSG_HASH( + MSG_FAILED_TO_ENTER_GAMEMODE, + "Misslyckades med att gå in i GameMode" + ) +MSG_HASH( + MSG_FAILED_TO_ENTER_GAMEMODE_LINUX, + "Misslyckades med att gå in i GameMode - kontrollera att GameMode-daemon är installerad och körs" ) /* Lakka */ @@ -10638,6 +13205,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, "Uppdatera Lakka" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME, + "Frontend-namn" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_REBOOT, "Starta om" @@ -10645,6 +13216,14 @@ MSG_HASH( /* Environment Specific Settings */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_SPLIT_JOYCON, + "Delade Joy-Con" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WIDGET_SCALE_FACTOR, + "Tillämpa en manuell skalningsfaktor vid ritning av displaywidgets. Gäller endast när ”Skala grafikwidgets automatiskt” är inaktiverat. Kan användas för att öka eller minska storleken på dekorerade meddelanden, indikatorer och kontroller oberoende av själva menyn." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, "Skärmupplösning" @@ -10701,10 +13280,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_FILE_BROWSER_OPEN_UWP_PERMISSIONS, "Öppna Windows-inställningar för filåtkomstbehörighet" ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_OPEN_UWP_PERMISSIONS, + "Öppna Windows inställningar för behörighet för att aktivera funktionen broadFileSystemAccess." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILE_BROWSER_OPEN_PICKER, "Öppna..." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILE_BROWSER_OPEN_PICKER, + "Öppna en annan katalog med hjälp av systemets filväljare" + ) MSG_HASH( MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS, "Skanna efter bluetooth-enheter och anslut dem." @@ -10737,14 +13324,42 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANUAL, "Manuell" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANAGED_PERF, + "Prestanda (hanterad)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MANAGED_PERF, + "Standard och rekommenderat läge. Maximal prestanda vid spel och strömsparläge vid paus eller menybläddring." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANAGED_PER_CONTEXT, + "Anpassad hanterad" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MAX_PERF, "Maximal prestanda" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MAX_PERF, + "Alltid maximal prestanda: högsta frekvenser för bästa upplevelse." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MIN_POWER, + "Minimal ström" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MIN_POWER, + "Använd den lägsta tillgängliga frekvensen för att spara ström. Användbart på batteridrivna enheter, men prestandan försämras avsevärt." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_BALANCED, "Balanserad" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_BALANCED, + "Anpassar sig till den aktuella arbetsbelastningen. Fungerar bra med de flesta enheter och emulatorer och hjälper till att spara ström. Krävande spel och kärnor kan drabbas av prestandaförsämring på vissa enheter." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CPU_POLICY_MIN_FREQ, "Minimal frekvens" @@ -10765,6 +13380,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_GAMEMODE_ENABLE, "Spelläge" ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_GAMEMODE_ENABLE, + "Om du aktiverar Linux GameMode kan du förbättra latensen, åtgärda problem med sprakande ljud och maximera den totala prestandan genom att automatiskt konfigurera CPU och GPU för bästa prestanda.\nProgramvaran GameMode måste installeras för att detta ska fungera. Se https://github.com/FeralInteractive/gamemode för information om hur du installerar GameMode." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, "Använd PAL60-läget" @@ -10773,6 +13392,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_RESTART_KEY, "Starta om RetroArch" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_RESTART_KEY, + "Avsluta och starta sedan om RetroArch. Krävs för aktivering av vissa menyinställningar (t. ex. vid byte av menydrivrutin)." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, "Litet tangentbord" @@ -10830,6 +13453,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_CPU_PROFILE, "Överklocka CPU" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SWITCH_CPU_PROFILE, + "Överklocka Switch CPUn." + ) #endif #ifdef HAVE_LAKKA MSG_HASH( @@ -10840,6 +13467,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, "Tjänster" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, + "Hantera tjänster på operativsystemsnivå." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAMBA_ENABLE, + "Dela nätverksmappar genom SMB-protokollet." + ) MSG_HASH( MENU_ENUM_SUBLABEL_SSH_ENABLE, "Använd SSH för att komma åt kommandoraden utifrån." @@ -10877,6 +13512,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_OC_ENABLE, "Överklocka CPU" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SWITCH_OC_ENABLE, + "Aktivera CPU-överklockningsfrekvenser" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_CEC_ENABLE, "CEC-stöd" @@ -10885,6 +13524,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SWITCH_CEC_ENABLE, "Aktivera CPU-handskakning med TV vid dockning" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BLUETOOTH_ERTM_DISABLE, + "Inaktivera Bluetooth ERTM" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE, + "Inaktivera Bluetooth ERTM för att fixa parkoppling av vissa enheter" + ) #endif MSG_HASH( MSG_LOCALAP_SWITCHING_OFF, @@ -10934,9 +13581,37 @@ MSG_HASH( #ifdef UDEV_TOUCH_SUPPORT #endif #ifdef HAVE_ODROIDGO2 +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_RGA_SCALING, + "RGA-skalning" + ) #else #endif #ifdef _3DS +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NEW3DS_SPEEDUP_ENABLE, + "Aktivera New3DS-klocka / L2-cache" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NEW3DS_SPEEDUP_ENABLE, + "Aktivera New3DS-klockhastighet (804 Mhz) och L2-cache." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_3DS_LCD_BOTTOM, + "Nedre 3DS-skärm" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_3DS_LCD_BOTTOM, + "Aktivera visning av statusinformation på den nedre skärmen. Inaktivera för att öka batteritiden och förbättra prestandan." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_3DS_DISPLAY_MODE, + "Läge för 3DS-skärmar" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_3DS_DISPLAY_MODE, + "Väljer mellan visningslägena 3D och 2D. I ”3D”-läget är bildpunkterna kvadratiska och en djupeffekt tillämpas när snabbmenyn visas. ”2D\"-läget ger bäst prestanda." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CTR_VIDEO_MODE_2D_800X240, "2D (hög upplösning)" @@ -10967,7 +13642,7 @@ MSG_HASH( ) MSG_HASH( MSG_3DS_BOTTOM_MENU_LOAD_STATE, - "Ladda\nÅterställ punkt" + "Läs in\nåterställningspunkt" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_ASSETS_DIRECTORY, @@ -10977,14 +13652,73 @@ MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY, "Nedre skärmens katalog för tillgångar. Katalogen måste inkludera \"bottom_menu.png\"." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, + "Typsnittsfärg röd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_GREEN, + "Typsnittsfärg grön" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_BLUE, + "Typsnittsfärg blå" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_SCALE, "Typsnittsskala" ) #endif #ifdef HAVE_QT +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, + "Genomsökning slutförd.

\nFör att innehållet ska sökas igenom korrekt måste du:\n
  • ha en kompatibel kärna redan hämtad
  • \n
  • ha ”Core Info Files” uppdaterat via Online Updater
  • \n
  • ha ”Databases” uppdaterat via Online Updater
  • \n
  • starta om RetroArch om något av ovanstående just har gjorts
\nSlutligen måste innehållet matcha befintliga databaser från här. Om det fortfarande inte fungerar kan du överväga att skicka in en felrapport." + ) #endif MSG_HASH( MSG_AI_SERVICE_STOPPED, "stoppad." ) +#ifdef HAVE_GAME_AI + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "Spel-AI" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Åsidosätt p1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Åsidosätt spelare 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Åsidosätt p2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Åsidosätt spelare 02" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Visa felsökning" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Visa felsökning" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Visa 'Spel-AI'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Visa alternativet 'Spel-AI'." + ) +#endif diff --git a/intl/msg_hash_tr.h b/intl/msg_hash_tr.h index 3e4d310aab..13b97cacc0 100644 --- a/intl/msg_hash_tr.h +++ b/intl/msg_hash_tr.h @@ -67,6 +67,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Kullanılacak çekirdeği seçin." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Çekirdeği Serbest Bırak" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Yüklenen çekirdeği serbest bırakın." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Bir libretro çekirdek uygulamasına göz atın. Tarayıcının nerede başlayacağı, Çekirdek Dizin yolunuza bağlıdır. Boşsa, kök dizinde başlar.\nÇekirdek Dizin bir dizinse, menü bunu üst klasör olarak kullanır. Çekirdek Dizin tam yol ise, dosyanın bulunduğu klasörde başlar." @@ -906,6 +914,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 Desteği" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL Desteği" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb Desteği" @@ -1470,7 +1482,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "Başarı ayarlarını değiştir." + "Başarım ayarlarını değiştir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, @@ -1952,7 +1964,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Karelerin arasına siyah kareler ekleyin. CRT tarama çıkışını taklit ederek hareket bulanıklığını büyük ölçüde azaltabilir, ancak parlaklık azalabilir. Değiştirme Aralığı > 1, alt-kareler, Kare Gecikmesi veya Tam İçerik Kare Hızına Eşitleme ile birleştirmeyin." + "UYARI: Hızlı titreme bazı ekranlarda görüntünün kalıcı olmasına neden olabilir. Kullanım riski size aittir // Karelerin arasına siyah kareler ekleyin. CRT tarama çıkışını taklit ederek hareket bulanıklığını büyük ölçüde azaltabilir, ancak parlaklık pahasına." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2036,7 +2048,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Kareler arasına fazladan gölgelendirici kareler ekleyin. Gölgelendiricilerin gerçek içerik hızından daha yüksek bir fps hızında çalışan efektler oluşturmasına olanak tanır. Mevcut ekran Hz değerine ayarlanmalıdır. Takas Aralığı > 1, BFI, Kare Gecikmesi veya Tam İçerik Kare Hızına Eşitle ile birleştirmeyin." + "UYARI: Hızlı titreme bazı ekranlarda görüntünün kalıcı olmasına neden olabilir. Kullanım riski size aittir // Ekranı dikey olarak bölerek ve ekranın her bir bölümünü kaç alt kare olduğuna göre işleyerek birden fazla alt kare üzerinde temel bir dönen tarama çizgisini taklit eder." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2112,7 +2124,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Ekranı dikey olarak böler ve ekranın her bir bölümünü kaç alt kare olduğuna göre işleyerek birden fazla alt kare üzerinde temel bir dönen tarama çizgisini taklit eder." + "UYARI: Hızlı titreme bazı ekranlarda görüntünün kalıcı olmasına neden olabilir. Kullanım riski size aittir // Ekranı dikey olarak bölerek ve ekranın her bir bölümünü kaç alt kare olduğuna göre işleyerek birden fazla alt kare üzerinde temel bir dönen tarama çizgisini taklit eder." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2539,7 +2551,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Yalnızca yüksekliği veya hem yüksekliği hem de genişliği ölçeklendirin. Yüksek çözünürlüklü kaynaklar için yarım adımlar geçerlidir." + "Yüksekliği veya genişliği ya da hem yüksekliği hem de genişliği ölçeklendirin. Yarım adımlar yalnızca yüksek çözünürlüklü kaynaklara uygulanır." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2641,11 +2653,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Görüntü alanını yatay olarak dengelemek için kullanılan özel görüntü alanı sapması (içerik yüksekliğinden daha genişse). 0,0 en sol, 1,0 ise en sağ anlamına gelir." + "Görünüm alanı içerik genişliğinden daha geniş olduğunda içeriğin yatay konumu. 0,0 en sol, 0,5 merkez, 1,0 en sağdır." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Görüntü alanını dikey olarak dengelemek için kullanılan özel görüntü alanı sapması (içerik yüksekliğinden daha uzunsa). 0,0 üst, 1,0 ise alt anlamına gelir." + "Görünüm içerik yüksekliğinden daha uzun olduğunda içeriğin dikey konumu. 0,0 üst, 0,5 orta, 1,0 alt anlamına gelir." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2666,11 +2678,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Görüntü alanını yatay olarak dengelemek için kullanılan özel görüntü alanı sapması (içerik yüksekliğinden daha genişse). 0,0 en sol, 1,0 ise en sağ anlamına gelir. (Portre Yönü)" + "Görünüm alanı içerik genişliğinden daha geniş olduğunda içeriğin yatay konumu. 0,0 en sol, 0,5 merkez, 1,0 en sağdır. (Dikey Yönlendirme)" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Görüntü alanını dikey olarak dengelemek için kullanılan özel görüntü alanı sapması (içerik yüksekliğinden daha uzunsa). 0,0 üst, 1,0 ise alt anlamına gelir. (Portre Yönü)" + "Görünüm içerik yüksekliğinden daha uzun olduğunda içeriğin dikey konumu. 0,0 üst, 0,5 orta, 1,0 alt konumdur. (Dikey Yönlendirme)" ) #endif MSG_HASH( @@ -2918,7 +2930,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Hızlı İleri Sararken Sesi Kapat" + "Hızlı İleri Sarmada Sesi Kapat" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2926,12 +2938,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Hızlı İleri Sarmada Sesi Hızlandır" + "Hızlı İleri Sarmada Seside Hızlandır" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Hızlı ileri sarma sırasında sesi hızlandırın. Cızırtıyı önler, ancak perdeyi değiştirir." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Geri Sarmada Sesi Kapat" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Geri sarmayı kullanırken sesi otomatik olarak kapatır." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Ses Artışı (dB)" @@ -3477,21 +3497,34 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Bekleme" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo Ateş" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Devre dışı bırakıldığında tüm turbo ateş operasyonları durur." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbo Aralığı" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Turbo özellikli düğmeler arasında geçiş yapılan süre (kare cinsinden)." + "Turbo-etkin düğmelere basıldığında kare cinsinden süre." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, "Turbo Görev Döngüsü" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Düğmelerin basılı tutulduğu Turbo Periyodundan kare sayısı. Bu sayı Turbo Periyoduna eşit veya ondan büyükse, düğmeler asla bırakılmaz." + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, + "Turbo süresinde düğmelerin basılı tutulduğu kare sayısı. Bu sayı Turbo süresine eşit veya daha büyükse, düğmeler asla serbest bırakılmayacaktır." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Yarı Dönem" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, @@ -3519,34 +3552,42 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Klasik mod, iki düğmeli işlem. Basın-bırakın dizisini etkinleştirmek için bir düğmeyi basılı tutun ve Turbo düğmesine dokunun.\nTurbo düğmesi Ayarlar/Giriş/Port 1 Kontrollerinde atanabilir." + "Klasik mod, iki düğmeli işlem. Basın-bırakın dizisini etkinleştirmek için bir düğmeyi basılı tutun ve Turbo düğmesine dokunun.\nTurbo bağlantısı Ayarlar/Giriş/Port X Kontrollerinde atanabilir." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Klasik geçiş, iki düğmeli işlem. Bir düğmeyi basılı tutun ve o düğme için turboyu etkinleştirmek için Turbo düğmesine dokunun. Turboyu devre dışı bırakmak için: düğmeyi basılı tutun ve Turbo düğmesine tekrar basın.\nTurbo düğmesi Ayarlar/Giriş/Bağlantı Noktası 1 Kontrolleri'nden atanabilir." + "Klasik geçiş, iki düğmeli işlem. Bir düğmeyi basılı tutun ve o düğme için turboyu etkinleştirmek için Turbo düğmesine dokunun. Turboyu devre dışı bırakmak için: düğmeyi basılı tutun ve Turbo düğmesine tekrar basın.\nTurbo bağlantısı Ayarlar/Giriş/Port X Kontrolleri'nden atanabilir." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Geçiş kipi. Seçilen varsayılan düğme için basma-bırakma sırasını etkinleştirmek için Turbo düğmesine bir kez basın, kapatmak için bir kez daha basın.\nTurbo düğmesi Ayarlar/Giriş/Port 1 Kontrollerinde atanabilir." + "Geçiş kipi. Seçilen varsayılan düğme için basma-bırakma sırasını etkinleştirmek için Turbo düğmesine bir kez basın, kapatmak için bir kez daha basın.\nTurbo bağlantısı Ayarlar/Giriş/Port X Kontrollerinde atanabilir." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Tutma kipi. Seçilen varsayılan düğme için basma-bırakma dizisi, Turbo düğmesi basılı tutulduğu sürece etkindir.\nTurbo düğmesi Ayarlar/Giriş/Port 1 Kontrollerinde atanabilir.\nEv bilgisayarı çağının otomatik ateşleme işlevini taklit etmek için Turbo'yu ayarlayın ve varsayılan düğmeler, joystick ateşleme düğmesiyle aynı olacaktır." + "Tutma modu. Seçili varsayılan düğme için basma-bırakma dizisi Turbo düğmesi basılı tutulduğu sürece etkindir.\nTurbo bağlama Ayarlar/Giriş/Port X Kontrolleri'nde atanabilir.\nEv bilgisayarı döneminin otomatik ateşleme işlevini taklit etmek için Bağlama ve Düğmeyi aynı joystick ateşleme düğmesine ayarlayın." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Varsayılan Turbo Düğmesi" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Turbo Bağlantısı" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Turbo Kipi için varsayılan etkin düğme 'Tek Düğme'." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "RetroPad bağlantısı turbo etkinleştirir. Boş porta özgü bağlamayı kullanır." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Turbo Düğmesi" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "'Tek Tuş' modunda hedef turbo düğmesi." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, "Turbo D-Pad Yönlerine İzin Ver" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, "Etkinleştirilirse, dijital yönlü girişler (aynı zamanda d-pad veya 'hatswitch' olarak da bilinir) turbo olabilir." ) MSG_HASH( @@ -3555,7 +3596,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Turbo ateş ayarlarını değiştirin.\nNot: turbo işlevi, ilgili 'Port X Kontrolleri' menüsünde giriş cihazınıza bir turbo düğmesinin eşlenmesini gerektirir." + "Turbo ateş ayarlarını değiştir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3752,7 +3793,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Mevcut ekranı menü ve çalışan içerik arasında değiştirir." + "Mevcut ekranı menü ve içerik arasında değiştirir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3832,7 +3873,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Çalışan içeriği duraklatılmış ve duraklatılmamış durumlar arasında değiştirir." + "İçeriği duraklatılmış ve duraklatılmamış durumlar arasında değiştirir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -4040,6 +4081,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Seçili olan tekrar oynatma aralığı sayısını azaltır." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Turbo Ateş (Değiştir)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Turbo ateşi açar/kapatır." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Fareyi Yakala (Değiştir)" @@ -4801,7 +4850,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "İçerik kapatıldığında otomatik olarak durum kaydı oluşturur. 'Durumu Otomatik Olarak Yükle' etkinse RetroArch bu durum kaydını otomatik olarak yükler." + "İçerik kapatıldığında otomatik durum kaydı oluşturun. 'Otomatik Durum Yükleme' etkinse, bu durum kaydı başlangıçta yüklenir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -4981,14 +5030,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Dosya tarayıcısında gösterilen dosyaları desteklenen uzantılara göre süzgeçle." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Dahili Medya Oynatıcı Kullan" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Mevcut Çekirdeğe Göre Süzgeçle" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Dosya tarayıcısında gösterilen dosyaları mevcut çekirdeğe göre filtreleyin." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Son Kullanılan Başlangıç ​​Dizinini Hatırla" @@ -4997,6 +5046,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Başlangıç ​​Dizininden içerik yüklerken son kullanılan konumda dosya tarayıcısını açın. Not: RetroArch yeniden başlatıldığında konum varsayılana sıfırlanacaktır." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Dahili Medya Oynatıcı Kullan" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Dahili Resim Görüntüleyici Kullan" + ) /* Settings > Frame Throttle */ @@ -5362,6 +5419,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "Örtüşme hassasiyetini ayarlayın. 8 yönlü simetri için %100'e ayarlayın." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analog Yeniden Yönlendirme Bölgesi" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analog çubuk girişi, bu bölgede basıldığında ilk dokunuşa göre olacaktır." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Kaplama" @@ -5797,6 +5862,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Giriş (Otomatik Yapılandırma) Bağlantı Bildirimleri" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Giriş (Otomatik Yapılandırma) Arıza Bildirimleri" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Hile Kodu Bildirimleri" @@ -5817,6 +5886,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Giriş cihazlarını bağlarken/bağlantısını keserken bir ekran mesajı görüntüleyin." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Giriş cihazları yapılandırılamadığında ekranda bir mesaj görüntüleyin." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Giriş Yeniden Eşleme Bildirimleri" @@ -5947,7 +6020,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Yazı tipi boyutunu nokta cinsinden belirtin." + "Yazı tipi boyutunu punto cinsinden belirtin. Gereçler kullanıldığında, bu boyut yalnızca ekrandaki istatistik gösterimine etki eder." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6104,7 +6177,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Menü etkinse, o anda çalışan içeriği duraklatın." + "Menü etkinse içeriği duraklatır." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6465,7 +6538,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Oynatma listesini gösterin. (Ozon/XMB'de Yeniden Başlatılmalı)" + "Ana Menü üstünde oynatma listelerini gösterin. Oynatma listesi sekmeleri ve gezinme çubuğu etkinse GLUI yok sayılır." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Oynatma Listesi Sekmesini Göster" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Oynatma listesi sekmelerini gösterin. RGUI etkilenmez. Gezinme çubuğu GLUI ile etkinleştirilmelidir. (Ozon/XMB yeniden başlatılmalı)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6919,11 +7000,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_ACHIEVEMENTS, - "'Başarıları' Göster" + "'Başarımları' Göster" ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_ACHIEVEMENTS, - "'Başarılar' ayarlarını gösterin." + "'Başarımlar' ayarlarını göster." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_NETWORK, @@ -6945,14 +7026,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "'Kullanıcıyı' Göster" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Oynatma Listesi Simgeleri" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Görüntülenecek Oynatma Listesi simgesinin küçük resminin türü." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "'Kullanıcı' ayarlarını gösterin." @@ -7154,11 +7227,11 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, - "Başarılar" + "Başarımlar" ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, - "Klasik oyunlarda başarılar kazanın. Daha fazla bilgi için 'https://retroachievements.org' adresini ziyaret edin." + "Klasik oyunlarda başarımlar kazanın. Daha fazla bilgi için 'https://retroachievements.org' adresini ziyaret edin." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, @@ -7182,15 +7255,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_BADGES_ENABLE, - "Başarı Rozetleri" + "Başarım Rozetleri" ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE, - "Başarı listesindeki rozetleri görüntüle." + "Başarım listesindeki rozetleri görüntüle." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, - "Resmi Olmayan Başarıları Test Et" + "Resmi Olmayan Başarımları Test Et" ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, @@ -7202,7 +7275,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_UNLOCK_SOUND_ENABLE, - "Bir başarının kilidi açıldığında bir ses çalın." + "Bir başarım kilidi açıldığında bir ses çalar." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_AUTO_SCREENSHOT, @@ -7312,7 +7385,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_SUMMARY_HASCHEEVOS, - "Başarıları Olan Oyunlar" + "Başarımları Olan Oyunlar" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_UNLOCK, @@ -7320,15 +7393,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_UNLOCK, - "Bir başarının kilidi açıldığında bir bildirim gösterir." + "Bir başarım kilidi açıldığında bir bildirim gösterir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_VISIBILITY_MASTERY, - "Başarı Tamamlama Bildirimlerini Aç" + "Ustalık Bildirimleri" ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_VISIBILITY_MASTERY, - "Bir oyun için tüm başarıların kilidi açıldığında bir bildirim gösterir." + "Bir oyun için tüm başarımların kilidi açıldığında bir bildirim gösterir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_CHALLENGE_INDICATORS, @@ -7917,7 +7990,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "Tarama esnasında olası kopyalarda crc kontrol eder" + "Tarama Olası Kopyalarda CRC Kontrol Eder" ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, @@ -8180,7 +8253,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Dosya Tarayıcısı" + "Başlangıç Dizini" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8425,7 +8498,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Çalışan içerikle ilgili hangi bilgilerin paylaşılacağına karar verin." + "İçerikle ilgili hangi bilgilerin paylaşılacağına karar verin." ) MSG_HASH( @@ -8777,7 +8850,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_EXPLORE_BY_ACHIEVEMENTS, - "Başarılara Göre" + "Başarımlara Göre" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_EXPLORE_BY_CATEGORY, @@ -9025,7 +9098,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Çalışan içeriği devam ettirip Hızlı Menüden çıkın." + "İçeriği devam ettirin ve Hızlı Menüden çıkın." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -9041,7 +9114,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Mevcut içeriği kapatın. Kaydedilmemiş tüm değişiklikler kaybolabilir." + "İçeriği kapatın. Kaydedilmemiş tüm değişiklikler yok olabilir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9177,7 +9250,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Çalışan içeriğin seçeneklerini değiştirin." + "İçerik seçeneklerini değiştirin." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9185,7 +9258,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Çalışan içerik için kontrolcüleri değiştirin." + "İçerik denetimlerini değiştirin." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9221,7 +9294,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, - "Başarılar" + "Başarımlar" ) MSG_HASH( MENU_ENUM_SUBLABEL_ACHIEVEMENT_LIST, @@ -9283,11 +9356,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Seçenekleri Sıfırla" + "Çekirdek Seçeneklerini Sıfırla" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Tüm temel seçenekleri varsayılan değerlere ayarlar." + "Mevcut çekirdeğin tüm seçeneklerini varsayılan değerlere ayarlayın." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9815,7 +9888,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Yeni değişiklikler için gölgelendirici dosyalarını izleyin. Değişiklikleri diskteki gölgelendiriciye kaydettikten sonra, otomatik olarak yeniden derlenecek ve çalışan içeriğe uygulanacaktır." + "Yeni değişiklikler için gölgelendirici dosyalarını izleyin. Değişiklikleri diskteki gölgelendiriciye kaydettikten sonra, otomatik olarak yeniden derlenecek ve içeriğe uygulanacaktır." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10280,6 +10353,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Küçük resim döngüsü" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Rastgele seç" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Geri" @@ -11024,7 +11101,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Hızlı Menü etkinken çalışan içeriğin arka planda görüntülenmesini etkinleştirin. Şeffaflığın devre dışı bırakılması tema renklerini değiştirebilir." + "Hızlı Menü etkinken içeriğin arka planda görüntülenmesini etkinleştirin. Şeffaflığın devre dışı bırakılması tema renklerini değiştirebilir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11215,7 +11292,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_MENU_COLOR_THEME_CLASSIC_GREY, - "Klasik Gri" + "Klasik Boz" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_MENU_COLOR_THEME_LEGACY_RED, @@ -11307,11 +11384,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_MENU_COLOR_THEME_GRAY_DARK, - "Koyu Gri" + "Koyu Boz" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_MENU_COLOR_THEME_GRAY_LIGHT, - "Açık Gri" + "Açık Boz" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_PARTICLE_EFFECT_NONE, @@ -11348,6 +11425,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Solda görüntülenecek küçük resim türü." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Simge Küçük Resim" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Görüntülenecek oynatma listesi simgesi küçük resminin türü." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Dinamik Arkaplan" @@ -11651,6 +11736,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ICE_COLD, "Buz Soğuğu" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Koyu Boz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Açık Boz" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11678,6 +11771,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Oynatma listeleri, adlarının üretici bileşeni kaldırıldıktan sonra alfabetik olarak yeniden sıralanacaktır." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "İkincil Küçük Resim" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "İçerik üst veri panelini başka bir küçük resimle değiştirin." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "İçerik Üst Verileri İçin Kayan Metin Kullan" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Etkinleştirildiğinde, çalma listelerinin sağ kenar çubuğunda gösterilen içerik meta verilerinin her bir maddesi (ilişkili çekirdek, çalma süresi) tek bir satır kaplar; Kenar çubuğunun genişliğini aşan dizeler kayan yazı metni olarak görüntülenir. Devre dışı bırakıldığında, içerik meta verilerinin her bir öğesi, gerektiği kadar satır tutacak şekilde kaydırılarak statik olarak görüntülenir." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Küçük Resim Ölçek Etkeni" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Küçük resim çubuğunun boyutunu ölçeklendirin." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Tema Rengi" @@ -11718,10 +11836,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_DRACULA, "Drakula" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, - "Selenyum" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, "Solar Koyu" @@ -11732,41 +11846,22 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRAY_DARK, - "Koyu Gri" + "Koyu Boz" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRAY_LIGHT, - "Açık Gri" + "Açık Boz" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_PURPLE_RAIN, "Mor Yağmur" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "İkincil Küçük Resim" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "İçerik üst veri panelini başka bir küçük resimle değiştirin." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "İçerik Üst Verileri İçin Kayan Metin Kullan" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Etkinleştirildiğinde, çalma listelerinin sağ kenar çubuğunda gösterilen içerik meta verilerinin her bir maddesi (ilişkili çekirdek, çalma süresi) tek bir satır kaplar; Kenar çubuğunun genişliğini aşan dizeler kayan yazı metni olarak görüntülenir. Devre dışı bırakıldığında, içerik meta verilerinin her bir öğesi, gerektiği kadar satır tutacak şekilde kaydırılarak statik olarak görüntülenir." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Küçük Resim Ölçek Etkeni" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Küçük resim çubuğunun boyutunu ölçeklendirin." + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "Selenyum" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -11890,7 +11985,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, - "Mavi Gri" + "Mavi Boz" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, @@ -11946,7 +12041,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_CUTIE_GREEN, - "Tatlı Gri" + "Tatlı Boz" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_CUTIE_ORANGE, @@ -11970,11 +12065,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GRAY_DARK, - "Koyu Gri" + "Koyu Boz" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GRAY_LIGHT, - "Açık Gri" + "Açık Boz" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_TRANSITION_ANIM_AUTO, @@ -12730,10 +12825,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Kullanıcı" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Dahili Resim Görüntüleyici Kullan" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Azami Takas Zinciri Görüntüleri" @@ -12869,14 +12960,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Bir oynatma listesinden seç" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Devam" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Çalışan içeriği devam ettirip Hızlı Menüden çıkın." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "%u Eşleşmelerinin Listesini Görüntüle" @@ -13007,7 +13090,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Başarılar (Zorlu)" + "Başarımlar (Zorlu)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_DETAILS, @@ -13471,10 +13554,6 @@ MSG_HASH( MSG_AUTODETECT, "Otomatik algıla" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Durum kaydından otomatik yükle" - ) MSG_HASH( MSG_CAPABILITIES, "Yetenekler" @@ -14567,6 +14646,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Sanal disk tepsisi kapatılamadı." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Durum kaydından otomatik yükle" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "\"%s\" konumundan durum kaydı otomatik olarak yüklenemedi." @@ -14875,6 +14958,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Bir hile etkinleştirildi. Başarılar mevcut oturum için Zorlu Kip devre dışı bırakıldı." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Başarımlar Zorlu Mod, sunucu tarafından değiştirildi." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "Netplay ana bilgisayarının güncellenmesi gerekiyor. Başarımlar Zorlu Mod mevcut oturum için devre dışı bırakıldı." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Ustalıkla %s" @@ -14901,7 +14992,7 @@ MSG_HASH( ) MSG_HASH( MSG_CHEEVOS_NUMBER_ACHIEVEMENTS_UNLOCKED, - "%d başarımdan %d tanesinin kilidi açıldı" + "Kilidi açılan başarım %d Toplam başarım %d" ) MSG_HASH( MSG_CHEEVOS_UNSUPPORTED_COUNT, @@ -15880,3 +15971,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "durduruldu." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "YZ oyuncuyu özelleştir" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "YZ oyuncu alt etiketi özelleştir" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "Oyun YZ" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "P1 özelleştir" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Oyuncu 01 özelleştir" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "P2 özelleştir" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Oyuncu 02 özelleştir" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Hata Ayıklamayı Göster" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Hata Ayıklamayı Göster" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "'Oyun YZ' göster" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "'Oyun YZ' seçeneğini gösterin." + ) +#endif diff --git a/intl/msg_hash_tt.h b/intl/msg_hash_tt.h index 4dd976b1f2..94b59a67f7 100644 --- a/intl/msg_hash_tt.h +++ b/intl/msg_hash_tt.h @@ -250,6 +250,7 @@ MSG_HASH( #ifdef ANDROID #endif + /* Settings > Input > Haptic Feedback/Vibration */ @@ -599,6 +600,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -735,4 +738,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_uk.h b/intl/msg_hash_uk.h index 2e48aadc60..f0f249cd37 100644 --- a/intl/msg_hash_uk.h +++ b/intl/msg_hash_uk.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Вибрати ядро для використання." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Відвантажити Ядро" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Відпустіть завантажене ядро." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Знайдіть основну реалізацію libretro. Де браузер запускається в залежності від вашого базового шляху каталогу. Якщо цього немає, то він запуститься в root.\nЯкщо Core Directory це каталог, меню буде використовувати це як верхню теку. Якщо Core Directory є повним шляхом, то він почнеться в папці[...]" @@ -914,6 +922,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Підтримка Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Підтримка SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Підтримка libusb" @@ -1968,7 +1980,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Вставте чорні рамки між кадрами. Може значно зменшити розмиття руху, імітуючи розгортку ЕПТ, але ціною втрати яскравості. Не поєднуйте з інтервалом заміни > 1, під кадрами, затримкою кадру або синхронізацією до точної частоти кадрів контенту." + "УВАГА: Швидке мерехтіння може призвести до збереження зображення на деяких дисплеях. Використовуйте на свій страх і ризик // вставте чорний фреймворк між кадрами. Можна значно зменшити розмиття руху шляхом емуляції сканування CRT, але це зменшило яскравість." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2052,7 +2064,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Вставляти додаткові кадри шейдерів між кадрами. Дозволяє шейдерам виконувати ефекти з вищою частотою кадрів, ніж реальна частота вмісту. Має бути налаштований на поточну частоту екрана. Не поєднуйте з інтервалом заміни > 1, BFI, затримкою кадру або синхронізацією до точної ч[...]" + "ПОПЕРЕДЖЕННЯ: Швидке мерехтіння може призвести до збереження зображень на деяких дисплеях. Використовуйте на свій страх і ризик // Симулює базовий рухомий стовпчик протягом декількох підкадрів шляхом ділення екрану вверх і рендерингу кожної частини екрана відповідно до [...]" ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2128,7 +2140,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Імітує базову рухливу розгортку на кількох підкадрах, розділяючи екран вертикально та відтворюючи кожну частину екрана відповідно до кількості підкадрів." + "ПОПЕРЕДЖЕННЯ: Швидке мерехтіння може призвести до збереження зображень на деяких дисплеях. Використовуйте на свій страх і ризик // Симулює базовий рухомий стовпчик протягом декількох підкадрів шляхом ділення екрану вверх і рендерингу кожної частини екрана відповідно до [...]" ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2563,7 +2575,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Масштабувати лише висоту, або висоту та ширину. Половинні кроки застосовуються до джерел високої роздільної здатності." + "Масштабувати або висоту, або висоту, і ширину. Половина кроків застосовуються лише до джерел високої роздільної здатності." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2661,11 +2673,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Настроюване зміщення вікна перегляду, яке використовується для зсуву вікна перегляду по горизонталі (якщо ширше за висоту вмісту). 0,0 означає крайній ліворуч, а 1,0 означає крайній правий." + "Горизонтальне положення вмісту, якщо вікно перегляду ширше, ніж ширина контенту. 0.0 знаходиться далеко, 0.5 - центр, 1.0 знаходиться набагато вірно." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Настроюване зміщення вікна перегляду, яке використовується для зсуву вікна перегляду по вертикалі (якщо вище за висоту вмісту). 0,0 означає верх і 1,0 означає низ." + "Вертикальне положення вмісту, коли вікно перегляду перевищує висоту. 0.0 знаходиться зверху, 0.5 - центр, 1.0 знизу." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2686,11 +2698,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Настроюване зміщення вікна перегляду, яке використовується для зміщення вікна перегляду по горизонталі (якщо ширше за висоту вмісту). 0,0 означає крайній ліворуч, а 1,0 означає крайній правий. (Книжкова орієнтація)" + "Горизонтальне положення вмісту, коли вікно перегляду ширше, ніж ширина контенту. 0,0 далеко зліва, 0,5 - центр, 1.0 - набагато правильніше. (портретний орієнтація)" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Настроюване зміщення вікна перегляду, яке використовується для зсуву вікна перегляду по вертикалі (якщо вище за висоту вмісту). 0,0 означає верх і 1,0 означає низ. (Книжкова орієнтація)" + "Вертикальне положення вмісту, коли вікно перегляду є вищим, ніж висота контенту. 0,0 зверху, 0.5 знаходиться в центрі, 1.0 знаходиться внизу. (портретна орієнтація)" ) #endif MSG_HASH( @@ -2938,7 +2950,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Вимкнути звук при перемотуванні" + "Вимкнення звуку швидкого переходу" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2946,12 +2958,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Прискорити Під Час Перемотування Вперед" + "Прискорення звуку Швидкого Вперед" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Прискорювати звук під час перемотування вперед. Запобігає потріскуванню, але змінює висоту тону." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Вимкнення звуку назад" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Автоматично вимикати звук під час перемотування назад." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Збільшення гучності (дБ)" @@ -3497,21 +3517,34 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Утримуйте" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Турбо Кнопки" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Вимкнено зупиняє всі операції турбопожежі." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Турбо-період" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Тривалість (у кадрах) дії turbo-кнопок." + "Період у кадрах під час натискання кнопок із увімкненим режимом турбо." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Робочий цикл турбо" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, + "Робочий цикл Turbo" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Кількість кадрів із турбо-періоду, протягом якого кнопки утримуються. Якщо це число дорівнює або перевищує період турбо, кнопки ніколи не відпустяться." + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, + "Кількість кадрів із турбо-періоду, протягом якого кнопки утримуються. Якщо це число дорівнює або перевищує Turbo Period, кнопки ніколи не відпустяться." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Половина періоду" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, @@ -3539,34 +3572,38 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Класичний режим, керування двома кнопками. Утримуйте кнопку та торкніться кнопки Турбо, щоб активувати послідовність пресреліз.\n Кнопку Турбо можна призначити в меню «Налаштування»/«Вхід»/«Керування портом 1»." + "Класичний режим, управління двома кнопками. Утримуйте кнопку та торкніться кнопки «Турбо», щоб активувати послідовність прес-релізів.\nТурбо-прив’язку можна призначити в «Параметрах»/«Введення»/«Керування портом X»." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Класичний режим перемикання, робота двома кнопками. Утримуйте кнопку та торкніться кнопки Turbo, щоб увімкнути турбо для цієї кнопки. Щоб вимкнути турбо: утримуйте кнопку та знову натисніть кнопку «Турбо».\nКнопку «Турбо» можна призначити в меню «Налаштування/Вхід/Керування[...]" + "Класичний режим перемикання, робота двома кнопками. Утримуйте кнопку та торкніться кнопки Turbo, щоб увімкнути турбо для цієї кнопки. Щоб вимкнути турбо: утримуйте кнопку та знову натисніть кнопку «Турбо».\nТурбозв’язування може b." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Режим перемикання. Натисніть кнопку «Турбо» один раз, щоб активувати послідовність прес-релізів для вибраної кнопки за замовчуванням, натисніть її ще раз, щоб вимкнути її.\nКнопку «Турбо» можна призначити в меню «Налаштування/Вхід/Керування портом 1»." + "Режим перемикання. Натисніть кнопку Turbo один раз, щоб активувати послідовність прес-релізів для вибраної кнопки за замовчуванням, натисніть її ще раз, щоб вимкнути її.\nTurbo bind можна призначити в Settings/Input/Por." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Режим утримання. Послідовність прес-релізів для вибраної кнопки за замовчуванням активна, доки кнопка Turbo утримується.\n Кнопку Turbo можна призначити в меню «Параметри/Вхід/Керування портом 1».\n Щоб імітувати функцію автозапуску епохи домашнього комп’ютера, установіть Turbo [...]" + "Режим утримання. Послідовність прес-релізів для вибраної кнопки за замовчуванням активна, доки кнопку Turbo утримують.\nТурбозв’язування можна призначити в меню «Параметри/Вхід/Керування портом X».\nЩоб імітувати функцію автозапуску ери домашнього комп’ютера, установіть «[...]" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Стандартна кнопка Турбо" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Зв'язати Турбо" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Активна кнопка для турбо режиму за замовчанням." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "Turbo активація прив'язки RetroPad. Empty використовує прив’язку до порту." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Дозволити маршрути Turbo D-Pad" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Турбо кнопка" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "Цільова турбо-кнопка в режимі «Одна кнопка»." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, "Якщо ввімкнено, цифрові спрямовані входи (також відомі як d-pad або «hatswitch») можуть бути турбо." ) MSG_HASH( @@ -3575,7 +3612,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Змініть налаштування турбопожежі.\n Примітка: функція турбо вимагає зіставлення кнопки турбо з пристроєм введення у відповідному меню «Керування портом X»." + "Змініть налаштування турбо вогню." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3768,7 +3805,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Перемикає поточний вигляд між меню та запущеним контентом." + "Перемикає поточний дисплей між меню та вмістом." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3848,7 +3885,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Перемикає запущений зміст між зупиненим та не зупиненими станом." + "Перемикає вміст між станами призупинення та без паузи." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -4056,6 +4093,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Зменшує поточний вибраний індекс слота для повтору." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Turbo Fire (перемикач)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Вмикає/вимикає турбо вогонь." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Захоплювати мишу (перемикач)" @@ -4436,7 +4481,7 @@ MSG_HASH( "Гармата D-панель праворуч" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, "Турбо" ) @@ -4569,7 +4614,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Визначає, чи ігнорувати можливості резервного копіювання інформаційних заощаджень, дозволяючи експериментувати з пов'язаними особами (виконуються наперед, перемотування тощо)." + "Визначає, чи ігнорувати основні інформаційні можливості збереження штатних можливостей, дозволяючи експериментувати з пов'язаними функціями (виконуючи попереду, перемотування тощо)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4813,7 +4858,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Автоматично робити стан збереження при закритому вмісті. РетроАрка автоматично завантажить цей стан збереження, якщо увімкнуто \"Завантажити стан\"." + "Автоматично відтворювати стан збереження при закритті вмісту. При ввімкнені автозавантаження - збережений стану." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -4989,14 +5034,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Фільтрація файлів, що відображаються у браузері файлів, підтримуючи розширення." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Використовувати вбудований медіа-програвач" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Фільтрувати за поточним ядром" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Фільтр файлів, що відображаються в браузері файлу по поточному ядру." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Запам’ятайте Останній Використаний Стартовий Каталог" @@ -5005,6 +5050,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Відкрити Файловий браузер в останньому використаному місці при завантаженні вмісту з папки Старт. Примітка: Місцезнаходження буде скинуто при перезапуску RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Використовувати вбудований медіа-програвач" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Використовувати вбудований переглядач зображень" + ) /* Settings > Frame Throttle */ @@ -5785,6 +5838,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Вхідний (автоматичний) Сповіщення про підключення" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Повідомлення про помилку введення (автоконфігурації)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Повідомлення чіт-кодів" @@ -5805,6 +5862,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Відображати екранне повідомлення під час підключення/відключення вхідних пристроїв." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Відображати повідомлення на екрані, якщо не вдалося налаштувати пристрої введення." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Вхідні нагадування про завантажене сповіщення" @@ -5939,7 +6000,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Вкажіть розмір шрифту в пунктах." + "Вкажіть розмір шрифту в точках. Коли віджети використовуються, цей розмір впливає лише на екранний дисплеї статистики." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6096,7 +6157,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Призупиняти запущений вміст, якщо меню активне." + "Призупинити вміст, якщо меню активне." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6453,7 +6514,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Показати список відтворення. (Потрібно перезапустити в Ozone/XMB)" + "Показати списки відтворення в головному меню. Ігнорується в GLUI, якщо ввімкнено вкладки списку відтворення та навігаційну панель." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Показати вкладки списку відтворення" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Показати вкладки списку відтворення. Не впливає на RGUI. Панель навігації має бути ввімкнена в GLUI. (Потрібен перезапуск Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -6933,14 +7002,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Показати 'Користувач'" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Значки списку відтворення" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Тип ескізу іконок у плейлісті для відображення." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Показувати налаштування \"Користувач\"." @@ -7885,7 +7946,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "Сканувати перевірки CRC на можливі дублікати" + "Сканування перевіряє CRC на можливі дублікати" ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, @@ -8156,7 +8217,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Файловий менеджер" + "Початковий каталог" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8401,7 +8462,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Визначте, яку інформацію, пов'язану з запущеним змістом, буде надано контент." + "Вирішіть, яку інформацію, пов’язану з вмістом, буде надано." ) MSG_HASH( @@ -9001,7 +9062,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Відновити актуальний вміст та залишити панель швидкого меню." + "Відновити вміст і вийти зі швидкого меню." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -9017,7 +9078,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Закрити поточний вміст. Будь-які незбережені зміни можуть бути втрачені." + "Закрийте вміст. Усі незбережені зміни можуть бути втрачені." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9153,7 +9214,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Змінити параметри, які зараз працюють." + "Змініть параметри вмісту." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9161,7 +9222,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Змінити параметри елементів керування на даний момент." + "Змініть елементи керування вмістом." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9259,11 +9320,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Скинути параметри" + "Скинути параметри ядра" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Встановити всі параметри ядра для значень за замовчуванням." + "Встановити всі параметри поточного ядра для значень за замовчуванням." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9787,7 +9848,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Перегляд файлів шейдерів для нових змін. Після збереження змін у тінню на диску він буде автоматично перекомпільований і застосований до запущеного вмісту." + "Слідкуйте за новими змінами у файлах шейдерів. Після збереження змін шейдера на диску його буде автоматично перекомпільовано та застосовано до вмісту." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10240,6 +10301,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Зациклити мініатюри" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Випадковий вибір" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Назад" @@ -11000,7 +11065,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Увімкнути фонове відображення запущеного вмісту, коли активне Швидке Меню. Вимкнення прозорості може змінити кольори теми." + "Увімкнути фонове відображення вмісту під час активного швидкого меню. Вимкнення прозорості може змінити кольори теми." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -11376,6 +11441,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Тип ескізу для відображення вліво." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Мініатюра значка" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Тип мініатюри значка списку відтворення." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Динамічне тло" @@ -11671,6 +11744,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDGAR, "Веселка" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Темно-сірий" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Світло-сірий" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -11698,6 +11779,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Плейлісти будуть повторно сортовані в алфавітному порядку після видалення компонента виконавців їх імен." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Додаткова мініатюра" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Замінити панель метаданих вмісту іншою мініатюрою." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Використовувати тікер для вмісту метаданих" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "Коли увімкнено, кожен елемент метаданих, що відображаються на правій бічній панелі списків відтворення (пов’язаний з ядром, час гри) буде займати одну лінію; рядки, що перевищують ширину бічної панелі, будуть відображатися як текст прокрутки тікета. Коли вимкнено, кожен ел[...]" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Фактор масштабування мініатюр" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Масштабувати розмір мініатюри (основного розміру)." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Колір теми" @@ -11758,30 +11864,7 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_PURPLE_RAIN, "Фіолетовий Дощ" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Додаткова мініатюра" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Замінити панель метаданих вмісту іншою мініатюрою." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Використовувати тікер для вмісту метаданих" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "Коли увімкнено, кожен елемент метаданих, що відображаються на правій бічній панелі списків відтворення (пов’язаний з ядром, час гри) буде займати одну лінію; рядки, що перевищують ширину бічної панелі, будуть відображатися як текст прокрутки тікета. Коли вимкнено, кожен ел[...]" - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Фактор масштабування мініатюр" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Масштабувати розмір мініатюри (основного розміру)." - ) + /* MaterialUI: Settings > User Interface > Appearance */ @@ -12754,10 +12837,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Користувач" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Використовувати вбудований переглядач зображень" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "Задає прийом відео чітка використовувати вказаний режим буферизації." @@ -12885,14 +12964,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Вибір зі списку відтворення" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Продовжити" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Відновити актуальний вміст та залишити панель швидкого меню." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Переглянути список матчів %u" @@ -13491,10 +13562,6 @@ MSG_HASH( MSG_AUTODETECT, "Автовизначення" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Автоматичне завантаження стану збереження" - ) MSG_HASH( MSG_CAPABILITIES, "Можливості" @@ -14587,6 +14654,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Не вдалося закрити віртуальний диск лотку." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Автоматичне завантаження стану збереження" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Автозавантаження стану збереження з \"%s\" не вдалося." @@ -14891,6 +14962,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "Читання було активовано. Досягнення Хардкорного режиму вимкнено для поточного сеансу." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Досягнення складного режиму змінено хостом." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "Netplay хост необхідно оновити. Досягнення в хардкорному режимі вимкнуто для поточної сесії." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Опанував %s" @@ -15827,7 +15906,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Відображення шрифту в нижньому меню. Увімкніть відображення описів кнопок на нижньому екрані. Виключає дату збереження." + "Виводити шрифт нижнього меню. Увімкніть для відображення описів кнопок на нижньому екрані. Це не впливає на дату збереження." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, @@ -15892,3 +15971,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "зупинено." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "Перевизначити гравця по ШІ" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "Перевизначити підмітку оператора AI" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "ШІ гри" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Перевизначити p1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Перевизначити гравця 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Перевизначити p2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Перевизначити гравця 02" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Показати налагодження" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Показати налагодження" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Показати 'Кінець гри'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Показувати опцію \"Кінець гри\"." + ) +#endif diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 05b4672494..85f9341d8b 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -500,9 +500,6 @@ int msg_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); } break; - case MENU_ENUM_LABEL_INPUT_ALLOW_TURBO_DPAD: - strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_INPUT_ALLOW_TURBO_DPAD), len); - break; default: if (string_is_empty(s)) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 90f3c86923..dc90b7eff4 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -71,6 +71,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LIST, "Select which core to use." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_LIST_UNLOAD, + "Unload Core" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_LIST_UNLOAD, + "Release the loaded core." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_CORE_LIST, "Browse for a libretro core implementation. Where the browser starts depends on your Core Directory path. If blank, it will start in root.\nIf Core Directory is a directory, the menu will use that as top folder. If Core Directory is a full path, it will start in the folder where the file is." @@ -918,6 +926,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 Support" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL Support" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb Support" @@ -2004,7 +2016,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Insert black frame(s) between frames. Can greatly reduce motion blur by emulating CRT scan out, but at cost of brightness. Do not combine with Swap Interval > 1, sub-frames, Frame Delay, or Sync to Exact Content Framerate." + "WARNING: Rapid flickering may cause image persistence on some displays. Use at your own risk // Insert black frame(s) between frames. Can greatly reduce motion blur by emulating CRT scan out, but at cost of brightness." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION, @@ -2088,7 +2100,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHADER_SUBFRAMES, - "Insert extra shader frame(s) between frames. Allows shaders to do effects that run at a higher fps than actual content rate. Should be set to current screen Hz. Do not combine with Swap Interval > 1, BFI, Frame Delay, or Sync to Exact Content Framerate." + "WARNING: Rapid flickering may cause image persistence on some displays. Use at your own risk // Simulates a basic rolling scanline over multiple sub-frames by dividing the screen up vertically and rendering each part of the screen according to how many sub-frames there are." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, @@ -2180,7 +2192,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCAN_SUBFRAMES, - "Simulates a basic rolling scanline over multiple sub-frames by dividing the screen up vertically and rendering each part of the screen according to how many sub-frames there are." + "WARNING: Rapid flickering may cause image persistence on some displays. Use at your own risk // Simulates a basic rolling scanline over multiple sub-frames by dividing the screen up vertically and rendering each part of the screen according to how many sub-frames there are." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SCAN_SUBFRAMES, @@ -2615,7 +2627,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Scale only height, or both height and width. Half steps apply to high resolution sources." + "Scale either height or width, or both height and width. Half steps apply only to high resolution sources." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -2717,11 +2729,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_X, - "Custom viewport bias used to offset the viewport horizontally (if wider than content height). 0.0 means far left and 1.0 means far right." + "Horizontal position of content when viewport is wider than content width. 0.0 is far left, 0.5 is center, 1.0 is far right." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_Y, - "Custom viewport bias used to offset the viewport vertically (if taller than content height). 0.0 means top and 1.0 means bottom." + "Vertical position of content when viewport is taller than content height. 0.0 is top, 0.5 is center, 1.0 is bottom." ) #if defined(RARCH_MOBILE) MSG_HASH( @@ -2742,11 +2754,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X, - "Custom viewport bias used to offset the viewport horizontally (if wider than content height). 0.0 means far left and 1.0 means far right. (Portrait Orientation)" + "Horizontal position of content when viewport is wider than content width. 0.0 is far left, 0.5 is center, 1.0 is far right. (Portrait Orientation)" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y, - "Custom viewport bias used to offset the viewport vertically (if taller than content height). 0.0 means top and 1.0 means bottom. (Portrait Orientation)" + "Vertical position of content when viewport is taller than content height. 0.0 is top, 0.5 is center, 1.0 is bottom. (Portrait Orientation)" ) #endif MSG_HASH( @@ -2998,7 +3010,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Mute When Fast-Forwarding" + "Fast-Forward Audio Mute" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -3006,12 +3018,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Speedup When Fast-Forwarding" + "Fast-Forward Audio Speedup" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Speed up audio when fast-forwarding. Prevents crackling but shifts pitch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Rewind Audio Mute" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Automatically mute audio when using rewind." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Volume Gain (dB)" @@ -3557,22 +3577,35 @@ MSG_HASH( MSG_INPUT_BIND_HOLD, "Hold" ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + "Turbo Fire" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ENABLE, + "Disabled stops all turbo fire operations." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbo Period" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "The period (in frames) when turbo-enabled buttons are pressed." + "The period in frames when turbo-enabled buttons are pressed." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DUTY_CYCLE, "Turbo Duty Cycle" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + MENU_ENUM_SUBLABEL_INPUT_TURBO_DUTY_CYCLE, "The number of frames from the Turbo Period the buttons are held down for. If this number is equal to or greater than the Turbo Period, the buttons will never release." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DUTY_CYCLE_HALF, + "Half Period" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, "Turbo Mode" @@ -3599,34 +3632,42 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC, - "Classic mode, two-button operation. Hold a button and tap the Turbo button to activate the press-release sequence.\nTurbo button can be assigned in Settings/Input/Port 1 Controls." + "Classic mode, two-button operation. Hold a button and tap the Turbo button to activate the press-release sequence.\nTurbo bind can be assigned in Settings/Input/Port X Controls." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_CLASSIC_TOGGLE, - "Classic toggle mode, two-button operation. Hold a button and tap the Turbo button to enable turbo for that button. To disable turbo: hold the button and press the Turbo button again.\nTurbo button can be assigned in Settings/Input/Port 1 Controls." + "Classic toggle mode, two-button operation. Hold a button and tap the Turbo button to enable turbo for that button. To disable turbo: hold the button and press the Turbo button again.\nTurbo bind can be assigned in Settings/Input/Port X Controls." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON, - "Toggle mode. Press the Turbo button once to activate the press-release sequence for the selected default button, press it once again to switch it off.\nTurbo button can be assigned in Settings/Input/Port 1 Controls." + "Toggle mode. Press the Turbo button once to activate the press-release sequence for the selected default button, press it once again to switch it off.\nTurbo bind can be assigned in Settings/Input/Port X Controls." ) MSG_HASH( MENU_ENUM_LABEL_HELP_TURBO_MODE_SINGLEBUTTON_HOLD, - "Hold mode. The press-release sequence for the selected default button is active as long as Turbo button is held down.\nTurbo button can be assigned in Settings/Input/Port 1 Controls.\nTo emulate the autofire function of the home computer era, set Turbo and default buttons to be the same as the joystick fire button." + "Hold mode. The press-release sequence for the selected default button is active as long as Turbo button is held down.\nTurbo bind can be assigned in Settings/Input/Port X Controls.\nTo emulate the autofire function of the home computer era, set Bind and Button to the same joystick fire button." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, - "Turbo Default Button" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BIND, + "Turbo Bind" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, - "Default active button for Turbo Mode 'Single Button'." + MENU_ENUM_SUBLABEL_INPUT_TURBO_BIND, + "Turbo activating RetroPad bind. Empty uses the port-specific bind." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_ALLOW_TURBO_DPAD, - "Allow Turbo D-Pad Directions" + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON, + "Turbo Button" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_ALLOW_TURBO_DPAD, + MENU_ENUM_SUBLABEL_INPUT_TURBO_BUTTON, + "Target turbo button in 'Single Button' mode." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ALLOW_DPAD, + "Turbo Allow D-Pad Directions" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_ALLOW_DPAD, "If enabled, digital directional inputs (also known as d-pad or 'hatswitch') can be turbo." ) MSG_HASH( @@ -3635,7 +3676,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_FIRE_SETTINGS, - "Change turbo fire settings.\nNote: the turbo function requires mapping a turbo button to your input device in the corresponding 'Port X Controls' menu." + "Change turbo fire settings." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HAPTIC_FEEDBACK_SETTINGS, @@ -3832,7 +3873,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, - "Switches the current display between menu and running content." + "Switches the current display between menu and content." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_QUIT_GAMEPAD_COMBO, @@ -3912,7 +3953,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_PAUSE_TOGGLE, - "Switches running content between paused and non-paused states." + "Switches content between paused and non-paused states." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, @@ -4120,6 +4161,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, "Decrements the currently selected replay slot index." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_TURBO_FIRE_TOGGLE, + "Turbo Fire (Toggle)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_TURBO_FIRE_TOGGLE, + "Switches turbo fire on/off." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Grab Mouse (Toggle)" @@ -4508,7 +4557,7 @@ MSG_HASH( "Gun D-Pad Right" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO, "Turbo" ) @@ -4641,7 +4690,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Specifies whether to ignore core info savestate capabilities, allowing to experiment with related features (run ahead, rewind, etc)." + "Specifies whether to ignore core info save state capabilities, allowing to experiment with related features (run ahead, rewind, etc)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4885,7 +4934,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatically make a save state when content is closed. RetroArch will automatically load this save state if 'Load State Automatically' is enabled." + "Automatically make a save state when content is closed. This save state is loaded on startup if 'Auto Load State' is enabled." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -5065,14 +5114,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filter files being shown in File Browser by supported extensions." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Use Built-In Media Player" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filter by Current Core" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filter files being shown in File Browser by current core." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Remember Last Used Start Directory" @@ -5081,6 +5130,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Open File Browser at the last used location when loading content from the Start Directory. Note: Location will be reset to default upon restarting RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Use Built-In Media Player" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Use Built-In Image Viewer" + ) /* Settings > Frame Throttle */ @@ -5909,6 +5966,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG, "Input (Autoconfig) Connection Notifications" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Input (Autoconfig) Failure Notifications" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_CHEATS_APPLIED, "Cheat Code Notifications" @@ -5929,6 +5990,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Display an on-screen message when connecting/disconnecting input devices." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, + "Display an on-screen message when input devices could not be configured." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_REMAP_LOAD, "Input Remap Loaded Notifications" @@ -6063,7 +6128,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, - "Specify the font size in points." + "Specify the font size in points. When widgets are used, this size has effect only to on-screen statistics display." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, @@ -6220,7 +6285,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "Pause the currently running content if the menu is active." + "Pause the content if the menu is active." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SAVESTATE_RESUME, @@ -6581,7 +6646,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, - "Show the playlists. (Restart required on Ozone/XMB)" + "Show the playlists in Main Menu. Ignored in GLUI if playlist tabs and navbar are enabled." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLIST_TABS, + "Show Playlist Tabs" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLIST_TABS, + "Show the playlist tabs. Does not affect RGUI. Navbar must be enabled in GLUI. (Restart required on Ozone/XMB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, @@ -7061,14 +7134,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Show 'User'" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, - "Playlist Icons" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, - "Type of Playlist icon thumbnail to display." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Show 'User' settings." @@ -8033,7 +8098,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCAN_SERIAL_AND_CRC, - "Scan checks CRC on possible duplicates" + "Scan Checks CRC on Possible Duplicates" ) MSG_HASH( MENU_ENUM_SUBLABEL_SCAN_SERIAL_AND_CRC, @@ -8312,7 +8377,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "File Browser" + "Start Directory" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -8557,7 +8622,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_STEAM_RICH_PRESENCE_FORMAT, - "Decide what information related to the running content will be shared." + "Decide what information related to the content will be shared." ) MSG_HASH( @@ -9157,7 +9222,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Resume the currently running content and leave the Quick Menu." + "Resume the content and leave the Quick Menu." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -9173,7 +9238,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, - "Close the current content. Any unsaved changes might be lost." + "Close the content. Any unsaved changes might be lost." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, @@ -9309,7 +9374,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Change the options for the currently running content." + "Change the options for the content." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, @@ -9317,7 +9382,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, - "Change the controls for the currently running content." + "Change the controls for the content." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, @@ -9415,11 +9480,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET, - "Reset Options" + "Reset Core Options" ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_OPTIONS_RESET, - "Set all core options to default values." + "Set all options of the current core to default values." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH, @@ -9999,7 +10064,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_SHADER_WATCH_FOR_CHANGES, - "Watch shader files for new changes. After saving changes to a shader on disk, it will automatically be recompiled and applied to the running content." + "Watch shader files for new changes. After saving changes to a shader on disk, it will automatically be recompiled and applied to the content." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR, @@ -10464,6 +10529,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CYCLE_THUMBNAILS, "Cycle thumbnails" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Random select" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Back" @@ -11624,7 +11693,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_TRANSPARENCY, - "Enable background display of running content while Quick Menu is active. Disabling transparency may alter theme colors." + "Enable background display of content while Quick Menu is active. Disabling transparency may alter theme colors." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_SHADOWS, @@ -12024,6 +12093,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS, "Type of thumbnail to display at the left." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Icon Thumbnail" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Type of playlist icon thumbnail to display." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "Dynamic Background" @@ -12331,6 +12408,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDGAR, "Midgar" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_DARK, + "Gray Dark" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GRAY_LIGHT, + "Gray Light" + ) /* Ozone: Settings > User Interface > Appearance */ @@ -12358,6 +12443,31 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, "Playlists will be re-sorted in alphabetical order after removing the manufacturer component of their names." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, + "Secondary Thumbnail" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, + "Replace the content metadata panel with another thumbnail." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, + "Use Ticker Text for Content Metadata" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, + "When enabled, each item of content metadata shown on the right sidebar of playlists (associated core, play time) will occupy a single line; strings exceeding the width of the sidebar will be displayed as scrolling ticker text. When disabled, each item of content metadata will be displayed statically, wrapped to occupy as many lines as required." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, + "Thumbnail Scale Factor" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, + "Scale the size of the thumbnail bar." + ) + MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_MENU_COLOR_THEME, "Color Theme" @@ -12398,10 +12508,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_DRACULA, "Dracula" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, - "Selenium" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SOLARIZED_DARK, "Solarized Dark" @@ -12423,30 +12529,11 @@ MSG_HASH( "Purple Rain" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE, - "Secondary Thumbnail" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE, - "Replace the content metadata panel with another thumbnail." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_SCROLL_CONTENT_METADATA, - "Use Ticker Text for Content Metadata" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_SCROLL_CONTENT_METADATA, - "When enabled, each item of content metadata shown on the right sidebar of playlists (associated core, play time) will occupy a single line; strings exceeding the width of the sidebar will be displayed as scrolling ticker text. When disabled, each item of content metadata will be displayed statically, wrapped to occupy as many lines as required." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_OZONE_THUMBNAIL_SCALE_FACTOR, - "Thumbnail Scale Factor" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_OZONE_THUMBNAIL_SCALE_FACTOR, - "Scale the size of the thumbnail bar." + MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_SELENIUM, + "Selenium" ) + /* MaterialUI: Settings > User Interface > Appearance */ MSG_HASH( @@ -13430,10 +13517,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Kbd" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Use Built-In Image Viewer" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Max Swapchain Images" @@ -13569,14 +13652,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SELECT_FROM_PLAYLIST, "Select from a playlist" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RESUME, - "Resume" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_RESUME, - "Resume the currently running content and leave the Quick Menu." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "View the List of %u Matches" @@ -14187,10 +14262,6 @@ MSG_HASH( MSG_AUTODETECT, "Autodetect" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto-loading save state from" - ) MSG_HASH( MSG_CAPABILITIES, "Capabilities" @@ -15287,6 +15358,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Failed to close virtual disc tray." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Auto-loading save state from" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Auto-loading save state from \"%s\" failed." @@ -15595,6 +15670,14 @@ MSG_HASH( MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT, "A cheat was activated. Achievements Hardcore Mode disabled for the current session." ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_CHANGED_BY_HOST, + "Achievements Hardcore Mode changed by host." + ) +MSG_HASH( + MSG_CHEEVOS_HARDCORE_MODE_REQUIRES_NEWER_HOST, + "Netplay host needs to be updated. Achievements Hardcore Mode disabled for current session." + ) MSG_HASH( MSG_CHEEVOS_MASTERED_GAME, "Mastered %s" @@ -16571,7 +16654,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Display bottom menu font. Enable to display button descriptions on the bottom screen. This excludes the savestate date." + "Display bottom menu font. Enable to display button descriptions on the bottom screen. This excludes the save state date." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, @@ -16640,3 +16723,54 @@ MSG_HASH( MSG_AI_SERVICE_STOPPED, "stopped." ) +#ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_MENU_OPTION, + "AI player override" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_MENU_OPTION, + "AI player override sublabel" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "Game AI" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Override p1" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P1, + "Override player 01" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Override p2" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_OVERRIDE_P2, + "Override player 02" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Show Debug" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Show Debug" + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Show 'Game AI'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_GAME_AI, + "Show the 'Game AI' option." + ) +#endif diff --git a/intl/msg_hash_val.h b/intl/msg_hash_val.h index 799253516b..b806c60e17 100644 --- a/intl/msg_hash_val.h +++ b/intl/msg_hash_val.h @@ -1988,18 +1988,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "Silencia el mesclador d'àudio." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Silenciar el so quan s'use l'avançament ràpid" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, "Automàticament silencia l'àudio quan s'usa l'avançament ràpid." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Accelerar a l'usar l'avançament ràpid" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Accelera l'àudio a l'emprar l'avançament ràpid. Defugirá sorolls en l'àudio a canvi de la seua tonalitat." @@ -2229,6 +2221,7 @@ MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_ON_DISCONNECT, "Posa en pausa el contingut quan qualssevol controlador es desconnecte." ) + MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_HAPTIC_FEEDBACK_SETTINGS, "Canvia els ajustos de vibració i resposta hàptica." @@ -2796,7 +2789,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Navegador d'arxius" + "Directori inicial" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, @@ -3055,6 +3048,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -3311,4 +3306,11 @@ MSG_HASH( #ifdef _3DS #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/msg_hash_vn.h b/intl/msg_hash_vn.h index 4f64a0f7b5..8942639fba 100644 --- a/intl/msg_hash_vn.h +++ b/intl/msg_hash_vn.h @@ -1497,6 +1497,7 @@ MSG_HASH( #endif #ifdef ANDROID #endif + MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, "Kích hoạt hotkeys" @@ -1567,10 +1568,6 @@ MSG_HASH( /* Settings > Input > Port # Controls */ -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, - "Kích hoạt Turbo" - ) /* Settings > Latency */ @@ -1932,7 +1929,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Quản lý tập tin" + "Yêu thích" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, @@ -2283,6 +2280,8 @@ MSG_HASH( /* Ozone: Settings > User Interface > Appearance */ + + /* MaterialUI: Settings > User Interface > Appearance */ @@ -2515,10 +2514,6 @@ MSG_HASH( MSG_AUTODETECT, "Tự động phát hiện" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Đang tự đông tải savestate từ" - ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, "Đang kết nối vào máy chủ netplay" @@ -2631,6 +2626,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "Viewport size calculation failed! Will continue using raw data. This will probably not work right ..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Đang tự đông tải savestate từ" + ) /* Lakka */ @@ -2723,4 +2722,11 @@ MSG_HASH( ) #endif #ifdef HAVE_QT +#endif +#ifdef HAVE_GAME_AI + + + + + #endif diff --git a/intl/progress.h b/intl/progress.h index d48bb1ce41..b2f70f4106 100644 --- a/intl/progress.h +++ b/intl/progress.h @@ -1,5 +1,5 @@ /* Arabic */ -#define LANGUAGE_PROGRESS_ARABIC_TRANSLATED 42 +#define LANGUAGE_PROGRESS_ARABIC_TRANSLATED 44 #define LANGUAGE_PROGRESS_ARABIC_APPROVED 0 /* Asturian */ @@ -7,7 +7,7 @@ #define LANGUAGE_PROGRESS_ASTURIAN_APPROVED 9 /* Belarusian */ -#define LANGUAGE_PROGRESS_BELARUSIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_BELARUSIAN_TRANSLATED 98 #define LANGUAGE_PROGRESS_BELARUSIAN_APPROVED 0 /* Bulgarian */ @@ -15,11 +15,11 @@ #define LANGUAGE_PROGRESS_BULGARIAN_APPROVED 0 /* Catalan */ -#define LANGUAGE_PROGRESS_CATALAN_TRANSLATED 50 +#define LANGUAGE_PROGRESS_CATALAN_TRANSLATED 77 #define LANGUAGE_PROGRESS_CATALAN_APPROVED 0 /* Czech */ -#define LANGUAGE_PROGRESS_CZECH_TRANSLATED 94 +#define LANGUAGE_PROGRESS_CZECH_TRANSLATED 99 #define LANGUAGE_PROGRESS_CZECH_APPROVED 0 /* Welsh */ @@ -32,38 +32,38 @@ /* German */ #define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 100 -#define LANGUAGE_PROGRESS_GERMAN_APPROVED 14 +#define LANGUAGE_PROGRESS_GERMAN_APPROVED 13 /* Greek */ #define LANGUAGE_PROGRESS_GREEK_TRANSLATED 19 #define LANGUAGE_PROGRESS_GREEK_APPROVED 0 /* English, United Kingdom */ -#define LANGUAGE_PROGRESS_ENGLISH_UNITED_KINGDOM_TRANSLATED 99 +#define LANGUAGE_PROGRESS_ENGLISH_UNITED_KINGDOM_TRANSLATED 98 #define LANGUAGE_PROGRESS_ENGLISH_UNITED_KINGDOM_APPROVED 0 /* Esperanto */ -#define LANGUAGE_PROGRESS_ESPERANTO_TRANSLATED 3 +#define LANGUAGE_PROGRESS_ESPERANTO_TRANSLATED 2 #define LANGUAGE_PROGRESS_ESPERANTO_APPROVED 0 /* Spanish */ #define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 100 -#define LANGUAGE_PROGRESS_SPANISH_APPROVED 90 +#define LANGUAGE_PROGRESS_SPANISH_APPROVED 91 /* Persian */ #define LANGUAGE_PROGRESS_PERSIAN_TRANSLATED 11 #define LANGUAGE_PROGRESS_PERSIAN_APPROVED 0 /* Finnish */ -#define LANGUAGE_PROGRESS_FINNISH_TRANSLATED 76 -#define LANGUAGE_PROGRESS_FINNISH_APPROVED 46 +#define LANGUAGE_PROGRESS_FINNISH_TRANSLATED 75 +#define LANGUAGE_PROGRESS_FINNISH_APPROVED 45 /* French */ #define LANGUAGE_PROGRESS_FRENCH_TRANSLATED 100 #define LANGUAGE_PROGRESS_FRENCH_APPROVED 100 /* Galician */ -#define LANGUAGE_PROGRESS_GALICIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_GALICIAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_GALICIAN_APPROVED 0 /* Hebrew */ @@ -75,7 +75,7 @@ #define LANGUAGE_PROGRESS_CROATIAN_APPROVED 0 /* Hungarian */ -#define LANGUAGE_PROGRESS_HUNGARIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_HUNGARIAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_HUNGARIAN_APPROVED 0 /* Indonesian */ @@ -87,15 +87,15 @@ #define LANGUAGE_PROGRESS_ITALIAN_APPROVED 0 /* Japanese */ -#define LANGUAGE_PROGRESS_JAPANESE_TRANSLATED 98 +#define LANGUAGE_PROGRESS_JAPANESE_TRANSLATED 95 #define LANGUAGE_PROGRESS_JAPANESE_APPROVED 0 /* Korean */ -#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_KOREAN_APPROVED 0 /* Dutch */ -#define LANGUAGE_PROGRESS_DUTCH_TRANSLATED 38 +#define LANGUAGE_PROGRESS_DUTCH_TRANSLATED 37 #define LANGUAGE_PROGRESS_DUTCH_APPROVED 0 /* Norwegian */ @@ -107,23 +107,23 @@ #define LANGUAGE_PROGRESS_ODIA_APPROVED 0 /* Polish */ -#define LANGUAGE_PROGRESS_POLISH_TRANSLATED 79 +#define LANGUAGE_PROGRESS_POLISH_TRANSLATED 77 #define LANGUAGE_PROGRESS_POLISH_APPROVED 22 /* Portuguese, Brazilian */ -#define LANGUAGE_PROGRESS_PORTUGUESE_BRAZILIAN_TRANSLATED 75 +#define LANGUAGE_PROGRESS_PORTUGUESE_BRAZILIAN_TRANSLATED 78 #define LANGUAGE_PROGRESS_PORTUGUESE_BRAZILIAN_APPROVED 9 /* Portuguese */ -#define LANGUAGE_PROGRESS_PORTUGUESE_TRANSLATED 26 +#define LANGUAGE_PROGRESS_PORTUGUESE_TRANSLATED 29 #define LANGUAGE_PROGRESS_PORTUGUESE_APPROVED 0 /* Russian */ -#define LANGUAGE_PROGRESS_RUSSIAN_TRANSLATED 100 -#define LANGUAGE_PROGRESS_RUSSIAN_APPROVED 13 +#define LANGUAGE_PROGRESS_RUSSIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_RUSSIAN_APPROVED 12 /* Slovak */ -#define LANGUAGE_PROGRESS_SLOVAK_TRANSLATED 22 +#define LANGUAGE_PROGRESS_SLOVAK_TRANSLATED 21 #define LANGUAGE_PROGRESS_SLOVAK_APPROVED 0 /* Serbian (Latin) */ @@ -131,12 +131,12 @@ #define LANGUAGE_PROGRESS_SERBIAN_LATIN_APPROVED 0 /* Swedish */ -#define LANGUAGE_PROGRESS_SWEDISH_TRANSLATED 56 -#define LANGUAGE_PROGRESS_SWEDISH_APPROVED 47 +#define LANGUAGE_PROGRESS_SWEDISH_TRANSLATED 86 +#define LANGUAGE_PROGRESS_SWEDISH_APPROVED 49 /* Turkish */ -#define LANGUAGE_PROGRESS_TURKISH_TRANSLATED 99 -#define LANGUAGE_PROGRESS_TURKISH_APPROVED 99 +#define LANGUAGE_PROGRESS_TURKISH_TRANSLATED 100 +#define LANGUAGE_PROGRESS_TURKISH_APPROVED 100 /* Tatar */ #define LANGUAGE_PROGRESS_TATAR_TRANSLATED 0 @@ -155,10 +155,10 @@ #define LANGUAGE_PROGRESS_VIETNAMESE_APPROVED 0 /* Chinese Simplified */ -#define LANGUAGE_PROGRESS_CHINESE_SIMPLIFIED_TRANSLATED 97 +#define LANGUAGE_PROGRESS_CHINESE_SIMPLIFIED_TRANSLATED 95 #define LANGUAGE_PROGRESS_CHINESE_SIMPLIFIED_APPROVED 43 /* Chinese Traditional */ -#define LANGUAGE_PROGRESS_CHINESE_TRADITIONAL_TRANSLATED 94 -#define LANGUAGE_PROGRESS_CHINESE_TRADITIONAL_APPROVED 74 +#define LANGUAGE_PROGRESS_CHINESE_TRADITIONAL_TRANSLATED 91 +#define LANGUAGE_PROGRESS_CHINESE_TRADITIONAL_APPROVED 72 diff --git a/intl/steam_sv.json b/intl/steam_sv.json index 0469307b5c..dc8ef32287 100644 --- a/intl/steam_sv.json +++ b/intl/steam_sv.json @@ -2,12 +2,12 @@ "main-desc": "RetroArch är en öppen källkod- och kross-plattform frontend/ram för emulatorer, spelmotorer, videospel, mediaspelare och andra program.\n\nÄven om det kan göra många saker förutom detta, är det mest känt för att du kan köra klassiska spel på ett brett utbud av datorer och konsoler genom ett smidigt grafiskt gränssnitt. Inställningarna är också enhetliga så konfigurationen görs en gång för alla.\n\nUtöver detta kommer du snart att kunna köra original spelskivor (CDs) från RetroArch. Vi tar bevarande av videospel på allvar och vill se till att du kan köra ditt ursprungligt köpta innehåll på moderna datorer.\n\nRetroArch har avancerade funktioner som shaders, nätspel, tillbakaspolning, nästa-ram svarstider, runahead, och mycket mer!", "final-burn-neo-desc": "[img]{STEAM_APP_IMAGE}/extras/FBN_a2.[/img]\n\nFinal Burn Neo (alias FBNeo) är den nya officiella grenen av Final Burn Alpha emulatorn, som är kompatibel med hundratals arkad- och konsolspel. FBNeos libretro kärna tar sitt bibliotek med kompatibla titlar till RetroArch, där kärnans täta integration med libretros API gör det möjligt att arbeta med RetroArchs avancerade tidsböjande funktioner som rollback-baserade nätspel och runahead latens minskning. Den innehåller ingångsförinställningar för automatisk mappning av knappar för olika spel, inklusive fightingspel layouter för både moderna och gamla skolans arkadkontroller (s.k fightsticks).", "genesis-plus-gx-desc": "[img]{STEAM_APP_IMAGE}/extras/Genesis_Plus_GX_(hone). ng[/img]\n\nGenesis Plus GX började som en homebrew-port för Genesis Plus-emulatorn för en hackad konsol innan den portades till libretro. Med fokus på hastighet, noggrannhet och portabilitet, Genesis Plus GX visas nu på en mängd olika plattformar och fronter, och är känd som en av de mest kapabla och kompatibla emulatorer för konsoler den täcker, med stöd för både patron och CD-ROM-spel. Det fungerar också bra med många av RetroArchs avancerade funktioner, såsom realtids-spolning, runahead-latensreducering, fusk och RetroPrestationer.", - "kronos-desc": "[img]{STEAM_APP_IMAGE}/extras/main.png[/img] \n\nKronos är en modern avgrening av UoYabause-emulatorn, vilken i sig är en avgrening av den ansedda Yabause-emulatorn. Denna DLC tillhandahåller Kronos-libretro-kärnan för användning med RetroArchs spelande och multimediala gränssnitt, vilket gör det möjligt för användare att ladda mjukvara som är kompatibel med Kronos-emulatorn.\n\nKronos använder moderna OpenGL-funktioner för att ge olika extra grafiska funktioner, såsom ökad intern upplösning, vilket gör att en uppdaterad och tillräckligt kraftfull GPU rekommenderas.\n\nKronos stödjer att ladda spel från många olika format, inklusive ISO, BIN/CUE och det komprimerade CHD-formatet, och den kräver externa BIOS-filer (saturn_bios.bin och stvbios.zip) som placeras antingen i RetroArchs \"system\"-mapp eller bredvid målmjukvaran för att fungera korrekt.", + "kronos-desc": "[img]{STEAM_APP_IMAGE}/extras/main.png[/img] \n\nKronos är en modern avgrening av UoYabause-emulatorn, vilken i sig är en förgrening av den ansedda Yabause-emulatorn. Denna DLC tillhandahåller Kronos-libretro-kärnan för användning med RetroArchs spelande och multimediala gränssnitt, vilket gör det möjligt för användare att ladda mjukvara som är kompatibel med Kronos-emulatorn.\n\nKronos använder moderna OpenGL-funktioner för att ge olika extra grafiska funktioner, såsom ökad intern upplösning, vilket gör att en uppdaterad och tillräckligt kraftfull GPU rekommenderas.\n\nKronos stödjer att läsa in spel från många olika format, inklusive ISO, BIN/CUE och det komprimerade CHD-formatet, och den kräver externa BIOS-filer (saturn_bios.bin och stvbios.zip) som placeras antingen i RetroArchs \"system\"-mapp eller bredvid målmjukvaran för att fungera korrekt.", "mesen-desc": "[img]{STEAM_APP_IMAGE}/extras/mesen2.png[/img]\n\nMesen är en mycket noggrann och funktionsspäckad emulator med stöd för massor av kassettmapper (även de som används för udda, oauktoriserade kassetter), anpassade färgpaletter och HD-tillgångspaket. Som en libretro-kärna stödjer Mesen många avancerade funktioner, som mjukpatchning och prestationer (genom RetroAchievements-tjänsten).", "mesen-s-desc": "[img]{STEAM_APP_IMAGE}/extras/mesen2.png[/img][img]{STEAM_APP_IMAGE}/extras/-S2.png[/img]\n\nMesen S är en mycket noggrann och funktionsspackad 16-bitars konsollemulator. Den har hög kompatibilitet med stöd för tilläggschips som används i många spel från eran, samtidigt som den bibehåller hög prestanda. Som en libretro-kärna stödjer Mesen S många avancerade funktioner, såsom mjukpatchning och prestationer (genom RetroAchievements-tjänsten).", "mgba-desc": "[img]{STEAM_APP_IMAGE}/extras/mgba.png[/img]\n\nmGBA är en snabb och träffsäker emulator för en av de mest populära och älskade handhållna spelkonsolerna, och den har kompatibilitet med ett stort bibliotek av älskade spel i 8- och 16-bitarsstil. Förutom fokus på hastighet och trogen återgivning har mGBA också en mängd fantastiska förbättringsfunktioner, inklusive stöd för anpassade färgpaletter för spel som ursprungligen var gråskaliga, samt visning av ramar för spel som inkluderar dessa.\n\nDenna DLC möjliggör att mGBA körs genom RetroArch, vilket tillför alla dess förbättringar och funktioner, inklusive realtidsåterställning, omfattande efterbehandlings-shaders och låglatensinmatning för att ge en modern spelupplevelse även med klassiska titlar.", "pcsx-rearmed-desc": "[img]{STEAM_APP_IMAGE}/extras/PCSX.png[/img]\n\nPCSX ReARMed är en del av en lång rad emulators som inkluderar PCSX-Reloaded, PCSX-df och, självklart, den ursprungliga PCSX. Denna särskilda avgrening var ursprungligen kraftigt optimerad för enheter med ARM-processorer, därav namnet, men vi har lagt tillbaka en hel del funktioner för att göra den väl fungerande även på vanlig PC-hårdvara.\n\nSom en libretro-kärna kräver denna DLC RetroArch-gränssnittet, där den kan laddas som en kärna för att köra spel och mjukvara som är kompatibel med PCSX ReARMed-emulatorn. Denna kärna kräver en BIOS-bild (ej inkluderad) för varje region av mjukvaran, som ska placeras i RetroArchs \"system\"-mapp för att fungera korrekt.", - "sameboy-desc": "[img]{STEAM_APP_IMAGE}/extras/SAMEBOY_(Phone).png[/img]\n\nSameBoy är en mycket noggrann emulator som är känd för att framgångsrikt köra några spel som får andra emulators att staka sig. Utöver denna höga noggrannhet har SameBoy också några fina funktioner, som möjligheten att välja vilken enhetsmodell som ska emuleras oavsett vilken modell spelet är designat för, användarvalbara färgpaletter, inbyggd HLE BIOS och möjligheten att ladda in ramar för de spel som stödjer dem.", + "sameboy-desc": "[img]{STEAM_APP_IMAGE}/extras/SAMEBOY_(Phone).png[/img]\nSameBoy är en mycket exakt emulator som är känd för att framgångsrikt köra några spel som får andra emulatorer att snubbla. Förutom denna höga noggrannhet har SameBoy också några trevliga funktioner som möjligheten att välja vilken enhetsmodell som ska emuleras oavsett vilken modell spelet är utformat för, användarvalbara färgpaletter, inbyggd HLE BIOS och möjligheten att ladda gränser på de spel som stöder dem.", "stella-desc": "[img]{STEAM_APP_IMAGE}/extras/stealla.png[/img]\n\nStella är en gratis, öppen källkodsemulator för en av de mest populära och inflytelserika hemmavideospelkonsolerna från 1970- och 80-talet. Denna emulator utvecklades ursprungligen för användning på GNU/Linux-operativsystemet men har med tiden portats till många olika plattformar, inklusive libretro, vilket gör det möjligt att spela genom RetroArch-spel- och multimediasystemet.\n\n[img]{STEAM_APP_IMAGE}/extras/2600.png[/img]\n\nUnder de senaste åren har Stella-utvecklingsteamet gjort stora framsteg med att efterlikna många egenskaper hos Stellas målkonsol, vilket gör den kompatibel med många svåråtergivna spel, homebrew programvaror och demo-versioner.\n\nGenom RetroArch kan du ge en modern touch till denna klassiska emulator med stöd för realtids-återställning och RetroAchievements, samt RetroArchs bästa shaders för att efterlikna CRT-skärmar och mer.", "requirements": "CPU: Intel Pentium 4 och uppåt (CPU med SSE2 instruktioner krävs) \nRekommenderad CPU: Intel Core-serien eller AMD ekvivalent \nGrafik: Alla kompatibla OpenGL 2.x eller Direct3D11 GPU. För att shaders ska fungera korrekt, bör det stödja minst Shader Modell 2.0. \nRekommenderad Grafik: Intel: Minst Intel HD 4K krävs för OpenGL, alla kompatibla D3D11 GPU för Direct3D 11. Bör stödja minst Shader Modell 3.0 och/eller 4.0. \nYtterligare anteckningar: För OpenGL: Intel HD 2K/3K GPU:er på Windows 10 måste falla tillbaka till en OpenGL 1.1 drivrutin.", "legal-limits": "RetroArch är fri programvara med öppen källkod tillgänglig under GNU GPL 3.0-licensen. \nDen innehåller inte något upphovsrättsskyddat material från tredje part. RetroArch tolererar inte piratkopiering på något sätt eller form." diff --git a/libretro-common/audio/audio_mix.c b/libretro-common/audio/audio_mix.c index eb138edd44..812f0dd9ae 100644 --- a/libretro-common/audio/audio_mix.c +++ b/libretro-common/audio/audio_mix.c @@ -38,29 +38,29 @@ #include