summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.ci/yuzu-patreon-step2.yml1
-rw-r--r--.gitmodules6
-rw-r--r--.lgtm.yml10
-rw-r--r--CMakeLists.txt2
-rw-r--r--dist/icons/controller/applet_dual_joycon.pngbin0 -> 3554 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_dark.pngbin0 -> 3554 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_dark_disabled.pngbin0 -> 3527 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_disabled.pngbin0 -> 3314 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_midnight.pngbin0 -> 3549 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_midnight_disabled.pngbin0 -> 3584 bytes
-rw-r--r--dist/icons/controller/applet_handheld.pngbin0 -> 1671 bytes
-rw-r--r--dist/icons/controller/applet_handheld_dark.pngbin0 -> 1637 bytes
-rw-r--r--dist/icons/controller/applet_handheld_dark_disabled.pngbin0 -> 2642 bytes
-rw-r--r--dist/icons/controller/applet_handheld_disabled.pngbin0 -> 2221 bytes
-rw-r--r--dist/icons/controller/applet_handheld_midnight.pngbin0 -> 1644 bytes
-rw-r--r--dist/icons/controller/applet_handheld_midnight_disabled.pngbin0 -> 2634 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller.pngbin0 -> 4382 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_dark.pngbin0 -> 4236 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_dark_disabled.pngbin0 -> 4477 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_disabled.pngbin0 -> 4173 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_midnight.pngbin0 -> 4376 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_midnight_disabled.pngbin0 -> 4459 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left.pngbin0 -> 2083 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_dark.pngbin0 -> 2067 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_dark_disabled.pngbin0 -> 2520 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_disabled.pngbin0 -> 2179 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_midnight.pngbin0 -> 2065 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_midnight_disabled.pngbin0 -> 2529 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right.pngbin0 -> 2150 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_dark.pngbin0 -> 2146 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_dark_disabled.pngbin0 -> 2556 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_disabled.pngbin0 -> 2212 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_midnight.pngbin0 -> 2150 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_midnight_disabled.pngbin0 -> 2611 bytes
-rw-r--r--dist/icons/controller/controller.qrc55
-rw-r--r--dist/icons/controller/dual_joycon.pngbin0 -> 36466 bytes
-rw-r--r--dist/icons/controller/dual_joycon_dark.pngbin0 -> 36261 bytes
-rw-r--r--dist/icons/controller/dual_joycon_midnight.pngbin0 -> 34667 bytes
-rw-r--r--dist/icons/controller/handheld.pngbin0 -> 14108 bytes
-rw-r--r--dist/icons/controller/handheld_dark.pngbin0 -> 13731 bytes
-rw-r--r--dist/icons/controller/handheld_midnight.pngbin0 -> 13366 bytes
-rw-r--r--dist/icons/controller/pro_controller.pngbin0 -> 36710 bytes
-rw-r--r--dist/icons/controller/pro_controller_dark.pngbin0 -> 34897 bytes
-rw-r--r--dist/icons/controller/pro_controller_midnight.pngbin0 -> 35893 bytes
-rw-r--r--dist/icons/controller/single_joycon_left.pngbin0 -> 25565 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_dark.pngbin0 -> 25682 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_midnight.pngbin0 -> 24405 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_vertical.pngbin0 -> 24764 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_vertical_dark.pngbin0 -> 24938 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_vertical_midnight.pngbin0 -> 23681 bytes
-rw-r--r--dist/icons/controller/single_joycon_right.pngbin0 -> 28320 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_dark.pngbin0 -> 28157 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_midnight.pngbin0 -> 27006 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_vertical.pngbin0 -> 27655 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_vertical_dark.pngbin0 -> 27729 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_vertical_midnight.pngbin0 -> 26354 bytes
-rw-r--r--dist/languages/de.ts4749
-rw-r--r--dist/languages/es.ts4757
-rw-r--r--dist/languages/fr.ts4732
-rw-r--r--dist/languages/it.ts4724
-rw-r--r--dist/languages/ja_JP.ts4752
-rw-r--r--dist/languages/nl.ts4719
-rw-r--r--dist/languages/pl.ts4713
-rw-r--r--dist/languages/pt_BR.ts4757
-rw-r--r--dist/languages/pt_PT.ts4725
-rw-r--r--dist/languages/ru_RU.ts4720
-rw-r--r--dist/languages/zh_CN.ts4747
-rw-r--r--dist/license.md3
-rw-r--r--dist/qt_themes/colorful_dark/icons/16x16/refresh.pngbin0 -> 362 bytes
-rw-r--r--dist/qt_themes/colorful_dark/icons/16x16/view-refresh.pngbin0 -> 362 bytes
-rw-r--r--dist/qt_themes/colorful_dark/style.qrc1
-rw-r--r--dist/qt_themes/colorful_midnight_blue/icons/16x16/refresh.pngbin0 -> 362 bytes
-rw-r--r--dist/qt_themes/colorful_midnight_blue/icons/16x16/view-refresh.pngbin0 -> 362 bytes
-rw-r--r--dist/qt_themes/colorful_midnight_blue/style.qrc1
-rw-r--r--dist/qt_themes/default/default.qrc1
-rw-r--r--dist/qt_themes/default/icons/16x16/refresh.pngbin0 -> 349 bytes
-rw-r--r--dist/qt_themes/default/icons/16x16/view-refresh.pngbin0 -> 349 bytes
-rw-r--r--dist/qt_themes/default/style.qss246
-rw-r--r--dist/qt_themes/qdarkstyle/icons/16x16/refresh.pngbin0 -> 362 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/icons/16x16/view-refresh.pngbin0 -> 362 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/style.qrc3
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss308
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/refresh.pngbin0 -> 362 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/view-refresh.pngbin0 -> 362 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qrc3
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qss448
-rw-r--r--externals/CMakeLists.txt3
m---------externals/dynarmic0
-rw-r--r--externals/httplib/httplib.h4451
m---------externals/libusb0
-rw-r--r--externals/libusb/CMakeLists.txt150
-rw-r--r--externals/libusb/config.h.in90
m---------externals/libusb/libusb0
-rw-r--r--externals/microprofile/microprofile.h59
-rw-r--r--externals/microprofile/microprofileui.h212
m---------externals/xbyak0
-rw-r--r--src/audio_core/CMakeLists.txt29
-rw-r--r--src/audio_core/algorithm/filter.cpp3
-rw-r--r--src/audio_core/algorithm/interpolate.cpp37
-rw-r--r--src/audio_core/algorithm/interpolate.h3
-rw-r--r--src/audio_core/audio_renderer.cpp548
-rw-r--r--src/audio_core/audio_renderer.h225
-rw-r--r--src/audio_core/behavior_info.cpp85
-rw-r--r--src/audio_core/behavior_info.h58
-rw-r--r--src/audio_core/codec.cpp5
-rw-r--r--src/audio_core/codec.h2
-rw-r--r--src/audio_core/command_generator.cpp977
-rw-r--r--src/audio_core/command_generator.h102
-rw-r--r--src/audio_core/common.h66
-rw-r--r--src/audio_core/cubeb_sink.cpp28
-rw-r--r--src/audio_core/effect_context.cpp299
-rw-r--r--src/audio_core/effect_context.h321
-rw-r--r--src/audio_core/info_updater.cpp516
-rw-r--r--src/audio_core/info_updater.h58
-rw-r--r--src/audio_core/memory_pool.cpp62
-rw-r--r--src/audio_core/memory_pool.h53
-rw-r--r--src/audio_core/mix_context.cpp296
-rw-r--r--src/audio_core/mix_context.h114
-rw-r--r--src/audio_core/sink_context.cpp31
-rw-r--r--src/audio_core/sink_context.h89
-rw-r--r--src/audio_core/splitter_context.cpp617
-rw-r--r--src/audio_core/splitter_context.h221
-rw-r--r--src/audio_core/stream.cpp7
-rw-r--r--src/audio_core/voice_context.cpp529
-rw-r--r--src/audio_core/voice_context.h296
-rw-r--r--src/common/CMakeLists.txt8
-rw-r--r--src/common/assert.h7
-rw-r--r--src/common/color.h4
-rw-r--r--src/common/common_funcs.h14
-rw-r--r--src/common/hex_util.h10
-rw-r--r--src/common/math_util.h6
-rw-r--r--src/common/param_package.h2
-rw-r--r--src/common/quaternion.h30
-rw-r--r--src/common/thread.cpp12
-rw-r--r--src/common/thread.h9
-rw-r--r--src/common/vector_math.h75
-rw-r--r--src/common/wall_clock.cpp2
-rw-r--r--src/common/wall_clock.h2
-rw-r--r--src/common/x64/native_clock.h2
-rw-r--r--src/common/x64/xbyak_abi.h32
-rw-r--r--src/core/CMakeLists.txt32
-rw-r--r--src/core/arm/cpu_interrupt_handler.cpp6
-rw-r--r--src/core/arm/cpu_interrupt_handler.h3
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp13
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp13
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.cpp6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.h4
-rw-r--r--src/core/core.cpp9
-rw-r--r--src/core/core.h6
-rw-r--r--src/core/core_timing.cpp12
-rw-r--r--src/core/core_timing_util.cpp1
-rw-r--r--src/core/core_timing_util.h1
-rw-r--r--src/core/cpu_manager.cpp31
-rw-r--r--src/core/crypto/key_manager.cpp162
-rw-r--r--src/core/crypto/key_manager.h10
-rw-r--r--src/core/crypto/partition_data_manager.cpp1
-rw-r--r--src/core/file_sys/bis_factory.cpp11
-rw-r--r--src/core/file_sys/bis_factory.h5
-rw-r--r--src/core/file_sys/card_image.cpp5
-rw-r--r--src/core/file_sys/card_image.h7
-rw-r--r--src/core/file_sys/content_archive.cpp15
-rw-r--r--src/core/file_sys/content_archive.h2
-rw-r--r--src/core/file_sys/control_metadata.cpp1
-rw-r--r--src/core/file_sys/control_metadata.h4
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp10
-rw-r--r--src/core/file_sys/ips_layer.cpp8
-rw-r--r--src/core/file_sys/kernel_executable.cpp3
-rw-r--r--src/core/file_sys/kernel_executable.h9
-rw-r--r--src/core/file_sys/nca_metadata.cpp3
-rw-r--r--src/core/file_sys/nca_metadata.h2
-rw-r--r--src/core/file_sys/nca_patch.cpp83
-rw-r--r--src/core/file_sys/nca_patch.h4
-rw-r--r--src/core/file_sys/partition_filesystem.cpp8
-rw-r--r--src/core/file_sys/partition_filesystem.h8
-rw-r--r--src/core/file_sys/patch_manager.cpp143
-rw-r--r--src/core/file_sys/patch_manager.h52
-rw-r--r--src/core/file_sys/program_metadata.cpp1
-rw-r--r--src/core/file_sys/program_metadata.h2
-rw-r--r--src/core/file_sys/registered_cache.cpp33
-rw-r--r--src/core/file_sys/romfs.h1
-rw-r--r--src/core/file_sys/romfs_factory.cpp50
-rw-r--r--src/core/file_sys/romfs_factory.h21
-rw-r--r--src/core/file_sys/sdmc_factory.cpp2
-rw-r--r--src/core/file_sys/sdmc_factory.h2
-rw-r--r--src/core/file_sys/submission_package.cpp96
-rw-r--r--src/core/file_sys/submission_package.h7
-rw-r--r--src/core/file_sys/vfs.cpp7
-rw-r--r--src/core/file_sys/vfs_offset.cpp7
-rw-r--r--src/core/file_sys/vfs_real.cpp80
-rw-r--r--src/core/file_sys/vfs_static.h8
-rw-r--r--src/core/file_sys/xts_archive.cpp10
-rw-r--r--src/core/file_sys/xts_archive.h10
-rw-r--r--src/core/frontend/applets/controller.cpp81
-rw-r--r--src/core/frontend/applets/controller.h56
-rw-r--r--src/core/frontend/emu_window.cpp10
-rw-r--r--src/core/frontend/framebuffer_layout.cpp6
-rw-r--r--src/core/frontend/framebuffer_layout.h1
-rw-r--r--src/core/frontend/input.h25
-rw-r--r--src/core/gdbstub/gdbstub.cpp30
-rw-r--r--src/core/hle/ipc_helpers.h19
-rw-r--r--src/core/hle/kernel/client_session.cpp5
-rw-r--r--src/core/hle/kernel/client_session.h7
-rw-r--r--src/core/hle/kernel/handle_table.cpp2
-rw-r--r--src/core/hle/kernel/kernel.cpp3
-rw-r--r--src/core/hle/kernel/scheduler.cpp18
-rw-r--r--src/core/hle/kernel/scheduler.h2
-rw-r--r--src/core/hle/kernel/server_session.cpp6
-rw-r--r--src/core/hle/kernel/server_session.h11
-rw-r--r--src/core/hle/kernel/svc.cpp2
-rw-r--r--src/core/hle/service/acc/acc.cpp19
-rw-r--r--src/core/hle/service/acc/acc.h1
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp10
-rw-r--r--src/core/hle/service/am/am.h2
-rw-r--r--src/core/hle/service/am/applets/applets.cpp72
-rw-r--r--src/core/hle/service/am/applets/applets.h19
-rw-r--r--src/core/hle/service/am/applets/controller.cpp210
-rw-r--r--src/core/hle/service/am/applets/controller.h123
-rw-r--r--src/core/hle/service/audio/audren_u.cpp149
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp20
-rw-r--r--src/core/hle/service/caps/caps_c.cpp16
-rw-r--r--src/core/hle/service/caps/caps_c.h3
-rw-r--r--src/core/hle/service/caps/caps_su.cpp7
-rw-r--r--src/core/hle/service/caps/caps_u.cpp15
-rw-r--r--src/core/hle/service/caps/caps_u.h1
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp16
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h4
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp4
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp643
-rw-r--r--src/core/hle/service/hid/controllers/npad.h92
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp12
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h1
-rw-r--r--src/core/hle/service/hid/hid.cpp158
-rw-r--r--src/core/hle/service/hid/hid.h7
-rw-r--r--src/core/hle/service/mii/manager.cpp6
-rw-r--r--src/core/hle/service/nfp/nfp.cpp23
-rw-r--r--src/core/hle/service/nifm/nifm.cpp13
-rw-r--r--src/core/hle/service/ns/ns.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h9
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp70
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h52
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp74
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h63
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp14
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h1
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp6
-rw-r--r--src/core/hle/service/service.cpp13
-rw-r--r--src/core/hle/service/service.h4
-rw-r--r--src/core/hle/service/sm/sm.cpp13
-rw-r--r--src/core/hle/service/sm/sm.h7
-rw-r--r--src/core/hle/service/sockets/blocking_worker.h161
-rw-r--r--src/core/hle/service/sockets/bsd.cpp810
-rw-r--r--src/core/hle/service/sockets/bsd.h150
-rw-r--r--src/core/hle/service/sockets/sockets.cpp6
-rw-r--r--src/core/hle/service/sockets/sockets.h85
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp165
-rw-r--r--src/core/hle/service/sockets/sockets_translate.h48
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp21
-rw-r--r--src/core/hle/service/vi/vi.cpp54
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp18
-rw-r--r--src/core/loader/deconstructed_rom_directory.h6
-rw-r--r--src/core/loader/elf.cpp3
-rw-r--r--src/core/loader/elf.h6
-rw-r--r--src/core/loader/kip.cpp5
-rw-r--r--src/core/loader/kip.h6
-rw-r--r--src/core/loader/loader.h7
-rw-r--r--src/core/loader/nax.cpp5
-rw-r--r--src/core/loader/nax.h8
-rw-r--r--src/core/loader/nca.cpp8
-rw-r--r--src/core/loader/nca.h6
-rw-r--r--src/core/loader/nro.cpp8
-rw-r--r--src/core/loader/nro.h6
-rw-r--r--src/core/loader/nso.cpp15
-rw-r--r--src/core/loader/nso.h14
-rw-r--r--src/core/loader/nsp.cpp7
-rw-r--r--src/core/loader/nsp.h6
-rw-r--r--src/core/loader/xci.cpp7
-rw-r--r--src/core/loader/xci.h6
-rw-r--r--src/core/memory.cpp14
-rw-r--r--src/core/memory/cheat_engine.cpp44
-rw-r--r--src/core/memory/cheat_engine.h5
-rw-r--r--src/core/network/network.cpp48
-rw-r--r--src/core/settings.cpp50
-rw-r--r--src/core/settings.h354
-rw-r--r--src/input_common/CMakeLists.txt37
-rwxr-xr-xsrc/input_common/analog_from_button.cpp18
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp134
-rw-r--r--src/input_common/gcadapter/gc_adapter.h13
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp66
-rw-r--r--src/input_common/keyboard.cpp5
-rw-r--r--src/input_common/main.cpp267
-rw-r--r--src/input_common/main.h152
-rw-r--r--src/input_common/motion_emu.cpp58
-rw-r--r--src/input_common/motion_from_button.cpp34
-rw-r--r--src/input_common/motion_from_button.h25
-rw-r--r--src/input_common/motion_input.cpp301
-rw-r--r--src/input_common/motion_input.h73
-rw-r--r--src/input_common/sdl/sdl.h19
-rw-r--r--src/input_common/sdl/sdl_impl.cpp675
-rw-r--r--src/input_common/sdl/sdl_impl.h10
-rw-r--r--src/input_common/settings.cpp40
-rw-r--r--src/input_common/settings.h352
-rw-r--r--src/input_common/touch_from_button.cpp52
-rw-r--r--src/input_common/touch_from_button.h23
-rw-r--r--src/input_common/udp/client.cpp226
-rw-r--r--src/input_common/udp/client.h89
-rw-r--r--src/input_common/udp/udp.cpp175
-rw-r--r--src/input_common/udp/udp.h54
-rw-r--r--src/video_core/CMakeLists.txt22
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h51
-rw-r--r--src/video_core/engines/fermi_2d.cpp22
-rw-r--r--src/video_core/engines/fermi_2d.h13
-rw-r--r--src/video_core/engines/kepler_compute.cpp17
-rw-r--r--src/video_core/engines/kepler_compute.h16
-rw-r--r--src/video_core/engines/maxwell_3d.cpp37
-rw-r--r--src/video_core/engines/maxwell_3d.h21
-rw-r--r--src/video_core/engines/maxwell_dma.cpp2
-rw-r--r--src/video_core/engines/shader_header.h13
-rw-r--r--src/video_core/fence_manager.h32
-rw-r--r--src/video_core/gpu.cpp31
-rw-r--r--src/video_core/gpu.h16
-rw-r--r--src/video_core/gpu_asynch.cpp10
-rw-r--r--src/video_core/gpu_asynch.h4
-rw-r--r--src/video_core/gpu_synch.cpp8
-rw-r--r--src/video_core/gpu_synch.h6
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt43
-rw-r--r--src/video_core/host_shaders/StringShaderHeader.cmake11
-rw-r--r--src/video_core/host_shaders/opengl_present.frag10
-rw-r--r--src/video_core/host_shaders/opengl_present.vert24
-rw-r--r--src/video_core/host_shaders/source_shader.h.in9
-rw-r--r--src/video_core/macro/macro.cpp2
-rw-r--r--src/video_core/macro/macro_hle.cpp6
-rw-r--r--src/video_core/macro/macro_interpreter.cpp1
-rw-r--r--src/video_core/macro/macro_jit_x64.cpp10
-rw-r--r--src/video_core/memory_manager.cpp22
-rw-r--r--src/video_core/memory_manager.h41
-rw-r--r--src/video_core/query_cache.h37
-rw-r--r--src/video_core/rasterizer_interface.h7
-rw-r--r--src/video_core/renderer_base.cpp4
-rw-r--r--src/video_core/renderer_base.h22
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h3
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_fence_manager.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_fence_manager.h7
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.h14
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp261
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h26
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp64
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h23
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp33
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.h16
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.h2
-rw-r--r--src/video_core/renderer_opengl/gl_state_tracker.cpp6
-rw-r--r--src/video_core/renderer_opengl/gl_state_tracker.h28
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h8
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h6
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp348
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h44
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp3
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.h10
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp24
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp51
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h25
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp37
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h25
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp17
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h7
-rw-r--r--src/video_core/renderer_vulkan/vk_command_pool.cpp46
-rw-r--r--src/video_core/renderer_vulkan/vk_command_pool.h34
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp23
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.cpp19
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.h15
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp32
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.cpp18
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.cpp56
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.h70
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp95
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h29
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp57
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.h23
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp142
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h20
-rw-r--r--src/video_core/renderer_vulkan/vk_resource_manager.cpp311
-rw-r--r--src/video_core/renderer_vulkan/vk_resource_manager.h196
-rw-r--r--src/video_core/renderer_vulkan/vk_resource_pool.cpp63
-rw-r--r--src/video_core/renderer_vulkan/vk_resource_pool.h43
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp77
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h70
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp49
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.h14
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.cpp19
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.h28
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp20
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h9
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp25
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h19
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp71
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h48
-rw-r--r--src/video_core/shader/ast.h25
-rw-r--r--src/video_core/shader/async_shaders.cpp6
-rw-r--r--src/video_core/shader/async_shaders.h37
-rw-r--r--src/video_core/shader/control_flow.cpp27
-rw-r--r--src/video_core/shader/decode/arithmetic_half.cpp3
-rw-r--r--src/video_core/shader/decode/arithmetic_integer_immediate.cpp35
-rw-r--r--src/video_core/shader/decode/image.cpp15
-rw-r--r--src/video_core/shader/decode/memory.cpp3
-rw-r--r--src/video_core/shader/decode/texture.cpp43
-rw-r--r--src/video_core/shader/memory_util.cpp7
-rw-r--r--src/video_core/shader/memory_util.h6
-rw-r--r--src/video_core/shader/registry.cpp50
-rw-r--r--src/video_core/shader/registry.h2
-rw-r--r--src/video_core/shader/track.cpp4
-rw-r--r--src/video_core/texture_cache/surface_base.cpp10
-rw-r--r--src/video_core/texture_cache/surface_params.cpp11
-rw-r--r--src/video_core/texture_cache/surface_params.h5
-rw-r--r--src/video_core/texture_cache/texture_cache.h51
-rw-r--r--src/video_core/video_core.cpp35
-rw-r--r--src/web_service/CMakeLists.txt1
-rw-r--r--src/web_service/telemetry_json.cpp4
-rw-r--r--src/web_service/verify_login.cpp2
-rw-r--r--src/web_service/web_backend.cpp69
-rw-r--r--src/web_service/web_backend.h20
-rw-r--r--src/web_service/web_result.h (renamed from src/common/web_result.h)4
-rw-r--r--src/yuzu/CMakeLists.txt22
-rw-r--r--src/yuzu/applets/controller.cpp601
-rw-r--r--src/yuzu/applets/controller.h133
-rw-r--r--src/yuzu/applets/controller.ui2672
-rw-r--r--src/yuzu/bootmanager.cpp52
-rw-r--r--src/yuzu/bootmanager.h9
-rw-r--r--src/yuzu/configuration/config.cpp210
-rw-r--r--src/yuzu/configuration/config.h7
-rw-r--r--src/yuzu/configuration/configure.ui59
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp17
-rw-r--r--src/yuzu/configuration/configure_cpu.h1
-rw-r--r--src/yuzu/configuration/configure_cpu.ui52
-rw-r--r--src/yuzu/configuration/configure_debug_controller.cpp40
-rw-r--r--src/yuzu/configuration/configure_debug_controller.h38
-rw-r--r--src/yuzu/configuration/configure_debug_controller.ui97
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp13
-rw-r--r--src/yuzu/configuration/configure_dialog.h7
-rw-r--r--src/yuzu/configuration/configure_input.cpp292
-rw-r--r--src/yuzu/configuration/configure_input.h31
-rw-r--r--src/yuzu/configuration/configure_input.ui1039
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp171
-rw-r--r--src/yuzu/configuration/configure_input_advanced.h46
-rw-r--r--src/yuzu/configuration/configure_input_advanced.ui2688
-rw-r--r--src/yuzu/configuration/configure_input_dialog.cpp37
-rw-r--r--src/yuzu/configuration/configure_input_dialog.h38
-rw-r--r--src/yuzu/configuration/configure_input_dialog.ui57
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp903
-rw-r--r--src/yuzu/configuration/configure_input_player.h120
-rw-r--r--src/yuzu/configuration/configure_input_player.ui4120
-rw-r--r--src/yuzu/configuration/configure_input_simple.cpp152
-rw-r--r--src/yuzu/configuration/configure_input_simple.h43
-rw-r--r--src/yuzu/configuration/configure_input_simple.ui97
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp314
-rw-r--r--src/yuzu/configuration/configure_motion_touch.h90
-rw-r--r--src/yuzu/configuration/configure_motion_touch.ui327
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp56
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.h15
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.ui252
-rw-r--r--src/yuzu/configuration/configure_touch_from_button.cpp623
-rw-r--r--src/yuzu/configuration/configure_touch_from_button.h92
-rw-r--r--src/yuzu/configuration/configure_touch_from_button.ui231
-rw-r--r--src/yuzu/configuration/configure_touch_widget.h62
-rw-r--r--src/yuzu/game_list.cpp85
-rw-r--r--src/yuzu/game_list.h24
-rw-r--r--src/yuzu/game_list_p.h34
-rw-r--r--src/yuzu/install_dialog.h5
-rw-r--r--src/yuzu/main.cpp81
-rw-r--r--src/yuzu/main.h23
-rw-r--r--src/yuzu/main.ui2
-rw-r--r--src/yuzu/uisettings.cpp1
-rw-r--r--src/yuzu/uisettings.h4
-rw-r--r--src/yuzu_cmd/config.cpp4
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp17
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h15
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp14
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h8
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp8
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h10
-rw-r--r--src/yuzu_cmd/yuzu.cpp17
-rw-r--r--src/yuzu_tester/config.cpp2
-rw-r--r--src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp5
-rw-r--r--src/yuzu_tester/emu_window/emu_window_sdl2_hide.h6
-rw-r--r--src/yuzu_tester/yuzu.cpp1
502 files changed, 83501 insertions, 9202 deletions
diff --git a/.ci/yuzu-patreon-step2.yml b/.ci/yuzu-patreon-step2.yml
index 41eccd973..3f338e2a0 100644
--- a/.ci/yuzu-patreon-step2.yml
+++ b/.ci/yuzu-patreon-step2.yml
@@ -9,6 +9,7 @@ stages:
displayName: 'build'
jobs:
- job: build
+ timeoutInMinutes: 120
displayName: 'windows-msvc'
pool:
vmImage: windows-2019
diff --git a/.gitmodules b/.gitmodules
index 79028bbb5..9d9356151 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -16,6 +16,9 @@
[submodule "libressl"]
path = externals/libressl
url = https://github.com/citra-emu/ext-libressl-portable.git
+[submodule "libusb"]
+ path = externals/libusb/libusb
+ url = https://github.com/libusb/libusb.git
[submodule "discord-rpc"]
path = externals/discord-rpc
url = https://github.com/discordapp/discord-rpc.git
@@ -34,9 +37,6 @@
[submodule "xbyak"]
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
-[submodule "externals/libusb"]
- path = externals/libusb
- url = https://github.com/ameerj/libusb
[submodule "opus"]
path = externals/opus/opus
url = https://github.com/xiph/opus.git
diff --git a/.lgtm.yml b/.lgtm.yml
new file mode 100644
index 000000000..5751d0e4c
--- /dev/null
+++ b/.lgtm.yml
@@ -0,0 +1,10 @@
+path_classifiers:
+ library: "externals"
+extraction:
+ cpp:
+ prepare:
+ packages:
+ - "libsdl2-dev"
+ - "qtmultimedia5-dev"
+ - "libtbb-dev"
+ - "libjack-jackd2-dev"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2f3c59c5d..45bd03a65 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -210,7 +210,7 @@ if(ENABLE_QT)
set(QT_PREFIX_HINT)
if(YUZU_USE_BUNDLED_QT)
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
- set(QT_VER qt-5.12.0-msvc2017_64)
+ set(QT_VER qt-5.12.8-msvc2017_64)
else()
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
endif()
diff --git a/dist/icons/controller/applet_dual_joycon.png b/dist/icons/controller/applet_dual_joycon.png
new file mode 100644
index 000000000..32e0a04ae
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_dark.png b/dist/icons/controller/applet_dual_joycon_dark.png
new file mode 100644
index 000000000..6adc66356
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_dark_disabled.png b/dist/icons/controller/applet_dual_joycon_dark_disabled.png
new file mode 100644
index 000000000..208603ee7
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_disabled.png b/dist/icons/controller/applet_dual_joycon_disabled.png
new file mode 100644
index 000000000..43950618d
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_midnight.png b/dist/icons/controller/applet_dual_joycon_midnight.png
new file mode 100644
index 000000000..c7edea8a3
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_midnight_disabled.png b/dist/icons/controller/applet_dual_joycon_midnight_disabled.png
new file mode 100644
index 000000000..ee1aafc85
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld.png b/dist/icons/controller/applet_handheld.png
new file mode 100644
index 000000000..7f8dd2227
--- /dev/null
+++ b/dist/icons/controller/applet_handheld.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_dark.png b/dist/icons/controller/applet_handheld_dark.png
new file mode 100644
index 000000000..41f6d7aea
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_dark_disabled.png b/dist/icons/controller/applet_handheld_dark_disabled.png
new file mode 100644
index 000000000..5a136ddd1
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_disabled.png b/dist/icons/controller/applet_handheld_disabled.png
new file mode 100644
index 000000000..53f8ce7ad
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_midnight.png b/dist/icons/controller/applet_handheld_midnight.png
new file mode 100644
index 000000000..7188b9154
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_midnight_disabled.png b/dist/icons/controller/applet_handheld_midnight_disabled.png
new file mode 100644
index 000000000..6ccfc3253
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller.png b/dist/icons/controller/applet_pro_controller.png
new file mode 100644
index 000000000..e32258855
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_dark.png b/dist/icons/controller/applet_pro_controller_dark.png
new file mode 100644
index 000000000..c122b7b11
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_dark_disabled.png b/dist/icons/controller/applet_pro_controller_dark_disabled.png
new file mode 100644
index 000000000..416e1e2fb
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_disabled.png b/dist/icons/controller/applet_pro_controller_disabled.png
new file mode 100644
index 000000000..72a549ea9
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_midnight.png b/dist/icons/controller/applet_pro_controller_midnight.png
new file mode 100644
index 000000000..622e57fa1
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_midnight_disabled.png b/dist/icons/controller/applet_pro_controller_midnight_disabled.png
new file mode 100644
index 000000000..2907f3be4
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left.png b/dist/icons/controller/applet_single_joycon_left.png
new file mode 100644
index 000000000..47c44d43a
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_dark.png b/dist/icons/controller/applet_single_joycon_left_dark.png
new file mode 100644
index 000000000..69530b69c
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_dark_disabled.png b/dist/icons/controller/applet_single_joycon_left_dark_disabled.png
new file mode 100644
index 000000000..cfe4b1475
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_disabled.png b/dist/icons/controller/applet_single_joycon_left_disabled.png
new file mode 100644
index 000000000..c0102dc20
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_midnight.png b/dist/icons/controller/applet_single_joycon_left_midnight.png
new file mode 100644
index 000000000..56522bccb
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_midnight_disabled.png b/dist/icons/controller/applet_single_joycon_left_midnight_disabled.png
new file mode 100644
index 000000000..62434c188
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right.png b/dist/icons/controller/applet_single_joycon_right.png
new file mode 100644
index 000000000..b0d4fba90
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_dark.png b/dist/icons/controller/applet_single_joycon_right_dark.png
new file mode 100644
index 000000000..af26cce4b
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_dark_disabled.png b/dist/icons/controller/applet_single_joycon_right_dark_disabled.png
new file mode 100644
index 000000000..b33efab42
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_disabled.png b/dist/icons/controller/applet_single_joycon_right_disabled.png
new file mode 100644
index 000000000..01ca38322
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_midnight.png b/dist/icons/controller/applet_single_joycon_right_midnight.png
new file mode 100644
index 000000000..5bf70e21e
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_midnight_disabled.png b/dist/icons/controller/applet_single_joycon_right_midnight_disabled.png
new file mode 100644
index 000000000..e6693b027
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/controller.qrc b/dist/icons/controller/controller.qrc
new file mode 100644
index 000000000..1c4e960c0
--- /dev/null
+++ b/dist/icons/controller/controller.qrc
@@ -0,0 +1,55 @@
+<RCC>
+ <qresource prefix="controller">
+ <file alias="dual_joycon">dual_joycon.png</file>
+ <file alias="dual_joycon_dark">dual_joycon_dark.png</file>
+ <file alias="dual_joycon_midnight">dual_joycon_midnight.png</file>
+ <file alias="handheld">handheld.png</file>
+ <file alias="handheld_dark">handheld_dark.png</file>
+ <file alias="handheld_midnight">handheld_midnight.png</file>
+ <file alias="pro_controller">pro_controller.png</file>
+ <file alias="pro_controller_dark">pro_controller_dark.png</file>
+ <file alias="pro_controller_midnight">pro_controller_midnight.png</file>
+ <file alias="single_joycon_left">single_joycon_left.png</file>
+ <file alias="single_joycon_left_dark">single_joycon_left_dark.png</file>
+ <file alias="single_joycon_left_midnight">single_joycon_left_midnight.png</file>
+ <file alias="single_joycon_right">single_joycon_right.png</file>
+ <file alias="single_joycon_right_dark">single_joycon_right_dark.png</file>
+ <file alias="single_joycon_right_midnight">single_joycon_right_midnight.png</file>
+ <file alias="single_joycon_left_vertical">single_joycon_left_vertical.png</file>
+ <file alias="single_joycon_left_vertical_dark">single_joycon_left_vertical_dark.png</file>
+ <file alias="single_joycon_left_vertical_midnight">single_joycon_left_vertical_midnight.png</file>
+ <file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file>
+ <file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file>
+ <file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file>
+ <file alias="applet_dual_joycon">applet_dual_joycon.png</file>
+ <file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file>
+ <file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file>
+ <file alias="applet_handheld">applet_handheld.png</file>
+ <file alias="applet_handheld_dark">applet_handheld_dark.png</file>
+ <file alias="applet_handheld_midnight">applet_handheld_midnight.png</file>
+ <file alias="applet_pro_controller">applet_pro_controller.png</file>
+ <file alias="applet_pro_controller_dark">applet_pro_controller_dark.png</file>
+ <file alias="applet_pro_controller_midnight">applet_pro_controller_midnight.png</file>
+ <file alias="applet_joycon_left">applet_single_joycon_left.png</file>
+ <file alias="applet_joycon_left_dark">applet_single_joycon_left_dark.png</file>
+ <file alias="applet_joycon_left_midnight">applet_single_joycon_left_midnight.png</file>
+ <file alias="applet_joycon_right">applet_single_joycon_right.png</file>
+ <file alias="applet_joycon_right_dark">applet_single_joycon_right_dark.png</file>
+ <file alias="applet_joycon_right_midnight">applet_single_joycon_right_midnight.png</file>
+ <file alias="applet_dual_joycon_disabled">applet_dual_joycon_disabled.png</file>
+ <file alias="applet_dual_joycon_dark_disabled">applet_dual_joycon_dark_disabled.png</file>
+ <file alias="applet_dual_joycon_midnight_disabled">applet_dual_joycon_midnight_disabled.png</file>
+ <file alias="applet_handheld_disabled">applet_handheld_disabled.png</file>
+ <file alias="applet_handheld_dark_disabled">applet_handheld_dark_disabled.png</file>
+ <file alias="applet_handheld_midnight_disabled">applet_handheld_midnight_disabled.png</file>
+ <file alias="applet_pro_controller_disabled">applet_pro_controller_disabled.png</file>
+ <file alias="applet_pro_controller_dark_disabled">applet_pro_controller_dark_disabled.png</file>
+ <file alias="applet_pro_controller_midnight_disabled">applet_pro_controller_midnight_disabled.png</file>
+ <file alias="applet_joycon_left_disabled">applet_single_joycon_left_disabled.png</file>
+ <file alias="applet_joycon_left_dark_disabled">applet_single_joycon_left_dark_disabled.png</file>
+ <file alias="applet_joycon_left_midnight_disabled">applet_single_joycon_left_midnight_disabled.png</file>
+ <file alias="applet_joycon_right_disabled">applet_single_joycon_right_disabled.png</file>
+ <file alias="applet_joycon_right_dark_disabled">applet_single_joycon_right_dark_disabled.png</file>
+ <file alias="applet_joycon_right_midnight_disabled">applet_single_joycon_right_midnight_disabled.png</file>
+ </qresource>
+</RCC>
diff --git a/dist/icons/controller/dual_joycon.png b/dist/icons/controller/dual_joycon.png
new file mode 100644
index 000000000..4230f5f7b
--- /dev/null
+++ b/dist/icons/controller/dual_joycon.png
Binary files differ
diff --git a/dist/icons/controller/dual_joycon_dark.png b/dist/icons/controller/dual_joycon_dark.png
new file mode 100644
index 000000000..4445db489
--- /dev/null
+++ b/dist/icons/controller/dual_joycon_dark.png
Binary files differ
diff --git a/dist/icons/controller/dual_joycon_midnight.png b/dist/icons/controller/dual_joycon_midnight.png
new file mode 100644
index 000000000..aac8e5321
--- /dev/null
+++ b/dist/icons/controller/dual_joycon_midnight.png
Binary files differ
diff --git a/dist/icons/controller/handheld.png b/dist/icons/controller/handheld.png
new file mode 100644
index 000000000..d009b4a47
--- /dev/null
+++ b/dist/icons/controller/handheld.png
Binary files differ
diff --git a/dist/icons/controller/handheld_dark.png b/dist/icons/controller/handheld_dark.png
new file mode 100644
index 000000000..c80ca9259
--- /dev/null
+++ b/dist/icons/controller/handheld_dark.png
Binary files differ
diff --git a/dist/icons/controller/handheld_midnight.png b/dist/icons/controller/handheld_midnight.png
new file mode 100644
index 000000000..19de4629b
--- /dev/null
+++ b/dist/icons/controller/handheld_midnight.png
Binary files differ
diff --git a/dist/icons/controller/pro_controller.png b/dist/icons/controller/pro_controller.png
new file mode 100644
index 000000000..07d65e94a
--- /dev/null
+++ b/dist/icons/controller/pro_controller.png
Binary files differ
diff --git a/dist/icons/controller/pro_controller_dark.png b/dist/icons/controller/pro_controller_dark.png
new file mode 100644
index 000000000..73efe18f4
--- /dev/null
+++ b/dist/icons/controller/pro_controller_dark.png
Binary files differ
diff --git a/dist/icons/controller/pro_controller_midnight.png b/dist/icons/controller/pro_controller_midnight.png
new file mode 100644
index 000000000..8d7e63f0d
--- /dev/null
+++ b/dist/icons/controller/pro_controller_midnight.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left.png b/dist/icons/controller/single_joycon_left.png
new file mode 100644
index 000000000..547153034
--- /dev/null
+++ b/dist/icons/controller/single_joycon_left.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_dark.png b/dist/icons/controller/single_joycon_left_dark.png
new file mode 100644
index 000000000..b6ee073cb
--- /dev/null
+++ b/dist/icons/controller/single_joycon_left_dark.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_midnight.png b/dist/icons/controller/single_joycon_left_midnight.png
new file mode 100644
index 000000000..34a485c81
--- /dev/null
+++ b/dist/icons/controller/single_joycon_left_midnight.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_vertical.png b/dist/icons/controller/single_joycon_left_vertical.png
new file mode 100644
index 000000000..1e6282ad8
--- /dev/null
+++ b/dist/icons/controller/single_joycon_left_vertical.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_vertical_dark.png b/dist/icons/controller/single_joycon_left_vertical_dark.png
new file mode 100644
index 000000000..a615d995d
--- /dev/null
+++ b/dist/icons/controller/single_joycon_left_vertical_dark.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_vertical_midnight.png b/dist/icons/controller/single_joycon_left_vertical_midnight.png
new file mode 100644
index 000000000..4cc578216
--- /dev/null
+++ b/dist/icons/controller/single_joycon_left_vertical_midnight.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right.png b/dist/icons/controller/single_joycon_right.png
new file mode 100644
index 000000000..8d29173f6
--- /dev/null
+++ b/dist/icons/controller/single_joycon_right.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_dark.png b/dist/icons/controller/single_joycon_right_dark.png
new file mode 100644
index 000000000..ead2c44e0
--- /dev/null
+++ b/dist/icons/controller/single_joycon_right_dark.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_midnight.png b/dist/icons/controller/single_joycon_right_midnight.png
new file mode 100644
index 000000000..89afe022d
--- /dev/null
+++ b/dist/icons/controller/single_joycon_right_midnight.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_vertical.png b/dist/icons/controller/single_joycon_right_vertical.png
new file mode 100644
index 000000000..4d7d06547
--- /dev/null
+++ b/dist/icons/controller/single_joycon_right_vertical.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_vertical_dark.png b/dist/icons/controller/single_joycon_right_vertical_dark.png
new file mode 100644
index 000000000..9a6eb3013
--- /dev/null
+++ b/dist/icons/controller/single_joycon_right_vertical_dark.png
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_vertical_midnight.png b/dist/icons/controller/single_joycon_right_vertical_midnight.png
new file mode 100644
index 000000000..685249b68
--- /dev/null
+++ b/dist/icons/controller/single_joycon_right_vertical_midnight.png
Binary files differ
diff --git a/dist/languages/de.ts b/dist/languages/de.ts
new file mode 100644
index 000000000..b93c9f51c
--- /dev/null
+++ b/dist/languages/de.ts
@@ -0,0 +1,4749 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="de" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>Über yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu ist ein experimenteller, quelloffener Emulator für Nintendo Switch, lizensiert unter GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Diese Software sollte nicht dazu verwendet werden, Spiele zu spielen, die du nicht legal erhalten hast.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Webseite&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Quellcode&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Mitwirkende&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lizenz&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; ist ein Warenzeichen von Nintendo. yuzu ist in keiner Weise mit Nintendo verbunden.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation>Verbindung mit dem Server wird hergestellt...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation>Tippe auf die obere linke Ecke &lt;br&gt;deines Touchpads.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation>Tippe auf die untere rechte Ecke &lt;br&gt;deines Touchpads.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation>Konfiguration abgeschlossen!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>Kompatibilität melden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>Kompatibilität des Spiels melden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Solltest du einen Bericht zur &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu-Kompatibilitätsliste&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; beitragen wollen, werden die folgenden Informationen gesammelt und auf der yuzu-Webseite dargestellt:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware-Informationen (CPU / GPU / Betriebssystem)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Welche yuzu-Version du benutzt&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Den verbundenen yuzu-Account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>Perfekt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Das Spiel funktioniert einwandfrei und ohne Audio- oder Grafikfehler.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>Gut</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Das Spiel funktioniert mit kleineren Grafik- oder Audiofehlern und ist von Anfang bis Ende spielbar. Eventuell sind einige Workarounds erforderlich.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>Okay</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Das Spiel funktioniert mit größeren Grafik- oder Audiofehlern, lässt sich aber mit Workarounds bis zum Ende durchspielen. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>Schlecht</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Spiel funktioniert zwar, aber nur mit starken Grafik- oder Audiofehlern. Manche Bereiche des Spiels können selbst mit Workarounds nicht abgeschlossen werden.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menü</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Das Spiel ist wegen schwerwiegendsten Grafik- oder Audiofehlern unspielbar. Das Spiel lässt sich lediglich starten.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Startet nicht</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Das Spiel stürzt beim Versuch zu starten ab.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Unabhängig von Geschwindigkeit oder Performance, wie gut läuft das Spiel von Start bis Ende in dieser Version von yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>Vielen Dank für deinen Beitrag!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>Absenden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>Kommunikationsfehler</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>Beim Senden des Berichtes ist ein Fehler aufgetreten.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>Weiter</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>Ausgabe-Engine:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>Dieser Nachbearbeitungseffekt passt die Audiogeschwindigkeit an die Emulationsgeschwindigkeit an und verhindert Audioaussetzer. Dies erhöht jedoch die Audioverzögerung.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>Audiodehnung aktivieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>Audiogerät:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation>Globale Lautstärke verwenden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation>Lautstärke:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>Lautstärke:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation>Allgemeines</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation>Genauigkeit der Emulation:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation>Akkurat</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation>Unsicher</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation>Debug-Modus aktivieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation>Wir empfehlen, dies auf &quot;Akkurat&quot; zu stellen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation>Unsichere CPU-Optimierungen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation>Diese Optionen reduzieren die Genauigkeit, können jedoch die Geschwindigkeit erhöhen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation>Unfuse FMA (erhöht Leistung auf CPUs ohne FMA)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Diese Option steigert die Geschwindigkeit, indem die Genauigkeit von sog. &quot;fused-multiply-add&quot; Anweisungen auf CPUs ohne native FMA-Unterstützung reduziert wird.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation>Schnelleres FRSQRTE und FRECPE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Diese Option steigert die Geschwindigkeit von einigen &quot;floating point&quot;-Anweisungen, indem weniger akkurate Schätzungen der Werte verwendet werden.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>Die CPU-Einstellungen sind nur verfügbar, wenn kein Spiel aktiv ist.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation>Debug-Modus für CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation>Der Debug-Modus ist nur für Entwickler gedacht. Bist du dir sicher?</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation>CPU-Optimierungen ändern</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;
+ &lt;b&gt;Dies ist nur zur Fehlerbehebung gedacht .&lt;/b&gt;
+ &lt;br&gt;
+ Falls du dir nicht sicher bist, was hier passiert, solltest du keine dieser Optionen ändern.
+ &lt;br&gt;
+ Diese Optionen treten nur dann in Kraft, wenn auch der CPU Debug-Modus aktiviert ist.
+ &lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation>Enable inline page tables</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation>Enable block linking</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation>Return stack buffer aktivieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation>Enable fast dispatcher</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation>Enable context elimination</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation>Enable constant propagation</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation>Enable miscellaneous optimizations</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation>Enable misalignment check reduction</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>Die CPU-Einstellungen sind nur verfügbar, wenn kein Spiel aktiv ist.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>GDB-Stub aktivieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>Port:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>Logging</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>Globaler Log-Filter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>Log-Konsole öffnen (nur Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>Log-Verzeichnis öffnen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>Homebrew</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>String-Argumente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation>Grafik</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation>Wenn aktiviert, wird die Grafik-API in einem langsamen Debug-Modus gestartet.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation>Grafik-Debugging aktivieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation>Diese Option deaktiviert den Macro-JIT-Compiler. Dies wird die Geschwindigkeit verringern.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation>Macro-JIT deaktivieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation>Speichern</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>Ausführliche Service-Fehlerberichte aktivieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>Dies wird automatisch beim Schließen von yuzu zurückgesetzt.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>Erweitert</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation>Kiosk(Quest)-Modus</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation>Debug-Controller einrichten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation>Löschen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation>Standardwerte</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>yuzu-Konfiguration</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>Allgemein</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>Benutzeroberfläche</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>Spieleliste</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>System</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>Nutzer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>Dateisystem</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>Steuerung</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>Hotkeys</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation>CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>Debug</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>Grafik</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation>Erweitert</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation>GraphicsAdvanced</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Web</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>Services</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>Speicherverzeichnisse</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>SD-Karte</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>Gamecard</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>Pfad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>Eingelegt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>Aktuelles Spiel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>Patchmanager</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>Dekomprimierte NSOs dumpen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>ExeFS dumpen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation>Mod-Ladeverzeichnis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation>Root dumpen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>Caching</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>Cache-Ordner</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation>Metadaten der Spieleliste cachen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>Metadaten-Cache zurücksetzen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>Emulierten NAND-Ordner auswählen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>Emulierten SD-Ordner auswählen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation>Gamecard-Pfad auswählen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>Dump-Verzeichnis auswählen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation>Mod-Ladeverzeichnis auswählen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>Cache-Ordner auswählen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>Der Metadaten-Cache ist bereits leer.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>Der Vorgang wurde erfolgreich abgeschlossen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>Der Metadaten-Cache konnte nicht gelöscht werden. Er könnte in Gebrauch oder nicht vorhanden sein.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>Allgemein</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>Geschwindigkeit auf % festlegen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation>Multicore-CPU-Emulation</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>Schließen des Emulators bestätigen, falls ein Spiel läuft</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation>Beim Spielstart nach Nutzer fragen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>Emulation im Hintergrund pausieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation>Mauszeiger verstecken</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation>API-Einstellungen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation>API:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation>Gerät:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation>Grafik-Einstellungen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>Nutze Festplatten-Shader-Cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>Asynchrone GPU-Emulation verwenden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation>Seitenverhältnis:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation>Standard (16:9)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation>4:3 erzwingen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation>21:9 erzwingen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation>Auf Fenster anpassen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation>Globale Hintergrundfarbe verwenden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation>Hintergrundfarbe:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>Hintergrundfarbe:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation>OpenGL GPU</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation>Erweiterte Grafik-Einstellungen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation>Genauigkeit der Emulation:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation>VSync verhindert Screen-Tearing, aber manche Grafikkarten haben eine schlechtere Leistung, wenn es aktiviert ist. Wenn du keinen Unterschied merkst, lasse es aktiviert.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation>VSync nutzen (Nur OpenGL)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation>Aktivieren dieser Einstellung reduziert Stottern durch Shader. Aktiviert OpenGL Assembly-Shader auf unterstützten Nvidia-Karten (NV_gpu_program5 wird benötigt). Dieses Feature ist experimentell.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation>Nutze Assembly-Shader (experimentell, nur Nvidia OpenGL)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation>Nutze asynchrone Shader-Kompilierung. Dies kann Stottern durch Shader reduzieren. Dieses Feature ist experimentell.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation>Nutze asynchrone Shader-Kompilierung (experimentell)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation>Nutze schnelle GPU-Zeit</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation>Anisotrope Filterung:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation>Standard</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation>2x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation>4x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation>8x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation>16x</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>Hotkey-Einstellungen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation>Doppelklicke auf eine Tastensequenz, um sie zu ändern.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation>Alle löschen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation>Standardwerte wiederherstellen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>Aktion</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>Hotkey</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>Kontext</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>Tastensequenz bereits belegt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation>Die eingegebene Sequenz ist bereits vergeben an: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation>Standardwerte wiederherstellen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation>Löschen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation>Die Standard-Sequenz ist bereits vergeben an: %1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation>ConfigureInput</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>Spieler 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>Spieler 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>Spieler 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>Spieler 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>Spieler 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>Spieler 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>Spieler 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>Spieler 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>Erweitert</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation>Konsolenmodus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation>Im Dock</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation>Handheld</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation>Vibration</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation>Bewegung</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>Konfigurieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation>Controller</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation>1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation>2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation>3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation>4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation>5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation>6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation>7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation>8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation>Verbunden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation>Standardwerte</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation>Löschen</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Eingabe einrichten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation>Joyconfarben</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation>Spieler 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation>Links</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation>L-Taste</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation>Rechts</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation>R-Taste</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation>Spieler 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation>Spieler 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation>Spieler 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation>Spieler 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation>Spieler 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation>Spieler 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation>Spieler 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation>Weiteres</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation>Tastatur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation>Erweitert</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation>Touchscreen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation>Maus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation>Bewegung / Touch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation>Konfigurieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation>Debug Controller</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Eingabe einrichten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation>Controller verbinden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation>Pro Controller</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation>Zwei Joycons</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation>Linker Joycon</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation>Rechter Joycon</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation>Handheld</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation>Eingabegerät</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation>Alle</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation>Tastatur/Maus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation>Profil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation>Speichern</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation>Neu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation>Löschen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>Linker Analogstick</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation>Hoch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation>Links</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation>Rechts</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation>Runter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation>Gedrückt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation>Modifikator</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation>Radius</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation>Deadzone: 0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation>Modifikator-Radius: 0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation>Steuerkreuz</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation>L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation>ZL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation>Minus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation>Screenshot</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation>Plus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation>Home</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation>R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation>ZR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation>SL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation>SR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>Tasten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation>B</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>Rechter Analogstick</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation>Deadzone: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation>Modifikator-Radius: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation>[wartet]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation>Bewegung / Touch einrichten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation>Bewegung</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation>Quelle für Bewegung:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation>Empfindlichkeit:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation>Touch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation>Quelle für Touch:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation>Kalibrierung:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation>(100, 50) - (1800, 850)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation>Einrichtung</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation>Tastenbelegung nutzen:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation>CemuhookUDP Konfiguration</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation>Du kannst alle Cemuhook-kompatiblen UDP-Eingabequellen für Bewegung und Touch verwenden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation>Server:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation>Port:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation>Pad:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation>Pad 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation>Pad 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation>Pad 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation>Pad 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation>Mehr erfahren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation>Testen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation>Maus (Rechtsklick)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation>CemuhookUDP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation>Emulator-Fenster</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Mehr erfahren&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation>Testen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation>Einrichten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation>Test erfolgreich</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation>Daten wurden erfolgreich vom Server empfangen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation>Test fehlgeschlagen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation>Konnte keine Daten vom Server empfangen.&lt;br&gt;Prüfe bitte, dass der Server korrekt eingerichtet wurde und dass Adresse und Port korrekt sind.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation>Citra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation>UDP-Test oder Kalibration wird gerade durchgeführt.&lt;br&gt;Bitte warte einen Moment.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>Maus einrichten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>Maustasten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>Vorwärts:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>Rückwärts:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>Links:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>Mitte:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>Rechts:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>Löschen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation>Standardwerte</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[nicht belegt]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>Standardwert wiederherstellen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[Taste drücken]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation>Info</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation>Name</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation>Titel ID</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation>Dateiname</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation>Format</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation>Version</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation>Größe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation>Entwickler</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation>Add-Ons</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation>Allgemeines</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation>System</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation>Grafik</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation>Erw. Grafik</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation>Einstellungen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation>Globale Konfiguration verwenden (%1)</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation>Patchname</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation>Version</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>Nutzerverwaltung</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>Aktueller Nutzer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>Nutzername</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>Bild wählen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>Hinzufügen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>Umbenennen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>Entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>Die Nutzerverwaltung ist nur verfügbar, wenn kein Spiel aktiv ist.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>Nutzername eingeben</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>Nutzer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>Gib einen Benutzernamen für den neuen Benutzer ein:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>Gib einen neuen Nutzernamen ein:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>Löschen bestätigen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>Du bist dabei, den Nutzer &quot;%1&quot; zu löschen. Bist du dir sicher?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>Profilbild wählen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>JPEG Bilddateien (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>Fehler beim Löschen des Bildes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>Fehler beim Überschreiben des vorherigen Bildes bei: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>Fehler beim Löschen der Datei</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>Konnte die bestehende Datei &quot;%1&quot; nicht löschen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>Fehler beim Erstellen des Ordners für die Profilbilder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>Konnte Ordner &quot;%1&quot; nicht erstellen, um Profilbilder zu speichern.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>Fehler beim Kopieren des Profilbildes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>Das Bild konnte nicht von &quot;%1&quot; nach &quot;%2&quot; kopiert werden</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>BCAT ist Nintendos Methode, Daten an Spiele zu senden, um die Community zu involvieren und zusätzliche Inhalte freizuschalten.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation>BCAT Backend</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Erfahre mehr über BCAT, Boxcat, und aktuelle Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation>Der Boxcat Service ist offline oder du bist nicht mit dem Internet verbunden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>Bei der Verarbeitung der Boxcat-Eventdaten ist ein Fehler aufgetreten. Kontaktiere die yuzu-Entwickler.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>Die Version von yuzu, die du verwendest, ist entweder zu neu oder zu alt für den Server. Versuche auf die neueste offizielle Version von yuzu zu updaten.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation>Es gibt zurzeit keine Events auf Boxcat.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation>Momentane Boxcat-Events</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation>Yuzu lädt den neuesten Boxcat-Status...</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>Systemeinstellungen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation>Region:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation>Auto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation>Standard</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation>CET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation>CST6CDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation>Kuba</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation>EET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation>Ägypten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation>Eire</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation>EST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation>EST5EDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation>GB-Eire</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation>GMT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation>GMT+0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation>GMT-0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation>GMT0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation>Greenwich</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation>Hongkong</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation>HST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation>Island</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation>Iran</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation>Israel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation>Jamaika</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation>Japan</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation>Kwajalein</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation>Libyen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation>MET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation>MST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation>MST7MDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation>Navajo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation>NZ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation>NZ-CHAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation>Polen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation>Portugal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation>PRC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation>PST8PDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation>ROC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation>ROK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation>Singapur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation>Türkei</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation>UCT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation>Universal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation>UTC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation>W-SU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation>WET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation>Zulu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation>USA</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation>Europa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation>Australien</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation>China</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation>Korea</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation>Taiwan</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation>Zeitzone:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>Anmerkung: Diese Einstellung kann überschrieben werden, falls deine Region auf &quot;auto-select&quot; eingestellt ist.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>Japanisch (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>Englisch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>Französisch (français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>Deutsch (German)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>Italienisch (italiano)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>Spanisch (español)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>Chinesisch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>Koreanisch (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>Niederländisch (Nederlands)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>Portugiesisch (português)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>Russisch (Русский)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>Taiwanesisch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>Britisches Englisch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>Kanadisches Französisch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>Lateinamerikanisches Spanisch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>Vereinfachtes Chinesisch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>Traditionelles Chinesisch (正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>Benutzerdefinierte Echtzeituhr</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>Sprache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>RNG Seed</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>Mono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>Stereo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>Surround</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>Konsolen ID:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>Soundausgabe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation>d MMM yyyy h:mm:ss AP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>Neu generieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>Die Systemeinstellungen sind nur verfügbar, wenn kein Spiel aktiv ist.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>Dieser Vorgang wird deine momentane &quot;virtuelle Switch&quot; mit einer Neuen ersetzen. Deine momentane &quot;virtuelle Switch&quot; wird nicht wiederherstellbar sein. Dies könnte einige unerwartete Effekte in manchen Spielen mit sich bringen. Zudem könnte der Prozess fehlschlagen, wenn zu alte Daten verwendet werden. Möchtest du den Vorgang fortsetzen?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>Warnung</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>Konsolen ID: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation>Touchscreen-Belegung einrichten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation>Belegung:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation>Neu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation>Löschen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation>Umbenennen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation>Klicke das untere Feld um einen Punkt hinzuzufügen und drücke dann eine Taste, die diesen Punkt auslösen soll.
+Ziehe die Punkte mit deiner Maus, um ihre Position zu ändern. Doppelklicke auf die Tabelle, um die Belegung des Punktes zu ändern.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation>Punkt löschen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation>Knopf</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation>Neues Profil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation>Neuen Namen für das Profil eingeben.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation>Profil löschen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation>Profil &quot;%1&quot; löschen?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation>Profil umbenennen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation>Neuer Name:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation>[Knopf drücken]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>Touchscreen einrichten:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>Achtung: Die Einstellungen auf dieser Seite haben Einfluss auf yuzus Touchscreen-Emulation. Sie zu ändern könnte zu unerwünschtem Verhalten, wie zu einem Ausfall des Touchscreens, führen. Du solltest sie nur verändern, falls du weißt, was du tust.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>Berührungsparameter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>Berührungsdurchmesser Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>Finger</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>Berührungsdurchmesser X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>Drehwinkel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>Standardwerte wiederherstellen</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>Allgemein</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>Anmerkung: Das Ändern der Sprache wird deine Konfiguration speichern.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>Sprache der Benutzeroberfläche:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>Theme:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>Spieleliste</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>Add-On Spalte anzeigen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>Icongröße:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>Zeile 1 Text:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>Zeile 2 Text:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation>Screenshots</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation>Frage nach, wo Screenshots gespeichert werden sollen (Nur Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation>Screenshotpfad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation>Screenshotpfad auswählen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>Englisch</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>yuzu Web Service</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>Mit dem Bereitstellen deines Benutzernamens und Tokens erlaubst du yuzu, zusätzliche Nutzungsdaten zu sammeln. Diese könnten auch Informationen beinhalten, die dich identifizieren könnten.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>Überprüfen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>Registrieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>Token: </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>Nutzername: </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>Was ist mein Token?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>Telemetrie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>Teile anonyme Nutzungsdaten mit dem yuzu-Team</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>Mehr erfahren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>Telemetrie-ID:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>Neu generieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Discord-Präsenz</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Zeig dein momentanes Spiel in deinem Discord-Status</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Mehr erfahren&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Registrieren&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Was ist mein Token?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>Telemetrie-ID: 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>Nicht spezifiziert</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>Token nicht verifiziert</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>Token wurde nicht verfiziert. Die Änderungen an deinem Token wurden nicht gespeichert.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>Verifizieren...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>Verifizierung fehlgeschlagen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>Verifizierung fehlgeschlagen. Prüfe ob dein Nutzername und Token richtig eingegeben wurden und ob deine Internetverbindung korrekt funktioniert.</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonyme Daten werden gesammelt,&lt;/a&gt; um yuzu zu verbessern.&lt;br/&gt;&lt;br/&gt;Möchstest du deine Nutzungsdaten mit uns teilen?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>Telemetrie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>Textprüfung fehlgeschlagen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation>Lade Web-Applet...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation>Web-Applet verlassen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>Verlassen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation>Um das Web-Applet zu verlassen, verwende die im Spiel enthaltenen Steuerelemente, wähle die die Option &apos;Web-Applet beenden&apos; in der Menüleiste oder drücke die &apos;Enter&apos;-Taste.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation>Web-Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>Diese Version von yuzu wurde ohne QtWebEngine-Unterstützung kompiliert, was bedeutet, dass yuzu das angeforderte Spielhandbuch oder die Webseite nicht richtig anzeigen kann.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation>Wie viele Shader im Moment kompiliert werden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>Derzeitige Emulations-Geschwindigkeit. Werte höher oder niedriger als 100% zeigen, dass die Emulation scheller oder langsamer läuft als auf einer Switch.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>Wie viele Bilder pro Sekunde angezeigt werden variiert von Spiel zu Spiel und von Szene zu Szene. </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Zeit, die gebraucht wurde, um einen Switch-Frame zu emulieren, ohne Framelimit oder V-Sync. Für eine Emulation bei voller Geschwindigkeit sollte dieser Wert bei höchstens 16.67ms liegen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation>DOCK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation>ASYNC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation>MEHRKERN</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation>VULKAN</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation>OPENGL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>Zuletzt geladene Dateien leeren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>Warnung veraltetes Spielformat</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>Du nutzt eine entpackte ROM-Ordnerstruktur für dieses Spiel, welches ein veraltetes Format ist und von anderen Formaten wie NCA, NAX, XCI oder NSP überholt wurde. Entpackte ROM-Ordner unterstützen keine Icons, Metadaten oder Updates.&lt;br&gt;&lt;br&gt;&lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;Unser Wiki&lt;/a&gt; enthält eine Erklärung der verschiedenen Formate, die yuzu unterstützt. Diese Nachricht wird nicht noch einmal angezeigt.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>ROM konnte nicht geladen werden!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>ROM-Format wird nicht unterstützt.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>Beim Initialisieren des Video-Kerns ist ein Fehler aufgetreten.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>Beim Laden des Video-Kerns trat ein Fehler auf. Bitte prüfe die Log-Dateien auf mögliche Fehlermeldungen. Weitere Informationen: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Wie kann ich eine Log-Datei hochladen?&lt;/a&gt;. Stelle sicher, dass die aktuellsten Grafiktreiber für deine Grafikkarte installiert sind.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation>Fehler beim Laden des ROMs!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>Ein unbekannter Fehler ist aufgetreten. Bitte prüfe die Log-Dateien auf mögliche Fehlermeldungen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>Start</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>Speicherdaten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Mod-Daten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>Konnte Verzeichnis %1 nicht öffnen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>Verzeichnis existiert nicht!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>Fehler beim Öffnen des transferierbaren Shader-Caches</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>Es existiert kein Shader-Cache für diesen Titel.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation>Inhalte</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation>Update</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation>DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation>Eintrag entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation>Installiertes Spiel %1 entfernen?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation>Erfolgreich entfernt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation>Das Spiel wurde entfernt.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation>Fehler beim Entfernen von %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation>Das Spiel ist nicht im NAND installiert und kann somit nicht entfernt werden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation>Das Update wurde entfernt.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation>Es ist kein Update für diesen Titel installiert.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation>Es sind keine DLC für diesen Titel installiert.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation>%1 DLC entfernt. </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation>Transferierbaren Shader-Cache entfernen?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation>Spiel-Einstellungen entfernen?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation>Datei entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation>Fehler beim Entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation>Der transferierbare Shader-Cache wurde entfernt.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation>Konnte den transferierbaren Shader-Cache nicht entfernen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation>Fehler beim Entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation>Es existieren keine Spiel-Einstellungen für dieses Spiel.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation>Die Spiel-Einstellungen wurden entfernt.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation>Die Spiel-Einstellungen konnten nicht entfernt werden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>RomFS-Extraktion fehlgeschlagen!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>Das RomFS konnte wegen eines Fehlers oder Abbruchs nicht kopiert werden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>Komplett</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation>Nur Ordnerstruktur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>RomFS Extraktions-Modus auswählen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>Bitte wähle, wie das RomFS gespeichert werden soll.&lt;br&gt;&quot;Full&quot; wird alle Dateien des Spiels extrahieren, während &lt;br&gt;&quot;Skeleton&quot; nur die Ordnerstruktur erstellt.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>RomFS wird extrahiert...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>RomFS wurde extrahiert!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>Der Vorgang wurde erfolgreich abgeschlossen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>Fehler beim Öffnen von %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>Verzeichnis auswählen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>Einstellungen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>Spiel-Einstellungen konnten nicht geladen werden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Switch-Programme (%1);;Alle Dateien (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>Datei laden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>Öffne das extrahierte ROM-Verzeichnis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>Ungültiges Verzeichnis ausgewählt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>Das Verzeichnis, das du ausgewählt hast, enthält keine &apos;main&apos;-Datei.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation>Installierbares Switch-Programm (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge Image (*.xci)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation>Dateien installieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>Datei &quot;%1&quot; wird installiert...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation>NAND-Installation</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>Systemanwendung</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>Systemarchiv</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>Systemanwendungsupdate</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>Firmware-Paket (Typ A)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>Firmware-Paket (Typ B)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>Spiel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>Spiel-Update</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>Spiel-DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>Delta-Titel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>Wähle den NCA-Installationstyp aus...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>Bitte wähle, als was diese NCA installiert werden soll:
+(In den meisten Fällen sollte die Standardeinstellung &apos;Spiel&apos; ausreichen.)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>Installation fehlgeschlagen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>Der Titel-Typ, den du für diese NCA ausgewählt hast, ist ungültig.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>Datei nicht gefunden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>Datei &quot;%1&quot; nicht gefunden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>Fortsetzen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>Fehleranzeige</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>Fehlender yuzu-Account</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>Um einen Kompatibilitätsbericht abzuschicken, musst du einen yuzu-Account mit yuzu verbinden.&lt;br&gt;&lt;br/&gt;Um einen yuzu-Account zu verbinden, prüfe die Einstellungen unter Emulation &amp;gt; Konfiguration &amp;gt; Web.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation>Fehler beim Öffnen der URL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation>URL &quot;%1&quot; kann nicht geöffnet werden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>Amiibo-Datei (%1);; Alle Dateien (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>Amiibo laden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>Fehler beim Öffnen der Amiibo Datei</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>Die Amiibo Datei &quot;%1&quot; konnte nicht zum Lesen geöffnet werden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>Fehler beim Lesen der Amiibo-Daten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>Amiibo-Daten können nicht vollständig gelesen werden. Es wurde erwartet, dass %1 Bytes gelesen werden, es konnten aber nur %2 Bytes gelesen werden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>Fehler beim Laden der Amiibo-Daten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>Amiibo-Daten konnten nicht geladen werden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>Screenshot aufnehmen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG Bild (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>Geschwindigkeit: %1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>Geschwindigkeit: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>Spiel: %1 FPS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>Frame: %1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>Das Spiel, dass du versuchst zu spielen, benötigt bestimmte Dateien von deiner Switch-Konsole.&lt;br/&gt;&lt;br/&gt;Um Informationen darüber zu erhalten, wie du diese Dateien von deiner Switch extrahieren kannst, prüfe bitte die folgenden Wiki-Seiten: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;System-Archive und Shared Fonts von einer Switch-Konsole extrahieren&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Willst du zur Spiele-Liste zurückkehren und die Emulation beenden? Das Fortsetzen der Emulation könnte zu Spielfehlern, Abstürzen, beschädigten Speicherdaten und anderen Fehlern führen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>yuzu konnte ein Switch Systemarchiv nicht finden. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>yuzu konnte ein Switch Systemarchiv nicht finden: %1. %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>Systemarchiv nicht gefunden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>Systemarchiv fehlt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>yuzu konnte die Switch Shared Fonts nicht finden. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>Shared Fonts nicht gefunden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>Shared Font fehlt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>Schwerwiegender Fehler</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>Ein schwerwiegender Fehler ist aufgetreten, bitte prüfe die Log-Dateien auf mögliche Fehlermeldungen. Weitere Informationen: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Wie kann ich eine Log-Datei hochladen&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Willst du zur Spiele-Liste zurückkehren und die Emulation beenden? Das Fortsetzen der Emulation könnte zu Spielfehlern, Abstürzen, beschädigten Speicherdaten und anderen Fehlern führen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>Fataler Fehler aufgetreten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>Schlüsselableitung bestätigen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>Du bist im Begriff, alle Schlüssel neu abzuleiten. Falls du nicht weißt, was das heißt oder was du hier tust, könnte dieser Prozess möglicherweise destruktiv sein. Bitte stelle sicher, dass du wirklich fortfahren willst und optional Sicherungen deiner Daten machst.
+
+Dieser Prozess wird die generierten Schlüsseldateien löschen und die Schlüsselableitung neu starten.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation>Fuses fehlen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation> - BOOT0 fehlt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation> - BCPKG2-1-Normal-Main fehlt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation> - PRODINFO fehlt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation>Derivationskomponenten fehlen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation>Einige Komponenten, die yuzu benötigt, um Schlüssel zu generieren, wurden nicht gefunden. &lt;br&gt;Bitte folge &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;dem yuzu Schnellstart-Guide&lt;/a&gt; um alle deine Schlüssel und Spiele zu übertragen.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>Schlüssel werden abgeleitet...
+Dies könnte, je nach Leistung deines Systems, bis zu einer Minute dauern.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>Schlüsselableitung</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>RomFS wählen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>Wähle, welches RomFS du speichern möchtest.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>Bist du sicher, dass du yuzu beenden willst?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>Bist du sicher, dass du die Emulation stoppen willst? Jeder nicht gespeicherte Fortschritt geht verloren.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>Die derzeit laufende Anwendung hat yuzu aufgefordert, sich nicht zu beenden.
+
+Möchtest du dies umgehen und sie trotzdem beenden?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation>OpenGL nicht verfügbar!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation>yuzu wurde nicht mit OpenGL-Unterstützung kompiliert.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation>Vulkan nicht verfügbar!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation>yuzu wurde nicht mit Vulkan-Unterstützung kompiliert.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation>Fehler beim Initialisieren von OpenGL 4.3!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation>Deine Grafikkarte unterstützt kein OpenGL 4.3, oder du hast nicht den neusten Treiber installiert.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation>Fehler beim Initialisieren von OpenGL!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation>Deine GPU unterstützt anscheinend nicht eine oder mehrere von yuzu benötigte OpenGL-Erweiterungen. Bitte stelle sicher, dass du den neusten Grafiktreiber für deine GPU installiert hast.&lt;br&gt;&lt;br&gt;Nicht unterstützte Erweiterungen:&lt;br&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>Name</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>Kompatibilität</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>Add-ons</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>Dateityp</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>Größe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>Spielstand-Verzeichnis öffnen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Mod-Verzeichnis öffnen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>Transferierbaren Shader-Cache öffnen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation>Entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation>Installiertes Update entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation>Alle installierten DLCs entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation>Shader-Cache entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation>Spiel-Einstellungen entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation>Alle installierten Inhalte entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>RomFS speichern</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>Title-ID in die Zwischenablage kopieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>GameDB-Eintrag öffnen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>Eigenschaften</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>Unterordner scannen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>Spieleverzeichnis entfernen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation>▲ Nach Oben</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation>▼ Nach Unten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>Verzeichnis öffnen</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>Perfekt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>Das Spiel funktioniert fehlerfrei, ohne Audio- oder Grafikfehler, und sämtliche getestete Funktionalität funktioniert wie vorhergesehen ohne Workarounds.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>Gut</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>Das Spiel funktioniert mit kleineren Audio- oder Grafikfehlern und lässt sich bis zum Ende durchspielen.
+Eventuell sind einige Workarounds notwendig.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>Okay</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>Das Spiel funktioniert mit größern Audio- oder Grafikfehlern,
+lässt sich aber mit Workarounds bis zum Ende durchspielen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>Schlecht</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>Spiel funktioniert zwar, aber nur mit starken Audio- oder Grafikfehlern. Manche Bereiche des Spiels können selbst mit Workarounds nicht abgeschlossen werden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menü</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>Das Spiel ist wegen schwerwiegenden Audio- oder Grafikfehlern unspielbar. Das Spiel lässt sich lediglich starten.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Startet nicht</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>Das Spiel stürzt beim Versuch zu starten ab.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>Nicht getestet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>Spiel wurde noch nicht getestet.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>Doppelklicke, um einen neuen Ordner zur Spieleliste hinzuzufügen.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>Filter:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>Wörter zum Filtern eingeben</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation>Bitte bestätige, dass du diese Dateien installieren willst.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation>Wenn du ein Update oder DLC installierst, wirst du die vorher installierten überschreiben.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation>Installieren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation>Dateien im NAND installieren</translation>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>Shader 387 / 1628 wird geladen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>Shader %v / %m wird geladen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>Geschätzte Zeit: 5m 4s</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>Lädt...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>Shader %1 / %2 wird geladen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>Starten...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>Geschätzte Zeit: %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>&amp;Datei</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>Letzte Dateien</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>&amp;Emulation</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>&amp;Anzeige</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>Debugging</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>Werkzeuge</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>&amp;Hilfe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation>Dateien im NAND installieren...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>Datei laden...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>Verzeichnis laden...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>S&amp;chließen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>&amp;Start</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>&amp;Pause</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>&amp;Stop</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>Schlüssel neu initialisieren...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>Über yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>Einzelfenster-Modus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>Einstellungen...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>Dock-Widget-Header anzeigen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>Filterleiste anzeigen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>Statusleiste anzeigen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation>Fenstergröße zurücksetzen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>Vollbild</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>Neustart</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>Amiibo laden...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>Kompatibilität berichten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation>Mods-Seite öffnen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation>Schnellstart-Anleitung öffnen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation>FAQ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>yuzu-Verzeichnis öffnen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>Screenshot aufnehmen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation>Spiel-Einstellungen ändern...</translation>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>MicroProfile</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>Installierte SD-Titel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>Installierte NAND-Titel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>Systemtitel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>Neues Spieleverzeichnis hinzufügen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Strg</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[nicht gesetzt]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>Hat %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>Achse %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>Taste %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[unbekannt]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation>Klick 0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation>Klick 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation>Klick 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation>Klick 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation>Klick 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation>GC Achse %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation>GC Knopf %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[unbenutzt]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>Achse %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation>GC Achse %1</translation>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>Ein Fehler ist aufgetreten.
+Bitte versuche es noch einmal oder kontaktiere den Entwickler der Software.
+
+Fehlercode: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>Ein Fehler ist in %1 bei %2 aufgetreten.
+Bitte versuche es noch einmal oder kontaktiere den Entwickler der Software.
+
+Fehlercode: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>Ein Fehler ist aufgetreten.
+Fehlercode: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>Wähle einen Benutzer aus:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>Nutzer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>Profilauswahl</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>Text eingeben:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>Software-Tastatur</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>Hotkey eingeben</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>Stack aufrufen</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>Warten auf Mutex 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>has waiters: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>owner handle: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>Warten auf alle Objekte</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>Warten auf eines der folgenden Objekte</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation>[%1]%2 %3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation>von keinem Thread pausiert</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>läuft</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>bereit</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>pausiert</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>warten auf HLE Rückgabe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>schläft</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>Warten auf IPC-Antwort</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>Warten auf Objekte</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>Warten auf Mutex</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>wartet auf condition variable</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>Warten auf den Adressarbiter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>ruhend</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>tot</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation>PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>ideal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>Kern %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>Unbekannter Prozessor %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>Prozessor = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>ideal core = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>Affinitätsmaske = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>Thread-ID = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>Priorität = %1(aktuell) / %2(normal)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>Letzte laufende Ticks = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>nicht auf Mutex warten</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>gewartet von Thread</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>Wait Tree</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/es.ts b/dist/languages/es.ts
new file mode 100644
index 000000000..437817561
--- /dev/null
+++ b/dist/languages/es.ts
@@ -0,0 +1,4757 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="es" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>Acerca de yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu es un emulador experimental de código abierto de Nintendo Switch licenciado bajo GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;Este software no debe ser utilizado para jugar juegos que no hayas obtenido legalmente.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Sitio web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Código fuente&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contribuidor&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licencia&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; es una marca registrada de Nintendo. yuzu no esta afiliado con Nintendo de ninguna manera.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation>Comunicando con el servidor...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation>Toque la esquina superior izquierda&lt;br&gt;de su trackpad.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation>Ahora toque la esquina inferior derecha &lt;br&gt;de su trackpad.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation>¡Configuración completa!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>Informar de compatibilidad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>Informar de compatibilidad del juego</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;SI decides presentar una prueba a la &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Lista de Compatibilidad de yuzu&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, La siguiente información será obtenida y mostrada en el sitio web:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Informacion de Hardware (CPU / GPU / Sistema Operativo)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Qué versión de yuzu estas utilizando&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;La cuenta de yuzu conectada&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>Perfecto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;El juego funciona a la perfección sin ningún problema gráfico o de audio.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>Excelente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;El juego funciona con fallos gráficos o de audio menores y es jugable desde el principio hasta el final. Puede requerir de soluciones temporales.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>Bien</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;El juego funciona con importantes fallos gráficos o de audio, pero es jugable desde el principio hasta el final con soluciones temporales.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>Mal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;El juego funciona, pero tiene errores gráficos o de audio. Imposible progresar en ciertas áreas debido a errores incluso con soluciones temporales.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menú</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;No es posible jugar a este juego debido a importantes errores gráficos o de audio. Es imposible avanzar mas allá de la pantalla de inicio.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>No inicia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;El juego se bloquea al intentar iniciar.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independientemente de la velocidad o del rendimiento, ¿cómo definiría su experiencia con el juego de principio a fin en esta versión de yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>Gracias por su contribución.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>Enviando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>Error de comunicación.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>Ha ocurrido un error mientras se mandaba el caso de prueba</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>Siguiente</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>Motor de Salida:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>Este efecto de post-procesado ajusta la velocidad del audio para igualarla a la velocidad de emulación y así prevenir parones en el audio. No obstante, esto aumenta la latencia del audio.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>Activar extensión del audio.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>Dispositivo de Audio:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation>Usar el volumen global</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation>Ajustar volumen:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>Volumen:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation>General</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation>Precisión: </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation>Preciso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation>Impreciso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation>Activar el Modo de Depuración</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation>Recomendamos ajustar la precisión a &quot;Preciso&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation>Ajustes del Modo Impreciso de Optimización de la CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation>Estos ajustes reducen la precisión para mejorar el rendimiento.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation>Unfuse FMA (mejorar el rendimiendo en las CPU sin FMA)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esta opción mejora el rendimiento al reducir la precisión de las instrucciónes fused-multiply-add en las CPU sin soporte nativo de FMA.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation>Más rápido FRSQRTE y FRECPE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esta opción mejora el rendimiento de algunas funciones aproximadas de punto flotante al utilizar aproximaciones nativas menos precisas.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>Los ajustes de la CPU sólo se encuentran disponibles cuando no se está ejecutando ningún juego.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation>Ajustando la CPU al Modo de Depuración</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation>El Modo de Depuración de la CPU sólo está destinado al uso de los desarrolladores. ¿Estás seguro de que quieres activar esto?</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation>Cambiar las optimizaciones de la CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;
+ &lt;b&gt;Sólo para la depuración.&lt;/b&gt;
+ &lt;br&gt;
+ Si no está seguro de lo que hacen estas opciónes, manténgalos todos activados.
+ &lt;br&gt;
+ Estos ajustes sólo toman efecto cuando la precisión de la CPU esta en &quot;Modo de Depuración&quot;.
+ &lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation>Activar las tablas de páginas inline.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Esta optimización acelera los accesos a la memoria del programa del invitado.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Activando las inlines accede a PageTable::pointers en código emitido.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Desactivando esto obliga a que todos los accesos a la memoria pasen por las funciones Memory::Read/Memory::Write.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation>Activar el enlace de bloques</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esta optimización evita las búsquedas del despachador permitiendo que los bloques básicos emitidos salten directamente a otros bloques básicos si el PC de destino es estático.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation>Activar el buffer de la pila de retorno</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esta optimización evita las búsquedas de los despachadores al rastrear las direcciones potenciales de retorno de las instrucciones de BL. Esto se aproxima a lo que sucede con un buffer de la pila de retorno en una CPU real.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation>Activar el despachador rápido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Habilitar un sistema de despacho de dos niveles. Un despachador más rápido escrito en ensamblado tiene un pequeño caché MRU de destinos de salto se utiliza primero. Si eso falla, el despacho vuelve al despacho más lento de C++.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation>Activar la eliminación del contexto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esto habilita una optimización de IR que reduce los accesos innecesarios a la estructura del contexto de la CPU.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation>Activar la propagación constante</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esto habilita optimizaciones de IR que implican una propagación constante.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation>Activar optimizaciones misceláneas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esto habilita optimizaciónes misceláneas IR.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation>Activar la reducción del control de desalineación</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Cuando está activada, una desalineación sólo se activa cuando un acceso cruza el límite de una página.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Cuando está desactivado, se desencadena una desalineación en todos los accesos desalineados.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>Los ajustes de la CPU sólo se encuentran disponibles cuando no se está ejecutando ningún juego.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>Activar GDB Stub</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>Puerto:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>Registro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>Filtro de Registro Global</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>Mostrar Consola del Registro (Sólo en Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>Abrir Ubicación del Registro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>Homebrew</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>Cadena de Argumentos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation>Gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation>Cuando está marcado, la API de gráficos entra en un modo de depuración más lento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation>Activar la Depuración de Gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation>Cuando está marcado, se desactiva el compilador de macro Just In Time. Activando esto hace que los juegos se ejecuten más lento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation>Desactivar Macro JIT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation>Volcar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>Habilitar Servicios de Reporte Detallados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>Estas opciones se restablecerán automáticamente cuando yuzu se cierre.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>Avanzado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation>Modo Quiosco (Quest)</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation>Configurar el Control de Depuración</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation>Eliminar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation>Valores Predeterminados</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>Configuración de yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>General</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>IU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>Lista de Juegos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>Perfiles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>Sistema de Archivos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>Controles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>Teclas de Acceso Rápido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation>CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>Depuración</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>Gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation>Avanzado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation>GráficosAvanzados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Web</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>Servicios</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>Directorios de Almacenamiento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>Tarjeta SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>Cartucho de Juegos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>Ruta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>Insertado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>Juego Actual</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>Administrador de Parches</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>Volcar NSOs Descomprimidos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>Volcar Partición ExeFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation>Carpeta raíz de carga de Mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation>Carpeta raíz de Volcado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>Cargando Caché</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>Directorio de Caché</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation>Metadatos de Lista de Juegos en Caché</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>Reiniciar Caché de Metadatos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>Seleccione el directorio de NAND Emulado...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>Seleccione el directorio de SD Emulado...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation>Seleccione la ruta del Cartucho...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>Seleccione Directorio para Volcar...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation>Seleccione el directorio de carga de Mod...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>Seleccione el Directorio para Caché...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>El caché de metadatos ya está vacío.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>La operación se completó con éxito.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>El caché de metadatos no se pudo eliminar. Puede que se encuentre en uso actualmente o ya haya sido eliminado.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>General</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>Limitar el Porcentaje de Velocidad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation>Emulación de CPU multinúcleo </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>Confirmar salida mientras se ejecuta la emulación</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation>Mostrar usuario actual al abrir el juego</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>Pausar emulación cuando la ventana esté en segundo plano</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation>Ocultar el cursor del ratón cuando no está activo.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation>Ajustes de la API</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation>API:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation>Dispositivo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation>Ajustes de los Gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>Usar caché de shaders en disco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>Usar emulación asíncrona de GPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation>Relación de Aspecto:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation>Valor Predeterminado (16:9)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation>Forzar a 4:3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation>Forzar a 21:9</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation>Estirar a la Ventana</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation>Usar el color de fondo global</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation>Establecer el color de fondo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>Color de Fondo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation>Dispositivo Gráfico OpenGL:</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation>Ajustes de los Gráficos Avanzados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation>Nivel de Precisión: </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation>VSync evita que la pantalla se desgarre, pero algunas tarjetas gráficas tienen un rendimiento menor con VSync activado. Mantenlo activado si no notas una diferencia de rendimiento.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation>Usar VSync (sólo en OpenGL)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation>Activando esto reduce el tartamudeo causado por la compilación de shaders. Activa shaders de ensamblaje OpenGL en los dispositivos de Nvidia soportados (se requiere NV_gpu_program5). Esta función es experimental.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation>Usar shaders de ensamblaje (experimental, sólo Nvidia OpenGL)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation>Activa la compilación de shaders en modo asíncrono, cuál podría reducir el tartamudeo de los shaders. Esta función es experimental.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation>Usar la construcción de shaders asíncronos (experimental)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation>Usar Tiempo Rápido en la GPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation>Filtrado Anisotrópico:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation>Valor Predeterminado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation>2x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation>4x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation>8x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation>16x</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>Configuración de Teclas de Acceso Rápido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation>Haz doble-clic para cambiar la asignación de teclas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation>Eliminar Todo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation>Restaurar Valores Predeterminados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>Acción</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>Tecla de Acceso Rápido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>Contexto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>Secuencia de Teclas en Conflicto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation>La secuencia de teclas introducida ya ha sido asignada a: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation>Restaurar Valor Predeterminado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation>Eliminar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation>La secuencia de teclas predeterminada ya ha sido asignada a: %1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation>ConfigurarEntrada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>Jugador 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>Jugador 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>Jugador 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>Jugador 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>Jugador 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>Jugador 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>Jugador 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>Jugador 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>Avanzado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation>Modo de la Consola</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation>Estacionado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation>Portátil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation>Vibración</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation>Movimiento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>Configurar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation>Controladores</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation>1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation>2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation>3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation>4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation>5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation>6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation>7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation>8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation>Conectado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation>Valores Predeterminados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation>Eliminar</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Configurar Controles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation>Colores de Joycon</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation>Jugador 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation>Lado L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation>Botón L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation>Lado R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation>Botón R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation>Jugador 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation>Jugador 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation>Jugador 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation>Jugador 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation>Jugador 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation>Jugador 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation>Jugador 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation>Otro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation>Teclado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation>Avanzado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation>Pantalla Táctil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation>Ratón</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation>Movimiento / Táctil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation>Configurar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation>Control de Depuración</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Configurar Controles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation>Conectar el Controlador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation>Pro Controller</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation>Doble Joycons</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation>Joycon Izquierdo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation>Joycon Derecho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation>Portátil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation>Dispositivo de Entrada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation>Cualquier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation>Teclado/Ratón</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation>Perfil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation>Guardar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation>Crear</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation>Borrar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>Palanca Izquierda</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation>Arriba</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation>Izquierda</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation>Derecha</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation>Abajo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation>Presionado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation>Modificador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation>Rango</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation>Zona Muerta: 0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation>Rango del Modificador: 0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation>Cruceta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation>L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation>ZL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation>Menos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation>Captura</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation>Más</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation>Inicio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation>R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation>ZR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation>SL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation>SR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>Botones Frontales</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation>B</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>Palanca Derecha</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation>Zona Muerta: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation>Rango del Modificador: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation>[esperando]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation>Configurar: Movimiento / Táctil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation>Movimiento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation>Proveedor de Movimiento:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation>Sensibilidad:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation>Táctil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation>Proveedor de Táctil:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation>Calibración:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation>(100, 50) - (1800, 850)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation>Configurar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation>Usar el mapeo de botones:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation>Configuración CemuhookUDP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation>Puede utilizar cualquier fuente de entrada UDP compatible con Cemuhook para proporcionar una entrada de movimiento y de tacto.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation>Servidor:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation>Puerto:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation>Pad:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation>Pad 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation>Pad 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation>Pad 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation>Pad 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation>Más Información</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation>Probar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation>Ratón (Clic Derecho)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation>CemuhookUDP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation>Ventana del Emulador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Más Información&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation>Probando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation>Configurando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation>Prueba Existosa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation>Se recibió con éxito los datos del servidor.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation>Prueba fallida</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation>No pudo recibir datos válidos del servidor.&lt;br&gt;Por favor, verifique que el servidor esté configurado correctamente y que la dirección y el puerto sean correctos.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation>Citra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation>La prueba de UDP o la configuración de la calibración está en curso.&lt;br&gt;Por favor, espere a que termine el proceso.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>Configurar el Ratón</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>Botones del Ratón</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>Adelante:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>Atrás:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>Izquierda:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>Medio:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>Derecha:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>Borrar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation>Valores Predeterminados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[no establecido]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>Restaurar Valor Predeterminado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[pulsa un botón]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation>Información</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation>ID del Título</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation>Nombre del Archivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation>Versión</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation>Tamaño</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation>Desarrollador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation>Complementos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation>General</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation>Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation>Gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation>Gráficos Avanzados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation>Propiedades</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation>Usar la configuración global (%1)</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation>Nombre del Parche</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation>Versión</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>Administrador de Perfiles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>Usuario Actual</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>Nombre de Usuario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>Seleccionar Imagen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>Añadir</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>Renombrar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>Eliminar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>El sistema de perfiles solo se encuentra disponible cuando no se está ejecutando ningún juego.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>Introduzca el Nombre de Usuario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>Usuarios</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>Introduzca un nombre para el nuevo usuario:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>Introduzca un nuevo nombre de usuario:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation> Confirmar Eliminanación</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>Estás a punto de eliminar al usuario &quot;%1&quot; ¿Estás seguro?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>Seleccione una Imagen de Usuario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>Imagenes JPEG (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>Error al eliminar la imagen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>Ocurrió un error al intentar sobrescribir la imagen anterior en: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>Error eliminando archivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>No se pudo eliminar el archivo existente: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>Error al crear el directorio de imagen del usuario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>No se puede crear el directorio % 1 para almacenar imágenes de usuario.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>Error al copiar la imagen del usuario.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>No se puede copiar la imagen de %1 a %2</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>BCAT es la forma con la que Nintendo envía datos de sus juegos para así interconectar su comunidad y desbloquear contenido adicional.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation>Backend de BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;Saber más sobre BCAT, Boxcat, y sus eventos actuales.&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation>El servicio boxcat se encuentra fuera de linea o usted no está conectado a internet.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>Hubo un error al intentar procesar los datos del evento de boxcat. Por favor, contacte con los desarrolladores de yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>La versión de yuzu que está utilizando actualmente es demasiado nueva o demasiado antigua para este servidor. Intente actualizar a la última versión oficial de yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation>No hay ningún evento de boxcat en estos momentos.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation>Eventos de Boxcat Actuales</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation>Yuzu está verificando el estado actual de boxcat...</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>Ajustes del sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation>Región:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation>Auto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation>Valor Predeterminado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation>CET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation>CST6CDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation>Cuba</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation>EET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation>Egipto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation>Eire</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation>EST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation>EST5EDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation>GB-Eire</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation>GMT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation>GMT+0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation>GMT-0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation>GMT0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation>Greenwich</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation>Hongkong</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation>HST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation>Islandia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation>Iran</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation>Israel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation>Jamaica</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation>Japón</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation>Kwajalein</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation>Libia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation>MET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation>MST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation>MST7MDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation>Navajo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation>NZ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation>NZ-CHAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation>Polonia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation>Portugal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation>PRC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation>PST8PDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation>ROC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation>ROK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation>Singapur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation>Turquía</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation>UCT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation>Universal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation>UTC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation>W-SU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation>WET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation>Zulu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation>EEUU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation>Europa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation>Australia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation>China</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation>Corea</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation>Taiwan</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation>Zona Horaria</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>Nota: esto puede ser ignorado cuando la opción de región está en &quot;autoseleccionar&quot;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>Japonés (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>Inglés (english)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>Francés (français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>Alemán (Deutsch)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>Italiano (italiano)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>Español</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>Chino</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>Coreano (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>Holandés (Nederlands)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>Portugués (português)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>Ruso (Русский)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>Taiwanés</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>Inglés Británico</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>Francés Canadiense</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>Español latinoamericano</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>Chino Simplificado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>Chino Tradicional (正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>RTC Personalizado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>Idioma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>Semilla de GNA</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>Mono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>Estereo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>Envolvente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>ID de la Consola:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>Modo de salida del sonido:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation>d MMM aaaa h:mm:ss AP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>Regenerar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>Los ajustes del sistema solo se encuentran disponibles cuando no se está ejecutando ningún juego.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>Esto reemplazará tu Switch virtual con una nueva. Tu Switch virtual actual no será recuperable. Esto podría causar efectos inesperados en determinados juegos. Si usas un archivo de configuración obsoleto, esto podría fallar. ¿Continuar?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>Advertencia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>ID de Consola: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation>Configurar las Asignaciones de la Pantalla Táctil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation>Asignaciones:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation>Crear</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation>Borrar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation>Renombrar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation>Haz clic en el área inferior para añadir un punto, y luego presiona un botón para unir.
+Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas de la tabla para editar los valores.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation>Borrar Punto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation>Botón</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation>Crear Perfíl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation>Introduzca un nombre para el nuevo perfíl:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation>Borrar Perfíl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation>Borrar Perfíl %1?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation>Renombrar Perfíl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation>Nuevo nombre:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation>[presionar tecla]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>Configurar pantalla táctil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>Advertencia: Los ajustes en esta página afectarán al funcionamiento de la pantalla táctil emulada de yuzu. Cambiarlas podría resultar en un comportamiento inapropiado, como que la pantalla táctil deje de funcionar parcialmente. Se recomienda usar esta pestaña sólo si sabes lo que estás haciendo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>Parámetros Táctil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>Diámetro Táctil Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>Dedo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>Diámetro Táctil X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>Ángulo Rotacional</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>Recuperar ajustes predeterminados</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>General</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>Nota: Cambiar el idioma guardará tu configuración actual.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>Lenguage de la Interfaz:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>Tema:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>Lista de Juegos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>Mostrar Columna de Accesorios</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>Tamaño de los Iconos:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>Texto de la Fila 1:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>Texto de la Fila 2:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation>Capturas de Pantalla</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation>Pregunte Dónde Guardar las Capturas de Pantalla (sólo para Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation>Trayectoria de las Capturas de Pantalla:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation>Selecciona la Trayectoria de las Capturas de Pantalla:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>Inglés</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>Servicio Web de yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>Al proporcionar su nombre de usuario y token, das tu consentimiento a que yuzu recopile datos de uso adicionales, que pueden incluir información de identificación del usuario.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>Verificar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>Registrarse</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>Token: </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>Nombre de usuario:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>¿Cuál es mi token?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>Telemetría</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>Compartir datos de uso anónimos con el equipo de yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>Saber más</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>ID de Telemetría:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>Regenerar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Presencia de Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Mostrar el juego actual en tu estado de Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Saber más&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Regístrate&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;¿Cuál es mi token?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>ID de Telemetría: 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>Sin especificar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>No se pudo verificar el token</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>El token pudo ser verificado. El cambio realizado a su token no se ha guardado.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>Verificando...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>Verificación fallida</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>Verificación fallida. Compruebe que ha ingresado el token correctamente, y que esté funcionando su conexión a internet.</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Se recogen datos anónimos&lt;/a&gt; para ayudar a mejorar yuzu. &lt;br/&gt;&lt;br/&gt;¿Quieres compartir tus datos de uso con nosotros?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>Telemetría </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>Comprobación de Texto Fallida</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation>Cargando Web Applet...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation>Cerrar Web Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>Salir</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation>Para salir de la aplicación web, use los controles provistos por el juego y seleccione la opción &quot;Cerrar Web Applet&quot; en la barra del menú, o presione la tecla &quot;Enter&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation>Web Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>Esta versión de yuzu fue creada sin soporte para QtWebEngine, lo que significa que yuzu no puede mostrar correctamente el manual del juego o la página solicitada.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation>La cantidad de shaders que se están construyendo actualmente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>La velocidad de emulación actual. Los valores superiores o inferiores al 100% indican que la emulación se está ejecutando más rápido o más lento que en una Switch.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>Cuántos fotogramas por segundo está mostrando el juego actualmente. Esto variará de un juego a otro y de una escena a otra.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Tiempo que lleva emular un fotograma de la Switch, sin tener en cuenta la limitación de fotogramas o sincronización vertical. Para una emulación óptima, este valor debería ser como máximo de 16.67 ms.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation>ESTACIONADO</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation>ASINC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation>MULTINÚCLEO</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation>VULKAN</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation>OPENGL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>Limpiar Archivos Recientes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>Advertencia Formato de Juego Obsoleto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>Está utilizando el formato de directorio de ROM deconstruido para este juego, que es un formato desactualizado que ha sido reemplazado por otros, como NCA, NAX, XCI o NSP. Los directorios de ROM deconstruidos carecen de íconos, metadatos y soporte de actualización.&lt;br&gt;&lt;br&gt;Para obtener una explicación de los diversos formatos de Switch que soporta yuzu,&lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;echa un vistazo a nuestra wiki&lt;/a&gt;. Este mensaje no se volverá a mostrar.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>¡Error al cargar la ROM!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>El formato de la ROM no es compatible.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>Se produjo un error al inicializar el núcleo de video.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>yuzu ha encontrado un error al ejecutar el núcleo de video, consulte el registro para obtener más detalles. Para obtener más información sobre cómo acceder al registro, consulte la siguiente página: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Cómo cargar el archivo de registro.&lt;/a&gt; Asegúrese de tener los últimos controladores de gráficos para su GPU.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation>¡Error al cargar la ROM!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>Error desconocido. Por favor, consulte el registro para ver más detalles.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>Iniciar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>Datos de Juegos Guardados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Datos de Mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>Error al abrir la carpeta %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>¡La carpeta no existe!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>Error al Abrir el Caché Transferible de Shaders</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>No existe un Caché de shaders para este título.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation>Contenidos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation>Actualización</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation>DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation>Eliminar el Título</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation>Eliminar el Juego Instalado %1?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation>Se Eliminó con Éxito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation>Se eliminó con éxito el juego de base instalado.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation>Error en la eliminación de %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation>El juego base no está instalado en el NAND y no se puede eliminar.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation>Se eliminó con éxito la actualización instalada.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation>No hay ninguna actualización instalada para este título.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation>No hay ningún DLC instalado para este título.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation>Se eliminó con éxito %1 DLC instalado(s).</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation>¿Desea eliminar el Caché Transferible de Shaders?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation>¿Desea Eliminar la Configuración Personalizada del Juego?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation>Eliminar Archivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation>Error al Eliminar el Caché Transferible de Shaders</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation>El Caché Transferible de Shaders fue eliminado con éxito.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation>No se ha podido eliminar el caché de shaders transferibles.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation>Error al Eliminar la Configuración Personalizada del Juego</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation>No existe una configuración personalizada para este título.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation>Se eliminó con éxito la configuración personalizada del juego.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation>No se ha podido eliminar la configuración personalizada del juego.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>¡La extracción de RomFS falló!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>Se produjo un error al copiar los archivos RomFS o el usuario canceló la operación.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>Completo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation>Base</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>Elegir modo para volcar el RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>Seleccione la forma en que desea volcar el RomFS. &lt;br&gt;Copiará todos los archivos en el nuevo directorio &lt;br&gt; mientras que el esqueleto solo creará la estructura del directorio.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>Extrayendo RomFS...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>¡La extracción RomFS tuvo éxito!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>La operación se completó con éxito.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>Error al intentar abrir %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>Seleccionar Directorio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>Propiedades</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>No se pudieron cargar las propiedades del juego.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Ejecutable de Switch (%1);;Todos los archivos (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>Cargar archivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>Abrir el directorio de la ROM extraída</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>Directorio no válido seleccionado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>El directorio que ha seleccionado no contiene ningún archivo &apos;main&apos;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation>Archivo de Switch Instalable (*.nca *.nsp *.xci);;Archivo de Contenidos Nintendo (*.nca);;Paquete de Envío Nintendo (*.nsp);;Imagen de Cartucho NX (*.xci)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation>Instalar Archivos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>Instalando el archivo &quot;%1&quot;...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation>Instalar Resultados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>Aplicación del sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>Archivo del Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>Actualización de la aplicación del sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>Paquete de Firmware (Tipo A)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>Paquete de Firmware (Tipo B)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>Juego</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>Actualización del juego</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>DLC del Juego</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>Titulo Delta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>Seleccione el tipo de instalación NCA...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>Seleccione el tipo de título en el que desea instalar este NCA como:
+(En la mayoría de los casos, el &apos;Juego&apos; predeterminado está bien).</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>Fallo en la instalación</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>El tipo de título que seleccionó para el NCA no es válido.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>Archivo no encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>Archivo &quot;%1&quot; no encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>Continuar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>Mostrar Error</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>Falta la cuenta de Yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>Para enviar un caso de prueba de compatibilidad de juegos, debe vincular su cuenta de yuzu.&lt;br&gt;&lt;br/&gt; Para vincular su cuenta yuzu, vaya a Emulación &amp; gt; Configuración &amp; gt; Web.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation>Error al abrir la URL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation>No se puede abrir la URL &quot;%1&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>Archivo Amiibo (%1);; Todos los archivos (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>Cargar amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>Error al abrir el archivo de datos de Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>No se puede abrir el archivo de Amiibo &quot;%1&quot; para leer.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>Error al leer el archivo de datos de Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>No se pueden leer completamente los datos de Amiibo. Se esperaban leer %1 bytes, pero solo se pudo leer %2 bytes.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>Error al cargar los datos de Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>No se pueden cargar los datos de Amiibo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>Captura de Pantalla</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>Imagen PNG (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>Velocidad: %1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>Velocidad: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>Juego: %1 FPS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>Fotogramas: %1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>El juego que estás intentando cargar requiere de archivos adicionales de su Switch antes de poder jugar. &lt;br/&gt;&lt;br/&gt;Para obtener más información sobre cómo obtener estos archivos, ve a la siguiente página de la wiki: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Volcar archivos del sistema y las fuentes compartidas desde una Consola Switch. &lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;¿Quieres volver a la lista de juegos? Continuar con la emulación puede provocar fallos, datos de guardado dañados u otros errores.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>yuzu no pudo localizar el archivo de sistema de la Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>yuzu no pudo localizar un archivo de sistema de la Switch: %1. %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>Archivo del Sistema No Encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>Falta Archivo del Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>yuzu no pudo encontrar las Fuentes Compartidas de la Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>Fuentes compartidas no encontradas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>Faltan las Fuentes Compartidas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>Error Fatal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>yuzu ha encontrado un error fatal, consulte el registro para obtener más detalles. Para obtener más información sobre cómo acceder al registro, consulte la siguiente página: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;¿Cómo cargar el archivo de registro?&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt; La emulación continua puede provocar fallos, datos de guardado dañados u otros errores.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>Error Fatal Encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>Confirma la Clave de Rederivación</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>Estás a punto de forzar todas tus claves.
+Si no sabes qué es esto,
+es una acción potencialmente destructiva.
+Por favor, asegúrese de que esto
+es lo que desea hacer si es necesario.
+
+ Esto eliminará los archivos de las claves generados automáticamente y volverá a ejecutar el módulo de derivación de claves.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation>Falta fuses</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation>- Falta BOOT0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation> - Falta BCPKG2-1-Normal-Main</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation> - Falta PRODINFO</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation>Faltan Componentes de Derivación</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation>Faltan componentes que pueden impedir que la derivación de la clave se complete. &lt;br&gt;Por favor siga &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;la guía de inicio rápido de yuzu&lt;/a&gt; para conseguir todas tus llaves y juegos.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>Derivando claves...
+Esto puede llevar unos minutos dependiendo
+del rendimiento de su sistema.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>Obtención de claves</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>Selecciona el destinatario para volcar el RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>Por favor, seleccione los RomFS que desea volcar.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>¿Estás seguro de que quieres cerrar yuzu?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>¿Estás seguro de que quieres detener la emulación? Cualquier progreso no guardado se perderá.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>La aplicación que se está ejecutando actualmente ha solicitado que yuzu no sea cerrado.
+
+¿Desea cerrarlo de todas formas?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation>OpenGL no está disponible!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation>yuzu no ha sido compilado con soporte de OpenGL.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation>Vulkan no está disponible!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation>yuzu no ha sido compilado con soporte de Vulkan.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation>¡Error al inicializar OpenGL 4.3!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation>Tu GPU no soporta OpenGL 4.3 o no tienes instalado el último controlador de la tarjeta gráfica.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation>¡Error al inicializar OpenGL!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation>Es posible que su GPU no soporta una o más extensiones OpenGL requeridas. Por favor, asegúrese de tener el último controlador de la tarjeta gráfica&lt;br&gt;&lt;br&gt;Extensiones no soportadas:&lt;br&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>Compatibilidad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>Complementos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>Tipo de Archivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>Tamaño</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>Abrir ubicación de los archivos de guardado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Abrir ubicación de Mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>Abrir Caché Transferible de Shaders</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation>Eliminar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation>Eliminar la Actualización Instalada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation>Eliminar todos los DLC instalados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation>Eliminar el Caché de Shaders</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation>Eliminar Configuración Personalizada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation>Eliminar Todos los Contenidos Instalados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>Volcar RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>Copiar ID de título al portapapeles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>Navegar a la entrada de BD del juego</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>Propiedades</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>Escanear subdirectorios</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>Eliminar Directorio de Juegos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation>▲ Mover Hacia Arriba</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation>▼ Mover Hacia Abajo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>Abrir Ubicación del Directorio</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>Perfecto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>El juego funciona a la perfección sin fallos de audio o gráficos, todas las funciones probadas funcionan según lo previsto
+sin ninguna solución necesaria.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>Excelente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>El juego funciona con fallos gráficos o de audio menores y se puede jugar de principio a fin. Puede requerir de
+soluciones temporales.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>Bien</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>El juego funciona con importantes fallos gráficos o de audio, pero el juego se puede jugar de principio a fin con
+soluciones temporales.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>Mal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>El juego funciona, pero con importantes fallos gráficos o de audio. Es imposible avanzar en zonas específicas
+incluso con soluciones temporales.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menú</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>No es posible jugar a este juego debido a importantes errores gráficos o de audio. Es imposible avanzar mas allá de la pantalla
+de inicio.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>No inicia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>El juego se bloquea al intentar iniciar.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>Sin probar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>El juego todavía no ha sido probado.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>Haga doble clic para agregar un nuevo directorio a la lista de juegos.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>Filtrar:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>Introduce patrón para filtrar</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation>Por favor, confirme que estos son los archivos que desea instalar.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation>Instalando una Actualización o DLC reemplazará la que está instalada anteriormente.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation>Instalar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation>Instalar archivos al NAND...</translation>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>Cargando Shaders 387 / 1628</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>Cargando Shaders %v de %m</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>Tiempo Estimado 5m 4s</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>Cargando...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>Cargando Shaders %1 / %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>Iniciando...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>Tiempo estimado %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>&amp;Archivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>Archivos recientes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>&amp;Emulación</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>&amp;Ver</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>Depuración</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>Herramientas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>&amp;Ayuda</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation>Instalar archivos al NAND...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>Cargar archivo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>Cargar carpeta...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>S&amp;alir</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>&amp;Iniciar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>&amp;Pausar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>&amp;Detener</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>Reiniciar claves...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>Acerca de yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>Modo Ventana Única</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>Configurar...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>Mostrar los Encabezados del Widget</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>Mostrar Barra de Filtro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>Mostrar Barra de Estado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation>Reiniciar el Tamaño de la Ventana</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>Pantalla completa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>Reiniciar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>Cargar Amiibo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>Informar de compatibilidad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation>Abrir la Página de Mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation>Abrir la Guía de Inicio Rápido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation>Preguntas Más Frecuentes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>Abrir la carpeta yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>Captura de Pantalla</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation>Configurar el Juego Actual...</translation>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>MicroPerfil</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>Títulos instalados en la SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>Títulos instalados en la NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>Títulos del Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>Agregar un Nuevo Directorio de Juegos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[no establecido]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>Rotación %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>Eje %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>Botón %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[desconocido]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation>Clic 0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation>Clic 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation>Clic 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation>Clic 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation>Clic 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation>Eje GC %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation>Botón GC %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[no usado]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>Eje %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation>Eje GC %1</translation>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>Ha ocurrido un error.
+Inténtelo nuevamente o contacte con el desarrollador del software.
+
+Código del error: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>Ha ocurrido un error en el %1 a las %2.
+Inténtelo nuevamente o contacte con el desarrollador del software.
+
+Código del error: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>Ha ocurrido un error.
+Códio del error: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>Seleccione un usuario:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>Usuarios</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>Selector de perfil</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>Introducir texto:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>Software del Teclado</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>Ingrese combinación de teclas de acceso rápido</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>Pila de Llamadas</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>esperando por mutex 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>tiene receptores: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>manejo del propietario: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>esperando todos los objetos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>esperando uno de los siguientes objetos</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation>[%1]%2 %3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation>esperado por ningún hilo</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>corriendo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>listo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>en pausa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>esperando para el retorno HLE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>dormido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>esperando para respuesta IPC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>esperando objetos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>esperando por mutex</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>esperando variable condicional</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>esperando al árbitro de dirección</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>inactivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>muerto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation>PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>ideal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>núcleo %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>Procesador desconocido %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>procesador = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>núcleo ideal = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>máscara de afinidad = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>id de hilo = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>prioridad = %1(presente) / %2(normal)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>Últimos ticks consecutivos = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>no esperando por mutex</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>esperado por hilo</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>Árbol de Espera</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/fr.ts b/dist/languages/fr.ts
new file mode 100644
index 000000000..83e678f93
--- /dev/null
+++ b/dist/languages/fr.ts
@@ -0,0 +1,4732 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="fr" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>À propos de yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu est un émulateur expérimental open-source pour la Nintendo Switch licencié sous GPLv2.0. &lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;Ce logiciel ne doit pas être utilisé pour jouer à des jeux que vous n&apos;avez pas obtenu légalement.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;
+&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Site Web&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Code Source&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributeurs&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licence&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; est une marque déposée de Nintendo. yuzu n&apos;est en aucun cas affilié à Nintendo.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation>Communications avec le serveur...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation>Touchez le coin supérieur&lt;br&gt;gauche de votre pavé tactile.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation>Touchez le coin supérieur gauche&lt;br&gt; de votre pavé tactile.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation>Configuration terminée!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>Signaler la compatibilité</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>Signaler la compatibilité d&apos;un jeu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Si vous choisissez à soumettre un test d&apos;essai à la liste de compatibilité yuzu&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, Les informations suivantes seront collectées et publiées sur le site :
+&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Informations Système (Processeur / Carte Graphique / Système d&apos;exploitation)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;La version de yuzu que vous employez&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Le compte yuzu sous lequel vous êtes connecté&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>Parfait</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Le jeu fonctionne parfaitement sans problèmes audio-visuels.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>Super</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Le jeu fonctionne avec des problèmes audio-visuels mineurs et est jouable du début jusqu&apos;à la fin. Peut nécessiter des patchs temporaires. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>Correct</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Le jeu fonctionne avec des problèmes audio ou graphiques majeurs, mais est jouable du début à la fin avec des modifications.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>Mauvais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Le jeu fonctionne, mais avec des problèmes graphiques ou audio majeurs. Impossible de progresser à certains endroits spécifiques à cause de ces problèmes même en utilisant des modifications. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Le jeu est complètement injouable à cause de problèmes graphique ou audio majeur. Impossible de progresser plus loin que le menu de départ.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Ne se lance pas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Le jeu crash au lancement. .&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sans prendre en compte la vitesse ou les performances, À quel point ce jeu est-il bien émulée du début à la fin sur cette version de yuzu ?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>Merci de votre Suggestion !</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>Soumission en cours</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>Erreur de communication</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>Une erreur est survenue en envoyant l&apos;erreur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>Suivant</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>Moteur de Sortie :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>Il s&apos;agit d&apos;un effet de post-traitement qui ajuste la vitesse de l&apos;audio sur celle de l&apos;émulation afin de prévenir les lags du son. Ceci augmente toutefois la latence du son.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>Activer l&apos;étirement du son</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>Appareil audio :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation>Utiliser le volume global</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation>Régler le volume:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>Volume :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation>Général</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation>Précision:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation>Précis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation>Peu sûr</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation>Activer le mode de débogage</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation>Nous recommandons de régler la précision sur &quot;Précis&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation>Paramètres d&apos;optimisation du CPU non sûrs</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation>Ces réglages réduisent la précision pour la vitesse.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation>Non-utilisation du FMA (améliorer les performances des CPU sans FMA) </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation>
+Cette option améliore la vitesse en réduisant la précision des instructions fusionnées-multiple-ajoutées sur les CPU sans support FMA natif.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation>FRSQRTE et FRECPE plus rapides</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation>
+Cette option améliore la vitesse de certaines fonctions approximatives en virgule flottante en utilisant des approximations natives moins précises.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>Les paramètres du CPU ne sont disponibles que lorsque le jeu n&apos;est pas en marche.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation>Mise en mode de débogage du CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation>Le mode de débogage du CPU est uniquement destiné à l&apos;usage des développeurs. Êtes-vous sûr de vouloir l&apos;activer?</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation>Activer les optimisations du CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;
+&lt;b&gt;Pour le débogage uniquement.&lt;/b&gt;
+&lt;br&gt;
+Si vous n&apos;êtes pas sûr de ce qu&apos;elles font, laissez-les toutes activées.
+&lt;br&gt;
+Ces réglages ne prennent effet que lorsque la précision du CPU est en &quot;mode débogage&quot;.
+&lt;/div&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>Activer le &quot;stub&quot; de GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>Port :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>S&apos;enregistrer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>Filtre de log global</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>Montrer le journal de logs (Uniquement sur Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>Ouvrir l&apos;emplacement du journal de logs</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>Homebrew</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>Chaîne d&apos;arguments</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>Activer les services de rapport verbeux</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>Ceci sera automatiquement mis à zéro quand yuzu se fermera</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>Avancé</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation>Mode Kiosk (Quest)</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>Configuration de yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>Général</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>UI</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>Liste des jeux</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>Système</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>Profils</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>Système de fichier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>Contrôles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>Raccourcis clavier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>Débogage</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>Vidéo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>Son</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Web</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>Services</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>Répertoire de stockage</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>Carte SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>Cartouche de jeu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>Chemin</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>Inséré</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>Jeu en cours</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>Gestionnaire de correctif</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>Extraire les fichiers NSOs décompressés</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>Extraire l&apos;ExeFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation>Racine de chargement de mod</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation>Extraire la racine</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>Mise en cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>Répertoire du cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation>Mettre en cache la métadonnée de la liste des jeux</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>Mettre à zéro le cache des métadonnées</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>Sélectionner le répertoire NAND émulé...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>Sélectionner le répertoire SD émulé...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation>Sélectionner le chemin de la cartouche de jeu...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>Sélectionner le répertoire d&apos;extraction...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation>Sélectionner le répertoire de chargement de mod...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>Sélectionner le répertoire du cache...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>Le cache des métadonnées est déjà vide.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>L&apos;opération s&apos;est terminée avec succès.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>Le cache des métadonnées n&apos;a pas pu être supprimé. Il pourrait être utilisé ou non-existant.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>Général </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>Limiter la vitesse en pourcentages</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>Confirmer la sortie pendent l&apos;émulation en cours</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation>Demander l&apos;utilisateur au lancement d&apos;un jeu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>Mettre en pause l’émulation lorsque mis en arrière plan </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>Utiliser les shader cache de disque</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>Utiliser l&apos;émulation GPU asynchrone</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>Couleur de L’arrière plan :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>Paramètres de raccourcis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation>Double-cliquez sur une liaison pour la changer.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>Action</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>Raccourci clavier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>Contexte</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>Séquence de touches conflictuelle</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>Joueur 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>Joueur 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>Joueur 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>Joueur 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>Joueur 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>Joueur 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>Joueur 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>Joueur 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>Avancé</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>Configurer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Configurer les touches</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>Stick Gauche</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>Boutons</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>Stick Droit</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>Configuration de la souris</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>Boutons de la souris</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>Avant :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>Arrière :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>Gauche :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>Milieu :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>Droite :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>Effacer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[pas défini]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>Réinitialiser </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[appuyez sur une touche]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>Gestionnaire de profil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>Utilisateur actuel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>Nom d&apos;utilisateur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>Mettre une image</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>Ajouter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>Renommer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>Supprimer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>La gestion de profil est accessible uniquement lorsque aucun jeu n&apos;est en cours.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>Entrez un nom d&apos;utilisateur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>Utilisateurs</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>Entrez un nom d&apos;utilisateur pour le nouvel utilisateur :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>Entrez un nouveau nom d&apos;utilisateur :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>Confirmez la suppression</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>Vous êtes sur le point de supprimer l&apos;utilisateur avec le nom &quot;%1&quot;. Êtes vous sûr?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>Sélectionner l&apos;image de l&apos;utilisateur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>Images JPEG (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>Erreur dans la suppression de l&apos;image</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>Une erreur est survenue en essayant de changer l&apos;image précédente à : %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>Erreur dans la suppression du fichier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>Impossible de supprimer le fichier existant : %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>Erreur dans la création du répertoire d&apos;image de l&apos;utilisateur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>Impossible de créer le répertoire %1 pour stocker les images de l&apos;utilisateur.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>Erreur dans la copie de l&apos;image de l&apos;utilisateur</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>Impossible de copier l&apos;image de %1 à %2</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>Le BCAT et le chemin que Nintendo utilise pour envoyer des informations au jeux pour encourager sa communauté à débloquer du contenu additionel.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation>BCAT Back-end</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Apprenez en plus sur le BCAT, le Boxcat, et les événements courants&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation>Le service boxcat est hors-ligne ou vous n&apos;êtes pas connectés à internet.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>Une erreur est survenu lors du traitement des données boxcat. Contactez les développeurs de yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>La version de yuzu que vous utilisez est trop vieille ou trop nouvelle pour le serveur. Essayez la dernière mise à jour officiel de yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation>Il n&apos;y a pour le moment aucun événements sur boxcat.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation>Yuzu récupere le statut de boxcat le plus récent...</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>Paramètres Système</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>Note : ceci peut être remplacé quand le paramètre de région est réglé sur automatique</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>Japonais (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>Anglais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>Français (français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>Allemand (Deutsch)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>Italien (italiano)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>Espagnol (español)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>Chinois</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>Coréen (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>Néerlandais (Nederlands)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>Portugais (português)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>Russe (Русский)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>Taïwanais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>Anglais Britannique</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>Français Canadien</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>Espagnol d&apos;Amérique Latine</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>Chinois Simplifié</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>Chinois Traditionnel (正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>RTC Customisé</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>Langue</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>Seed RNG</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>Mono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>Stéréo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>Surround</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>ID de la Console :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>Mode de sortie Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation>d MMM yyyy h:mm:ss AP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>Regénérer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>Les paramètres systèmes ne sont accessibles que lorsque le jeu n&apos;est pas en cours.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>Ceci remplacera la Switch virtuelle actuelle par une nouvelle. La Switch actuelle ne sera plus récupérable. cela peut entrainer des effets non désirés pendant le jeu. Ceci peut échouer si une configuration de sauvegarde périmée est utilisée. Continuer ?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>Avertissement</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>ID de la Console : 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>Configurer l&apos;Écran Tactile</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>Avertissement : les paramètres de cette page affecte la fonctionnalité intrinsèque de l&apos;écran tactile émulée de yuzu. Toute modification pourrait aboutir à un comportement non désiré, comme par exemple : l&apos;écran tactile qui ne fonctionne plus, de manières partielle ou totale. N&apos;utilisez cette page que si ne vous ne savez ce que vos faites.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>Paramètres Tactiles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>Diamètres Tactiles Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>Doigt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>Diamètres Tactiles X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>Angle de Rotation</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>Restaurer</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>Général</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>Note : Changer la langue appliquera votre configuration.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>Language de l&apos;interface :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>Thème :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>Liste de jeux</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>Afficher la colonne Des Add-Ons</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>Grosseur de l&apos;icône</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>Texte rangée 1 :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>Texte rangée 2 :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>Anglais</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forme</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>Service Web yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>En fournissant votre surnom et token, vous acceptez de permettre à yuzu de collecter des données d&apos;utilisation supplémentaires, qui peuvent contenir des informations d&apos;identification de l&apos;utilisateur.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>Vérifier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>Se connecter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>Token :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>Pseudonyme :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>Qu&apos;est ce que mon token ? </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>Télémétrie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>Partager les données d&apos;utilisation anonymes avec l&apos;équipe yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>En savoir plus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>ID Télémétrie :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>Regénérer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Statut Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Afficher le jeu en cours dans le Statut Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;En savoir plus&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Se connecter&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Quel est mon token ?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>ID Télémétrie : 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>Non-spécifié</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>Token non vérifié</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>Le token n&apos;a pas été vérifié. Le changement à votre token n&apos;a pas été enregistré.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>Vérification...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>Échec de la vérification</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>Échec de la vérification. Vérifiez si vous avez correctement entrez votre token, et que votre connection internet fonctionne.</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Des données anonymes sont collectées&lt;/a&gt; pour aider à améliorer yuzu. &lt;br/&gt;&lt;br/&gt;Voulez-vous partager vos données d&apos;utilisations avec nous ?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>Télémétrie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>Échec de la vérification du texte</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation>Chargement du Web Applet...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation>Quitter le Web Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>Quitter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation>Pour quitter l&apos;application web, utilisez les contrôles réserver par le jeu pour sélectionner exit, sélectionner l&apos;option &apos;Quitter le Web Applet&apos; dans la barre menu, ou appuyez sur la touche &apos;Entrer&apos;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation>Web Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>Cette version de yuzu à été construit sans le support de QtWebEngine, ce qui veut dire que yuzu ne peut pas correctement afficher le manuel du jeu ou la page web demandée.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>Valeur actuelle de la vitesse de l&apos;émulation. Des valeurs plus hautes ou plus basses que 100% indique que l&apos;émulation fonctionne plus vite ou plus lentement qu&apos;une véritable Switch.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>Combien d&apos;image par seconde le jeu est en train d&apos;afficher. Ceci vas varier de jeu en jeu et de scènes en scènes.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Temps pris pour émuler une image par seconde de la switch, sans compter le limiteur d&apos;image par seconde ou la synchronisation verticale. Pour une émulation à pleine vitesse, ceci devrait être au maximum à 16.67 ms.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>Effacer les Fichiers Récents</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>Avertissement : Le Format de jeu est dépassé</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>Vous utilisez un format de ROM déconstruite pour ce jeu, qui est donc un format dépassé qui à été remplacer par d&apos;autre. Par exemple les formats NCA, NAX, XCI, ou NSP. Les destinations de ROM déconstruites manque des icônes, des métadonnée et du support de mise à jour.&lt;br&gt;&lt;br&gt;Pour une explication des divers formats Switch que yuzu supporte, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;Regardez dans le wiki&lt;/a&gt;. Ce message ne sera pas montré une autre fois.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>Erreur lors du chargement de la ROM !</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>Le format de la ROM n&apos;est pas supporté.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>Une erreur s&apos;est produite lors de l&apos;initialisation du noyau dédié à la vidéo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>yuzu a rencontré une erreur fatale, veuillez consulter les logs pour plus de détails. Pour plus d&apos;informations sur l&apos;accès aux logs, veuillez consulter la page suivante : &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt; Comment télécharger le fichier des logs &lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Voulez-vous quitter la liste des jeux ? Une émulation continue peut entraîner des crashs, la corruption de données de sauvegarde ou d’autres bugs.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>Une erreur inconnue est survenue. Veuillez consulter le journal des logs pour plus de détails.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>Démarrer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>Enregistrer les données</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Donnés du Mod</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>Erreur dans l&apos;ouverture du dossier %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>Le dossier n&apos;existe pas !</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>Erreur lors de l&apos;ouverture des Shader Cache Transferable</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>Un shader cache pour ce titre n&apos;existe pas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>L&apos;extraction de la RomFS a échoué !</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>Une erreur s&apos;est produite lors de la copie des fichiers RomFS ou l&apos;utilisateur a annulé l&apos;opération.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>Plein</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation>Squelette</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>Sélectionnez le mode d&apos;extraction de la RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>Veuillez sélectionner la manière dont vous souhaitez que le fichier RomFS soit extrait.&lt;br&gt;Full copiera tous les fichiers dans le nouveau répertoire, tandis que&lt;br&gt;skeleton créera uniquement la structure de répertoires.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>Extraction de la RomFS ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>Extraction de la RomFS réussi !</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>L&apos;opération s&apos;est déroulée avec succès.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>Erreur lors de l&apos;ouverture %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>Sélectionner un répertoire</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>Propriétés</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>Les propriétés du jeu n&apos;ont pas pu être chargées.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Exécutable Switch (%1);;Tous les fichiers (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>Charger un fichier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>Ouvrir le dossier des ROM extraites</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>Destination sélectionnée invalide</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>Le répertoire que vous avez sélectionné ne contient pas de fichier &quot;main&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>Installation du fichier &quot;%1&quot; ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>Application Système</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>Archive Système</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>Mise à jour de l&apos;application système</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>Paquet micrologiciel (Type A)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>Paquet micrologiciel (Type B)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>Jeu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>Mise à jour de jeu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>DLC de jeu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>Titre Delta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>Sélectionner le type d&apos;installation du NCA...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>Veuillez sélectionner le type de titre auquel vous voulez installer ce NCA :
+(Dans la plupart des cas, le titre par défaut : &apos;Jeu&apos; est correct.)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>Échec de l&apos;installation</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>Le type de titre que vous avez sélectionné pour le NCA n&apos;est pas valide.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>Fichier non trouvé</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>Fichier &quot;%1&quot; non trouvé</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>Continuer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>Erreur d&apos;affichage</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>Compte yuzu manquant</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>Pour soumettre un test de compatibilité pour un jeu, vous devez lier votre compte yuzu.&lt;br&gt;&lt;br/&gt;Pour lier votre compte yuzu, aller à Emulation &amp;gt; Configuration&amp;gt; Web.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>Fichier Amiibo (%1);; Tous les fichiers (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>Charger un Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>Erreur lors de l&apos;ouverture du fichier de données Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>Impossible d&apos;ouvrir le fichier Amiibo &quot;%1&quot; à lire.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>Erreur lors de la lecture du fichier de données Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>Impossible de lire entièrement les données Amiibo. On s&apos;attend à lire %1 octets, mais il n&apos;a pu lire que %2 octets</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>Erreur lors du chargement des données Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>Impossible de charger les données Amiibo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>Capture d&apos;écran</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>Image PNG (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>Vitesse : %1% / %2% </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>Vitesse : %1% </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>Jeu : %1 FPS </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>Frame : %1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>Le jeu que vous essayez de charger a besoin de fichiers additionnels que vous devez extraire depuis votre Switch avant de jouer.&lt;br/&gt;&lt;br/&gt;Pour plus d&apos;information sur l&apos;extraction de ces fichiers, veuillez consulter la page du wiki suivante : &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Extraction des archives système et des Shared Fonts depuis la Switch&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Voulez-vous quitter la liste des jeux ? Une émulation continue peut entraîner des crashs, la corruption de données de sauvegarde ou d’autres bugs.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>yuzu n&apos;a pas été capable de localiser un système d&apos;archive Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>yuzu n&apos;a pas été capable de localiser un système d&apos;archive Switch. %1. %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>Archive système introuvable</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>Archive Système Manquante</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>Yuzu n&apos;a pas été capable de localiser les polices partagées de la Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>Les polices partagées non pas été trouvées</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>Polices Partagée Manquante</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>Erreur fatale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>yuzu a rencontré une erreur fatale, veuillez consulter les logs pour plus de détails. Pour plus d&apos;informations sur l&apos;accès aux logs, veuillez consulter la page suivante : &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt; Comment télécharger le fichier des logs &lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Voulez-vous quitter la liste des jeux ? Une émulation continue peut entraîner des crashs, la corruption de données de sauvegarde ou d’autres bugs.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>Erreur Fatale rencontrée</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>Confirmer la réinstallation de la clé</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>Vous êtes sur le point de réinstaller toutes vos clés.
+Si vous ne savez pas ce que cela veut dire et ce que vous faites,
+cela peut être une action potentiellement destructrice.
+S&apos;il vous plaît assurez-vous que c&apos;est bien ce que vous voulez
+et éventuellement faites des sauvegardes.
+
+Cela supprimera vos fichiers de clé générés automatiquement et ré exécutera le module d&apos;installation de clé.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>Installation des clés...
+Cela peut prendre jusqu&apos;à une minute en fonction
+des performances de votre système.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>Installation des clés</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>Sélectionner la cible d&apos;extraction du RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>Veuillez sélectionner quel RomFS vous voulez extraire.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>Êtes vous sûr de vouloir fermer yuzu ?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>Êtes-vous sûr d&apos;arrêter l&apos;émulation ? Tout progrès non enregistré sera perdu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>L&apos;application en cours a demandé à yuzu de ne pas quitter.
+
+Voulez-vous ignorer ceci and quitter quand même ?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>Nom</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>Compatibilité</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>Extensions</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>Type de fichier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>Taille</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>Ouvrir l&apos;emplacement des données de sauvegarde</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Ouvrir l&apos;emplacement des données des mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>Ouvrir le cache de shaders transférable</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>Extraire la RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>Copier l&apos;ID du titre dans le Presse-papiers</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>Accédez à l&apos;entrée GameDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>Propriétés</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>Scanner les sous-dossiers</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>Supprimer le répertoire du jeu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>Ouvrir l&apos;emplacement du répertoire</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>Parfait</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>Le jeu fonctionne parfaitement, de manière fluide sans aucun bug audio ou graphique, toutes les fonctionnalités testées fonctionnent comme prévu sans
+aucune modification nécessaire.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>Bon</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>Le jeu fonctionne correctement avec des bugs audio ou graphiques mineurs et est jouable du début à la fin. Nécessite peut être des
+modifications</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>Le jeu fonctionne avec des bugs audio ou graphiques majeurs, mais il est jouable du début à la fin avec des modifications.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>Mauvais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>Le jeu fonctionne mais avec des bugs audio et graphiques majeurs. Impossible de progresser dans certaines zones à causes des bugs
+même avec des modifications.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>Le jeu est complètement injouable à cause de bugs audio et graphiques. Impossible de progresser plus loin que l&apos;écran de démarrage.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Ne démarre pas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>Le jeu crash au lancement.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>Non testé</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>Le jeu n&apos;a pas encore été testé.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>Double-cliquez pour ajouter un nouveau dossier à la liste de jeux</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>Filtre :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>Entrez un motif à filtrer</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>Chargement des shaders 387 / 1628</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>Chargement des shaders %v sur %m</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>Temps Estimé 5m 4s</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>Chargement...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>Chargement des shaders %1 / %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>Lancement...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>Temps Estimé %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>&amp;Fichier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>Fichiers récents</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>&amp;Émulation</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>&amp;Vue</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>Débogage</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>Outils</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>&amp;Aide</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>Charger un fichier ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>Charger un dossier ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>Q&amp;uitter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>&amp;Démarrer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>&amp;Pause</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>&amp;Arrêter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>Réinitialiser les clés ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>À propos de yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>Mode fenêtre unique</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>Configurer ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>Afficher les &quot;Dock Widget Headers&quot;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>Afficher la barre de filtre</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>Afficher la barre d&apos;état</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>Plein écran</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>Redémarrer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>Charger un Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>Signaler la compatibilité</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>Ouvrir le dossier de yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>Prendre une capture d&apos;ecran</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>MicroProfil</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>Titres installés sur la SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>Titres installés sur la NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>Titres Système</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>Ajouter un nouveau répertoire de jeu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Maj</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[non défini]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>Chapeau %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>Axe %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>Bouton %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[inconnu]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[inutilisé]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>Axe %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>Une erreur s&apos;est produite.
+Veuillez essayer à nouveau ou contactez le développeur du logiciel.
+
+Code d&apos;Erreur: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>Une erreur s&apos;est produite le %1 à %2.
+Veuillez essayer à nouveau ou contactez le développeur du logiciel.
+
+Code d&apos;Erreur: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>Une erreur s&apos;est produite.
+Code d&apos;Erreur: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>Choisir un utilisateur :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>Utilisateurs</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>Sélecteur de profil</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>Entrer le texte :</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>Clavier virtuel</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>Entrez une hotkey</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>Pile d&apos;exécution</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>en attente du &quot;mutex&quot; 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>En attente : %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>propriétaire de la manche : 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>en attente de tous les objets</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>en attente d&apos;un des objets suivants</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>en cours</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>prêt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>en pause</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>en attente du retour de HLE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>en veille</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>en attente de réponse IPC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>En attente d&apos;objets</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>En attente du &quot;mutex&quot;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>en attente de la variable conditionnelle</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>En attente de l&apos;adresse arbitre</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>dormant</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>Mort</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation>PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>idéal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>cœur %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>Processeur inconnu %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>Processeur = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>Cœur idéal = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>masque d&apos;affinité = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>id du fil = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>priorité = %1(courant) / %2(normal)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>dernier tick en cours = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>en attente du &quot;mutex&quot;</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>attendu par un fil</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>Arbre d&apos;attente</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/it.ts b/dist/languages/it.ts
new file mode 100644
index 000000000..09c832fd3
--- /dev/null
+++ b/dist/languages/it.ts
@@ -0,0 +1,4724 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="it" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>Riguardo yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu è un emulatore open source sperimentale per Nintendo Switch sotto licenza GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;Questo software non dovrebbe essere utilizzato per giocare a giochi che non hai ottenuto legalmente&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Sito&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Codice Sorgente&lt;/span&gt;&lt;/a&gt; I &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributori&lt;/span&gt;&lt;/a&gt; I &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licenza&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; è un marchio registrato di Nintendo. yuzu non è affiliato a Nintendo in alcun modo.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation>In comunicazione con il server...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation>Configurazione completata!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>Segnala Compatibilità</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>Segnala la Compatibilità di un Gioco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Se dovessi scegliere di inviare un rapporto alla &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Lista Compatibilità di yuzu&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, Le seguenti informazioni saranno raccolte e visualizzate sul sito: &lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Informazioni sull&apos;Hardware (CPU / GPU / Sistema Operativo)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Quale versione di yuzu stai utilizzando&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;L&apos;account di yuzu connesso&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>Perfetto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Il gioco funziona impeccabilmente senza errori di audio o grafici.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>Buono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Il gioco funziona con qualche errore grafico minore o glitch nell&apos;audio ed è giocabile dall&apos;inizio alla fine. Potrebbe richiedere qualche metodo alternativo.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Il gioco funziona e ha errori grafici gravi o glitch nell&apos;audio ma è possibile giocare dall&apos;inizio alla fine con dei metodi alternativi.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>Scadente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Il gioco presenta alcuni errori audio o video. E&apos; impossibile proseguire in alcune aree a causa della presenza di glitch persino utilizzando metodi alternativi.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Questo gioco è completamente ingiocabile a causa di gravi errori audio o video. E&apos; impossibile proseguire oltre la schermata iniziale.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Non si Avvia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Il gioco si blocca quando viene avviato.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Indipendentemente da velocità o prestazioni, come ti è sembrato giocare questo gioco dall&apos;inizio alla fine su questa versione di yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>Grazie per la tua segnalazione!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>Inviando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>Errore di comunicazione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>E&apos; stato riscontrato un errore mandando il Testcase</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>Prossimo</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>Motore dell&apos;Output:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>L&apos;effetto post-processing regola la velocità dell&apos;audio per fare in modo che sia uguale alla velocità del gioco e prevenire problemi di audio. Questo tuttavia aumenta la latenza dell&apos;audio.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>Abilita allungamento dell&apos;audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>Dispositivo Audio:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation>Usa volume globale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation>Imposta volume:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>Volume:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation>Generale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation>Non sicuro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation>Abilita Modalità Debug</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation>Impostazioni Ottimizzazione CPU non sicura</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>Abilita GDB Stub</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>Porta:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>Logging</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>Filtro Log Globale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>Mostra Console Log (Solo per Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>Apri Cartella Log</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>Homebrew</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>Stringa degli Argomenti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation>Grafica</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>Abilita Servizi di Segnalazione Dettagliata</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>Verrà ripristinato automaticamente dopo la chiusura di yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>Avanzate</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation>Modalità Kiosk (Quest)</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>Configurazione di yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>Generale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>Interfaccia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>Lista Giochi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>Profili</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>Filesystem</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>Comandi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>Hotkey</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>Debug</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>Grafica</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Web</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>Servizi</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>Cartelle di Archiviazione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>Scheda SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>Cartuccia di gioco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>Percorso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>Inserita</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>Gioco In Uso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>Gestione Patch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>Estrai NSO Decompressi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>Estrai ExeFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation>Cartella Caricamento Mod</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation>Cartella di Estrazione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>Caching</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>Cartella Cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation>Crea Cache di Metadati Lista Giochi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>Elimina Cache dei Metadati</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>Seleziona Cartella NAND Emulata</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>Seleziona Cartella Scheda SD Emulata</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation>Seleziona Percorso Cartuccia di Gioco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>Seleziona Cartella di Estrazione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation>Seleziona Cartella per il Caricamento delle Mod</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>Seleziona Cartella della Cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>La cache dei metadati è già vuota.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>L&apos;operazione è stata completata con successo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>Impossibile eliminare cache dei metadati. Potrebbe essere in uso o inesistente.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>Generale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>Percentuale Limite Velocità</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>Richiedi conferma di uscire mentre l&apos;emulazione è in corso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation>Richiedi utente all&apos;avvio di un gioco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>Pausa emulazione quando in background</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation>Impostazioni API</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation>API:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation>Dispositivo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation>Impostazioni grafiche</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>Usa cache shader su disco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>Usa emulazione GPU asincrona</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation>Default (16:9)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation>Usa il colore di sfondo globale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation>Imposta colore dello sfondo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>Colore Sfondo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation>2x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation>4x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation>8x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation>16x</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>Impostazioni Hotkey</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation>Clicca due volte su un collegamento per cambiarlo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>Azione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>Hotkey</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>Contesto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>Conflitto nella Sequenza di Tasti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>Giocatore 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>Giocatore 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>Giocatore 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>Giocatore 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>Giocatore 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>Giocatore 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>Giocatore 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>Giocatore 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>Avanzate</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation>Vibrazione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>Configura</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation>1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation>2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation>3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation>4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation>5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation>6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation>7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation>8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation>Connesso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation>Predefiniti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation>Giocatore 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation>Giocatore 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation>Giocatore 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation>Giocatore 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation>Giocatore 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation>Giocatore 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation>Giocatore 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation>Giocatore 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation>Altro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation>Tastiera</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation>Avanzate</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation>Touchscreen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation>Mouse</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation>Configura</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation>Debug Controller</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Configura Input</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation>Salva</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation>Nuovo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation>Elimina</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>Stick Sinistro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation>Su</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation>Sinistra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation>Destra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation>Giù</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation>Premuto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation>Modificatore</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation>L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation>ZL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation>Meno</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation>Cattura</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation>Più</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation>Home</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation>R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation>ZR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation>SL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation>SR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>Pulsanti Frontali</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation>B</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>Stick Destro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation>[in attesa]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation>Sensibilità:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation>Touch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation>Calibrazione:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation>(100, 50) - (1800, 850)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation>Configura</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>Configura Mouse</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>Pulsanti Mouse</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>Avanti:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>Indietro:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>Sinistro:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>Centrale:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>Destro:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>Cancella</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[non impostato]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>Ripristina Predefinito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[premi un pulsante]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>Gestione Profili</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>Utente in Uso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>Nome Utente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>Imposta Immagine</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>Aggiungi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>Rinomina</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>Rimuovi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>La gestione dei profili è disponibile solamente quando nessun gioco è in esecuzione.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>&amp;1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>Inserisci Nome Utente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>Utenti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>Inserisci un nome utente per il nuovo utente:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>Inserisci un nuovo nome utente:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>Conferma Eliminazione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>Stai per cancellare l&apos;utente chiamato &quot;%1&quot;. Sei sicuro?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>Seleziona Immagine Utente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>Immagini JPEG (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>Impossibile eliminare l&apos;immagine</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>Impossibile sovrascrivere l&apos;immagine precedente in: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>Impossibile eliminare il file</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>Impossibile eliminare il file già esistente: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>Errore nella creazione della cartella delle immagini dell&apos;utente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>Impossibile creare la cartella %1 per archiviare le immagini dell&apos;utente.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>Impossibile copiare l&apos;immagine utente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>Impossibile copiare l&apos;immagine da %1 a %2</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>Nintendo usa BCAT per inviare dati ai giochi per coinvolgere la comunità e sbloccare contenuti aggiuntivi.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation>Backend BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Scopri di più riguardo BCAT, Boxcat, ed Eventi in Corso&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation>Il servizio boxcat è offline o potresti non essere connesso a internet.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>E&apos; stato riscontrato un errore nell&apos;elaborazione dei dati degli eventi di boxcat. Contatta gli sviluppatori di yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>La versione di yuzu che stai usando è troppo vecchia o troppo nuova per questo server. Prova ad aggiornare all&apos;ultima release ufficiale di yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation>Non ci sono eventi in corso su boxcat.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation>yuzu sta recuperando lo stato attuale di boxcat...</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>Impostazioni di Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation>UTC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation>W-SU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation>WET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation>Zulu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation>USA</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation>Europa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation>Australia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation>Cina</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation>Corea</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation>Taiwan</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>Nota: questo può essere ignorato quando le impostazioni della regione sono su auto-select</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>Giapponese (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>Inglese (English)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>Francese (français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>Tedesco (Deutsch)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>Italiano</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>Spagnolo (español)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>Cinese</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>Coreano (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>Olandese (Nederlands)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>Portoghese (português)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>Russo (Русский)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>Taiwanese</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>Inglese Britannico</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>Francese Canadese</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>Spagnolo Latino Americano</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>Cinese Semplificato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>Cinese Tradizionale (正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>RTC Personalizzato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>Lingua</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>Seed RNG</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>Mono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>Stereo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>Surround</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>ID Console:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>Modalità di output del sonoro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation>d MMM yyyy h:mm:ss AP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>Rigenera</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>Le impostazioni di sistema sono disponibili solamente quando nessun gioco è in esecuzione.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>Questo rimpiazzerà la tua Switch virtuale con una nuova. La tua Switch virtuale non sarà recuperabile. Questo potrebbe avere effetti indesiderati nei giochi. Questo potrebbe fallire, se usi un salvataggio non aggiornato. Desideri continuare?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>Attenzione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>ID Console: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation>Nuovo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation>Elimina</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation>Rinomina</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation>Elimina Punto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation>Pulsante</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation>Nuovo Profilo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation>Inserisci il nome per il nuovo profilo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation>Elimina Profilo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation>Elimina profilo %1?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation>Rinomina Profilo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation>Nuovo nome:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation>[premi pulsante]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>Configura Touchscreen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>Attenzione: Le impostazioni in questa pagina influenzano il funzionamento interno del touchscreen emulato di yuzu. Cambiarle potrebbe risultare in effetti indesiderati, ad esempio il touchscreen potrebbe non funzionare parzialmente o totalmente. Utilizza questa pagina solo se sei consapevole di ciò che stai facendo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>Parametri Touch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>Diametro Touch Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>Dito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>Diametro Touch X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>Angolo di Rotazione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>Ripristina Predefiniti</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>Generale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>Nota: Cambiare lingua applicherà i cambiamenti fatti alla configurazione.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>Lingua Interfaccia:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>Tema:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>Lista Giochi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>Mostra Colonna Add-On</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>Dimensione Icona:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>Testo Riga 1:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>Testo Riga 2:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation>Screenshots</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>Inglese</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>Servizio Web di yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>Fornendo i tuoi nome utente e token, permetti a yuzu di raccogliere dati di utilizzo, che potrebbero includere informazioni di identificazione utente.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>Verifica</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>Registrati</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>Token:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>Nome utente:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>Qual è il mio token?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>Telemetria</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>Condividi dati sull&apos;utilizzo anonimamente con il team di yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>Per saperne di più</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>ID Telemetria:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>Rigenera</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Discord Presence</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Mostra il Gioco Attuale nel tuo Stato di Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Per saperne di più&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Registrati&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Qual è il mio token?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>ID Telemetria: 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>Non specificato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>Token non verificato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>Nome utente e token non verificati. I cambiamenti al tuo nome utente e/o token non sono stati salvati.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>Verifica in corso...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>Verifica fallita</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>Verifica fallita. Controlla di aver inserito correttamente il tuo username e token, e che la tua connessione ad internet sia funzionante.</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Vengono raccolti dati anonimi&lt;/a&gt; per aiutarci a migliorare yuzu. &lt;br/&gt;&lt;br/&gt;Desideri condividere i tuoi dati di utilizzo con noi?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>Telemetria</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>Verificazione Testo Fallita</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation>Caricamento Web Applet...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation>Esci dal Web Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>Esci</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation>Per uscire dall&apos;applicazione web, usa i pulsanti provvisti dal gioco per uscire, seleziona l&apos;opzione &apos;Esci dal Web Applet&apos; nel menu in alto, o premi il tasto &apos;Invio&apos;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation>Web Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>Questa versione di yuzu è stata compilata senza supporto a QtWebEngine, quindi yuzu non potrà aprire il manuale di gioco o delle pagine web.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>Velocità corrente dell&apos;emulazione. Valori più alti o più bassi di 100% indicano che l&apos;emulazione sta funzionando più velocemente o lentamente rispetto a una Switch.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>Quanti frame al secondo il gioco mostra attualmente. Questo varia da gioco a gioco e da situazione a situazione.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Tempo utilizzato per emulare un frame della Switch, non contando i limiti ai frame o il v-sync.
+Per un&apos;emulazione alla massima velocità, il valore dev&apos;essere al massimo 16.67 ms.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>Elimina File Recenti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>Avviso Formato di Gioco Obsoleto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>Stai usando una cartella con dentro una ROM decostruita come formato per avviare questo gioco, è un formato obsoleto ed è stato sostituito da altri come NCA, NAX, XCI o NSP. Le ROM decostruite non hanno icone, metadata e non supportano gli aggiornamenti. &lt;br&gt;&lt;br&gt;Per una spiegazione sui vari formati di Switch che yuzu supporta, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;controlla la nostra wiki&lt;/a&gt;. Questo messaggio non verrà più mostrato.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>Errore nel caricamento della ROM!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>Il formato della ROM non è supportato.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>E&apos; stato riscontrato un errore nell&apos;inizializzazione del core video.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>yuzu ha riscontrato un errore nell&apos;esecuzione del video core, visualizza il log per maggiori dettagli. Per maggiori informazioni su come accedere al log, visualizza la seguente pagina: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Come Caricare Il File Log&lt;/a&gt;. Assicurati di avere gli ultimi driver della tua GPU.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>E&apos; stato riscontrato un errore sconosciuto. Visualizza il log per maggiori dettagli.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>Avvia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>Dati di Salvataggio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Dati delle Mod</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>Errore nell&apos;Apertura della Cartella %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>La cartella non esiste!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>Errore nell&apos;Apertura della Cache Shader Trasferibile</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>Una cache di shader per questo titolo non esiste.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation>Contenuti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation>Aggiorna</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation>DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>Estrazione RomFS Fallita!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>C&apos;è stato un errore nella copia dei file del RomFS o l&apos;operazione è stata annullata dall&apos;utente.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>Completa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation>Scheletro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>Seleziona Modalità Estrazione RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>Seleziona come vorresti estrarre il RomFS. &lt;br&gt;Completo copierà tutti i file in una nuova cartella mentre&lt;br&gt;scheletro creerà solamente le cartelle e le sottocartelle.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>Estrazione RomFS in corso...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>Estrazione RomFS Riuscita!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>L&apos;operazione è stata completata con successo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>Errore nell&apos;Apertura di %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>Seleziona Cartella</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>Proprietà</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>Le proprietà del gioco non sono potute essere caricate.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Eseguibile Switch (%1);;Tutti i File (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>Carica File</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>Apri Cartella ROM Estratta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>Cartella Selezionata Non Valida</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>La cartella che hai selezionato non contiene un file &quot;main&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>Installazione del file &quot;%1&quot;...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>Applicazione di Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>Archivio di Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>Aggiornamento Applicazione di Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>Pacchetto Firmware (Tipo A)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>Pacchetto Firmware (Tipo B)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>Gioco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>Aggiornamento di Gioco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>DLC Gioco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>Titolo Delta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>Seleziona il Tipo di Installazione NCA</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>Seleziona il tipo del file NCA da installare:
+(Nella maggior parte dei casi, il predefinito &apos;Gioco&apos; va bene.)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>Installazione Fallita</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>Il tipo che hai selezionato per l&apos;NCA non è valido.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>File non trovato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>File &quot;%1&quot; non trovato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>Continua</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>Messaggio di Errore</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>Account di yuzu non trovato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>Per segnalare la compatibilità di un gioco, devi collegare il tuo account yuzu. &lt;br&gt;&lt;br/&gt;Per collegare il tuo account yuzu, vai su Emulazione &amp;gt;
+Configurazione &amp;gt; Web.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>File Amiibo (%1);; Tutti I File (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>Carica Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>Errore nell&apos;apertura del file dati Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>Impossibile aprire e leggere il file Amiibo &quot;%1&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>Errore nella lettura dei dati del file Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>Impossibile leggere tutti i dati dell&apos;Amiibo. E&apos; stato possibile leggere solamente %2 byte di %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>Errore nel caricamento dei dati dell&apos;Amiibo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>Impossibile caricare i dati dell&apos;Amiibo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>Cattura Screenshot</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>Immagine PNG (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>Velocità: %1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>Velocità: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>Gioco: %1 FPS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>Frame: %1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>Il gioco che stai provando a caricare richiede ulteriori file che devono essere estratti dalla tua Switch prima di poter giocare. &lt;br/&gt;&lt;br/&gt;Per maggiori informazioni sull&apos;estrazione di questi file, visualizza la seguente pagina della wiki: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Estrazione di Archivi di Sistema e Font Condivisi da una Console Switch&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Vuoi uscire e tornare alla lista dei giochi? Continuare l&apos;emulazione potrebbe risultare in crash, salvataggi corrotti o altri bug.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>yuzu non ha potuto individuare un archivio di sistema della Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>yuzu non ha potuto individuare un archivio di sistema della Switch: %1. %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>Archivio di Sistema Non Trovato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>Archivio di Sistema Mancante</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>yuzu non ha potuto individuare i font condivisi della Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>Font Condivisi Non Trovati</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>Font Condivisi Mancanti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>Errore Fatale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>yuzu ha riscontrato un errore fatale, visualizza il log per maggiori dettagli. Per maggiori informazioni su come accedere al log, visualizza la seguente pagina: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Come Caricare Il File Log&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Vuoi uscire e tornare alla lista dei giochi? Continuare l&apos;emulazione potrebbe risultare in crash, salvataggi corrotti o altri bug.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>Errore Fatale riscontrato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>Conferma Riderivazione Chiave</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>Stai per forzare la ri-derivazione di tutte le tue chiavi.
+Se non sai cosa significa o cosa stai per fare,
+questa azione potrebbe causare gravi problemi.
+Assicurati di volerlo fare
+e facoltativamente fai dei backup.
+
+Questo eliminerà i tuoi file di chiavi autogenerati e ri-avvierà il processo di derivazione delle chiavi.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>Derivazione chiavi...
+Questa operazione potrebbe durare fino a un minuto in
+base alle prestazioni del tuo sistema.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>Derivazione Chiavi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>Seleziona Target dell&apos;Estrazione del RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>Seleziona quale RomFS vorresti estrarre.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>Sei sicuro di voler chiudere yuzu?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>Sei sicuro di voler fermare l&apos;emulazione? Tutti i progressi non salvati verranno perduti.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>L&apos;applicazione in uso ha richiesto a yuzu di non uscire.
+
+Desideri uscire comunque?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>Nome</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>Compatibilità</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>Add-on</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>Tipo di file</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>Dimensione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>Apri Cartella Dati di Salvataggio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Apri Cartella Mod</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>Apri Cache Shader Trasferibile</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>Estrai RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>Copia il Title ID negli Appunti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>Vai alla pagina di GameDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>Proprietà</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>Scansiona Sottocartelle</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>Rimuovi Cartella Giochi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>Apri Cartella</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>Perfetto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>Il gioco funziona perfettamente senza alcuni glitch audio o video, tutte le funzionalità testate funzionano come dovrebbero senza alcun metodo alternativo necessario.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>Buono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>Il gioco presenta qualche errore grafico minore o glitch nell&apos;audio ed è giocabile dall&apos;inizio alla fine. Potrebbe richiedere dei metodi alternativi.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>l gioco presenta alcuni errori gravi audio o video. E&apos; impossibile proseguire in alcune aree a causa della presenza di glitch persino utilizzando metodi alternativi. </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>Scadente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>Il gioco funziona, ma presenta alcuni errori gravi audio o video. È impossibile proseguire in alcune aree a causa della presenza di glitch
+persino utilizzando metodi alternativi.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>Il gioco è completamente ingiocabile a causa di errori gravi audio o video. È impossibile proseguire oltre la Schermata
+Iniziale.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Non si Avvia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>Il gioco si blocca quando viene avviato.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>Non Testato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>Il gioco non è ancora stato testato.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>Clicca due volte per aggiungere una nuova cartella alla lista dei giochi</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>Filtro:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>Inserisci pattern per filtrare</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>387 / 1628 Shader Caricate</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>Caricamento di %v su %m Shader</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>Tempo Stimato 5m 4s</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>Caricamento...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>%1 / %2 Shader Caricate</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>Avvio in corso...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>Tempo Stimato %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>&amp;File</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>File Recenti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>&amp;Emulazione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>&amp;Visualizza</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>Debugging</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>Strumenti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>&amp;Aiuto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>Carica File...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>Carica Cartella...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>&amp;Esci</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>&amp;Avvia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>&amp;Pausa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>&amp;Stop</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>Ri-inizializzando le chiavi...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>Riguardo yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>Modalità Finestra Singola</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>Configura...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>Visualizza le Intestazioni del Dock dei Widget</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>Mostra Barra Filtri</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>Mostra Barra Stato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>Schermo Intero</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>Riavvia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>Carica Amiibo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>Segnala Compatibilità</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>Apri Cartella yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>Cattura Screenshot</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>MicroProfile</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>Titoli SD Installati</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>Titoli NAND Installati</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>Titoli di Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>Aggiungi Nuova Cartella Giochi</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[non impostato]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>Hat %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>Asse %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>Pulsante %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[sconosciuto]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation>Clicca 0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation>Clicca 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation>Clicca 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation>Clicca 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation>Clicca 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation>Assi GC %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation>Pulsanti GC %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[inutilizzato]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>Asse %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation>Assi GC %1</translation>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>E&apos; stato riscontrato un errore.
+Riprova o contatta gli sviluppatori del software.
+
+Codice Errore: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>E&apos; stato riscontrato un errore su %1 a %2.
+Riprova o contatta gli sviluppatori del software.
+
+Codice Errore: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>E&apos; stato riscontrato un errore.
+Codice Errore: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>Seleziona un utente:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>Utenti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>Selettore Profili</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>Inserisci testo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>Tastiera Software</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>Inserisci una hotkey</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>Stack chiamata</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>attende il mutex 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>ha dei waiter: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>proprietario handle: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>attende tutti gli oggetti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>attende uno dei seguenti oggetti</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation>[%1]%2 %3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation>atteso da nessun thread</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>in funzione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>pronto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>in pausa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>attende ritorno dell&apos;HLE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>dormendo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>attende una risposta dell&apos;IPC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>attende degli oggetti</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>attende un mutex</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>aspettando la condition variable</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>attende un indirizzo arbitro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>dormiente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>morto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation> PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>ideale</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>core %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>Processore sconosciuto %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>processore = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>core ideale = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>affinity mask = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>id thread = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>priorità = %1(corrente) / %2(normale)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>last running ticks = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>non attende un mutex</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>atteso dal thread</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>Wait Tree</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/ja_JP.ts b/dist/languages/ja_JP.ts
new file mode 100644
index 000000000..4c3870603
--- /dev/null
+++ b/dist/languages/ja_JP.ts
@@ -0,0 +1,4752 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ja_JP" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>yuzuについて</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzuはGPLv2.0の下で提供されている任天堂Switchの実験的なオープンソースエミュレータです。&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;このソフトウェアは違法に入手したゲームを遊ぶために使用されるべきではありません。&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;ウェブサイト&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;ソースコード&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;貢献者&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;ライセンス&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;任天堂 Switch&amp;quot;は任天堂の登録商標です。 yuzuは任天堂と提携しているわけではありません。&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation>サーバと通信中...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation>タッチパッドの左上を&lt;br&gt;タッチして下さい。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation>次にタッチパッドの右下を&lt;br&gt;タッチして下さい。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation>設定が完了しました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>互換性を報告</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>ゲームの互換性を報告</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;テストケースを&lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu互換性リスト&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;に送信した場合、以下の情報が収集され、サイトに表示されます:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;ハードウェア情報(CPU/GPU/OS)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;実行中のyuzuバージョン&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;接続中のyuzuアカウント&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>パーフェクト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ゲームはオーディオやグラフィックの不具合なしに完全に動作します。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>グレート</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ゲームの動作にはグラフィック、またはオーディオの軽微な不具合がありますが、最初から最後までプレイ可能です。いくつかの回避策が必要な場合があります。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ゲームの動作にはグラフィック、またはオーディオの重大な不具合がありますが、回避策を使うことで最初から最後までプレイ可能です。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>NG</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ゲームは動作しますが、グラフィック、またはオーディオに重大な不具合があります。回避策を使用しても不具合が原因で特定の場所から進めなくなります。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>イントロ/メニューまで</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;グラフィック、またはオーディオの重大な不具合のため、ゲームはプレイ不可能です。スタート画面から先に進めることは出来ません。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>起動せず</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ゲームは起動時にクラッシュします。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;速度やパフォーマンスに関係なく、このゲームはこのバージョンのyuzuで最初から最後までどの程度うまく実行できていますか?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>ご協力ありがとうございます!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>送信中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>通信エラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>テストケースを送信中にエラーが発生しました</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>次</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>オーディオ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>出力エンジン:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>後処理エフェクトは、エミュレーション速度と一致するようにオーディオ速度を調整し、オーディオの乱れを防ぐのに役立ちます。ただしオーディオの遅延が長くなります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>オーディオストレッチの有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>オーディオデバイス:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation>共通の音量設定を使用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation>音量設定:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>音量:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation>全般</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation>正確度:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation>正確</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation>不安定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation>デバッグモードを使用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation>正確度は”正確”に設定することを推奨します。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation>CPU最適化設定(不安定)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation>これらの設定は高速化のために正確性を犠牲にします。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation>FMAの統合を解除(FMAを持たないCPUにおいて速度を改善する)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;このオプションは、ネイティブFMAのサポートを持たないCPUで融合積和命令の精度を下げることで速度を改善させます。&lt;/div&gt;
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation>高速FRSQRTEとFRECPE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;このオプションは、精度の低いネイティブ近似を使用することにより、一部の近似浮動小数点関数の速度を改善させます。&lt;/div&gt;
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>CPU設定は、ゲームが実行されていない場合にのみ使用できます。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation>CPUをデバッグモードに設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation>CPUデバッグモードは、開発者による使用のみを目的としています。有効にしてもよろしいですか?</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation>CPUの最適化を切り替え</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;
+ &lt;b&gt;デバッグ用&lt;/b&gt;
+ &lt;br&gt;
+ これらの機能が何を意味するのか分からない場合は、すべて有効にしておいてください。
+ &lt;br&gt;
+ これらの設定は、CPU精度が”デバッグモード”の場合にのみ有効になります。
+ &lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation>インラインページテーブルの有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;この最適化により、ゲストプログラムによるメモリアクセスが高速化されます。&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;これを有効にすると、PageTable :: pointersへのアクセスが発行されたコードにインライン化されます。&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;これを無効にすると、すべてのメモリアクセスが強制的にMemory :: Read / Memory :: Write関数を経由します。&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation>ブロックリンクの有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;この最適化では、宛先PCが静的な場合、発行された基本ブロックが他の基本ブロックに直接ジャンプできるようにすることで、ディスパッチャーのルックアップを回避します。&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation>リターンスタックバッファの有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;この最適化は、BL命令の潜在的な戻りアドレスを追跡することにより、ディスパッチャーの検索を回避します。これは、実際のCPUのリターンスタックバッファで何が起こるかを概算します。&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation>高速ディスパッチャの有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;2層のディスパッチシステムを有効にします。アセンブリで記述されたより高速なディスパッチャには、ジャンプ先の小さなMRUキャッシュが最初に使用されます。それが失敗した場合、ディスパッチはより遅いC ++ディスパッチャーにフォールバックします。&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation>コンテキスト消去の有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;CPUコンテキスト構造への不要なアクセスを削減するIR最適化を有効にします。&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation>定数伝播の有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;一定の伝播を伴うIR最適化を有効にします。&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation>その他の最適化を有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;その他のIR最適化を有効にします。&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation>ミスアライメントチェックの削減を有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;有効にすると、アクセスがページの境界を越えたときにのみ、ミスアライメントがトリガーされます。&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;無効にすると、ミスアライメントされたすべてのアクセスでミスアライメントがトリガーされます。&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>CPU設定は、ゲームが実行されていない場合にのみ使用できます。</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>GDBスタブの有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>ポート:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>ログの記録</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>グローバルログフィルター</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>ログコンソールの表示(Windowsのみ)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>ログ出力フォルダを開く</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>自作</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>引数文字列</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation>グラフィック</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation>オンにすると、グラフィックAPIはより遅いデバッグモードになります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation>グラフィックデバッグの有効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation>オンにすると、マクロJust In Timeコンパイラが無効になります。有効にすると、ゲームの実行が遅くなります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation>マクロJITの無効化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation>ダンプ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>詳細なレポートサービスを有効にする</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>yuzuを終了したときに自動的にリセットされます。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>拡張</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation>キオスク (クエスト) モード</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation>デバッグコントローラ設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation>消去</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation>デフォルト</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>yuzuの設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>全般</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>UI</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>ゲームリスト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>システム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>プロファイル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>ファイルシステム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>コントロール</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>ホットキー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation>CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>デバッグ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>グラフィック</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation>拡張</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation>拡張グラフィック</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>オーディオ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Web</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>サービス</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>ストレージディレクトリ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>SDカード</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>ゲームカード</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>パス</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>挿入する</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>現在のゲーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>パッチマネージャ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>解凍されたNSOをダンプ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>ExeFSをダンプ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation>Modロードディレクトリ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation>ダンプディレクトリ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>キャッシュ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>キャッシュディレクトリ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation>ゲームリストのメタデータをキャッシュする</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>メタデータのキャッシュをクリアする</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>NANDディレクトリを選択...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>SDディレクトリを選択...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation>ゲームカードのパスを選択...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>ダンプディレクトリを選択...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation>Modロードディレクトリを選択...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>キャッシュディレクトリを選択...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>メタデータのキャッシュはすでに空です。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>操作は成功しました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>メタデータのキャッシュを削除できませんでした。使用中、または存在していない可能性があります。</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>全般</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>速度パーセントの制限</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation>マルチコアCPUエミュレーション</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>エミュレーション実行中の終了確認</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation>ゲーム起動時に確認を表示</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>バックグラウンド時にエミュレーションを停止</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation>未使用時にマウスを非表示</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation>API設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation>API:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation>デバイス:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation>グラフィック設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>ディスクシェーダキャッシュを使用する</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>非同期GPUエミュレーションを使用する</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation>アスペクト比:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation>デフォルト (16:9)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation>4:3を強制</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation>21:9を強制</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation>ウィンドウに合わせる</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation>共通の背景色を使用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation>背景色の設定:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>背景色:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation>OpenGLグラフィックデバイス</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation>拡張グラフィック設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation>正確性レベル:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation>VSyncは画面のティアリングを防ぎますが、一部のグラフィックカードはVSyncが有効になっているとパフォーマンスが低下します。パフォーマンスの違いに気づかない場合は、有効にしてください。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation>VSyncを使用(OpenGLのみ)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation>これを有効にすると、シェーダースタッターが減少します。サポートされているNvidiaデバイスでOpenGLアセンブリシェーダーを有効にします(NV_gpu_program5が必要です)。この機能は実験的なものです。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation>アセンブリシェーダーを使用します(実験的、Nvidia OpenGLのみ)。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation>非同期シェーダーコンパイルを有効にします。これにより、シェーダースタッターが減少する場合があります。この機能は実験的なものです。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation>非同期シェーダー構築を使用します(実験的)。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation>高速CPU時間を使用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation>異方性フィルタリング:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation>デフォルト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation>2x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation>4x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation>8x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation>16x</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>ホットキー設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation>変更するには項目をダブルクリックしてください。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation>すべて消去</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation>デフォルトに戻す</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>アクション</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>ホットキー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>コンテキスト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>キー設定の衝突</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation>入力されたキーシーケンスは既に割り当てられています:%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation>デフォルトに戻す</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation>消去</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation>デフォルトのキーシーケンスは既に割り当てられています:%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation>入力設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>プレイヤー1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>プレイヤー2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>プレイヤー3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>プレイヤー4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>プレイヤー5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>プレイヤー6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>プレイヤー7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>プレイヤー8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>拡張</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation>コンソールモード</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation>接続</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation>接続解除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation>バイブレーション</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation>モーション</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation>コントローラ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation>1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation>2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation>3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation>4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation>5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation>6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation>7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation>8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation>接続</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation>デフォルト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation>消去</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>入力設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation>Joyconカラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation>プレイヤー1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation>L本体</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation>Lボタン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation>R本体</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation>Rボタン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation>プレイヤー2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation>プレイヤー3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation>プレイヤー4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation>プレイヤー5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation>プレイヤー6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation>プレイヤー7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation>プレイヤー8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation>その他</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation>キーボード</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation>拡張</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation>タッチスクリーン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation>マウス</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation>モーション / タッチ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation>設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation>コントローラのデバッグ</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>入力設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation>コントローラの接続</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation>プロコントローラ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation>デュアルジョイコン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation>ジョイコン左</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation>ジョイコン右</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation>携帯</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation>入力デバイス</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation>すべて</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation>キーボード / マウス</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation>プロファイル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation>セーブ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation>新規</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation>削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>左スティック</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation>上</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation>左</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation>右</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation>下</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation>押下</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation>変更</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation>範囲</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation>デッドゾーン:0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation>変更範囲:0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation>Dパッド</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation>L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation>ZL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation>マイナス</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation>キャプチャ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation>プラス</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation>ホーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation>R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation>ZR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation>SL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation>SR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>ボタン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation>B</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>右スティック</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation>デッドゾーン:%1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation>変更範囲:%1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation>[待機中]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation>モーション / タッチ設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation>モーション</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation>モーションプロバイダ:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation>感度:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation>タッチ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation>タッチプロバイダ:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation>キャリブレーション:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation>(100, 50) - (1800, 850)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation>設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation>ボタンマッピングの使用:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation>CemuhookUDP設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation>モーションとタッチ入力を提供するために、Cemuhook互換のUDP入力ソースを使用します。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation>サーバー:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation>ポート:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation>パッド:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation>パッド1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation>パッド2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation>パッド3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation>パッド4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation>詳細情報</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation>テスト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation>マウス(右クリック)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation>CemuhookUDP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation>エミュレータウィンドウ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;詳細情報&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation>テスト中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation>設定中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation>テスト成功</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation>サーバーからデータ受信成功</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation>テスト失敗</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation>サーバーから有効なデータを受信できませんでした。&lt;br&gt;サーバーが正しくセットアップされ、アドレスとポートが正しいことを確認してください。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation>Citra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation>UDPテスト、またはキャリブレーション設定が実行中です。&lt;br&gt;完了するまでお待ちください。</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>マウス設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>マウスボタン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>進む:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>戻る:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>左:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>中央:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>右:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>消去</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation>デフォルト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[未設定]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>デフォルトに戻す</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[キーを押す]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation>情報</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation>名称</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation>タイトルID</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation>ファイル名</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation>フォーマット</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation>バージョン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation>サイズ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation>開発者</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation>アドオン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation>全般</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation>システム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation>グラフィック</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation>拡張グラフィック</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation>オーディオ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation>プロパティ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation>共通設定を使用(%1)</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation>パッチ名称</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation>バージョン</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>プロファイルマネージャ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>現在のユーザー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>ユーザー名</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>画像を設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>追加</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>リネーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>プロファイル管理はゲームが実行されていない場合のみ可能です。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>ユーザー名を入力</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>ユーザー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>新しいユーザーのユーザー名を入力:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>新しいユーザー名を入力:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>削除確認</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>ユーザー名”%1”を削除しようとしています。間違いありませんか?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>ユーザー画像を選択 </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>JPEG画像 (*.jpg *.jpeg) </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>画像削除エラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>既存画像の上書き時にエラーが発生しました: %1 </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>ファイル削除エラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>ファイルを削除できませんでした: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>ユーザー画像ディレクトリ作成失敗</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>ユーザー画像保存ディレクトリ”%1”を作成できませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>ユーザー画像コピーエラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>画像を”%1”から”%2”へコピー出来ませんでした。</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>BCATは任天堂のゲームへのデータ送信方法であり、コミュニティに参加して追加コンテンツのロックを解除します。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation>BCATバックエンド</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;BCAT, Boxcat, 現在のイベントについての詳細情報&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation>Boxcatサービスはオフラインまたはインターネットに接続されていません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>Boxcatイベントデータを処理中にエラー発生しました。yuzu開発者に連絡してください。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>使用中のyuzuのバージョンは、サーバと比較して新しすぎまたは古すぎます。最新の公式リリースに更新してください。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation>Boxcatには現在イベントがありません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation>現在のBoxcatイベント</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation>yuzuが最新のBoxcat状況を取得中です...</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>システム設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation>リージョン:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation>自動</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation>デフォルト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation>CET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation>CST6CDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation>キューバ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation>EET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation>エジプト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation>アイルランド</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation>EST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation>EST5EDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation>GB-Eire</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation>GMT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation>GMT+0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation>GMT-0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation>GMT0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation>グリニッジ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation>香港</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation>HST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation>アイスランド</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation>イラン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation>イスラエル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation>ジャマイカ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation>日本</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation>クェゼリン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation>リビア</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation>MET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation>MST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation>MST7MDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation>ナバホ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation>NZ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation>NZ-CHAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation>ポーランド</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation>ポルトガル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation>PRC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation>PST8PDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation>ROC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation>ROK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation>シンガポール</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation>トルコ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation>UCT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation>ユニバーサル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation>UTC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation>W-SU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation>WET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation>ズールー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation>USA</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation>ヨーロッパ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation>オーストラリア</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation>中国</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation>韓国</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation>台湾</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation>タイムゾーン:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>注意:地域設定が自動選択の場合、設定が上書きされる可能性があります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>日本(日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>英語</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>フランス(フランス語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>ドイツ(ドイツ語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>イタリア(イタリア語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>スペイン(スペイン語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>中国</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>韓国(韓国語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>オランダ(オランダ語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>ポルトガル(ポルトガル語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>ロシア(ロシア語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>台湾</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>イギリス</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>カナダ・フランス語</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>ラテンアメリカ・スペイン語</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>簡体字中国語</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>繁体字中国語(正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>カスタムRTC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>言語</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>RNG速度</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>モノラル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>ステレオ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>サラウンド</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>コンソールID:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>サウンド出力モード</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation>d MMM yyyy h:mm:ss AP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>再作成</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>システム設定はゲームが実行されていない場合のみ可能です。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>現在の仮想スイッチが新しいものに置換されます。現在の仮想スイッチは復旧できません。ゲームに予期せぬ影響を与える可能性があります。古い設定などを使うと失敗するかもしれません。続行しますか?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>警告</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>コンソールID: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation>タッチスクリーンマッピング設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation>マッピング:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation>新規</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation>削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation>リネーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation>下の領域をクリックしてポイントを追加し、ボタンを押してバインドします。
+ポイントをドラッグして位置を変更するか、テーブルのセルをダブルクリックして値を編集します。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation>ポイント削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation>ボタン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation>新規プロファイル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation>新規プロファイルの名称を入力</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation>プロファイル削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation>プロファイル%1を削除しますか?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation>プロファイルリネーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation>新規名称:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation>[キーを押す]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>タッチスクリーン設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>警告:このページの設定は、yuzuのタッチスクリーンエミュレートの内部動作に影響します。これらを変更すると、タッチスクリーンが部分的に機能しなくなったりするなど、望ましくない動作が生じる可能性があります。それらを理解した上で、このページを使用してください。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>タッチパラメータ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>タッチ直径Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>指</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>タッチ直径X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>回転角</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>デフォルトに戻す</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>全般</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>注意:言語を変更した時点で、設定が適用されます。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>UI言語:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>テーマ:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>ゲームリスト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>アドオン列を表示</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>アイコンサイズ:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>1行目:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>2行目:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation>スクリーンショット</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation>スクリーンショットの保存場所を確認する(Windowsのみ)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation>スクリーンショットパス:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation>スクリーンショットパスを選択...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>英語</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>yuzu Webサービス</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>ユーザー名とトークンを入力すると、yuzuがユーザー識別情報を含む可能性がある追加の統計情報データを収集することを許可することに同意したと見なされます。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>検証</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>サインアップ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>トークン:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>ユーザー名:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>私のトークンはなんですか?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>テレメトリ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>匿名統計情報データをyuzuチームと共有</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>詳細情報</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>テレメトリID:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>再作成</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Discordプレゼンス</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Discordステータスに実行中のゲームを表示</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;詳細情報&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;サインアップ&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;私のトークンはなんですか?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>テレメトリID:0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>未設定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>トークンは検証されていません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>トークンは検証されていません。トークンの変更はまだ保存されていません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>検証中...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>検証失敗</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>検証に失敗しました。トークンを正しく入力したこと、およびインターネット接続が機能していることを確認してください。</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>yuzuを改善するための&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;匿名データが収集されました&lt;/a&gt;。&lt;br/&gt;&lt;br/&gt;統計情報データを共有しますか?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>テレメトリ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>テキストチェック失敗</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation>Webアプレットをロード中...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation>Webアプレットを終了する</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>終了</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation>Webアプリケーションを終了するには、ゲームが提供する&quot;終了&quot;を選択するか、メニューの&quot;Webアプレットを終了する&quot;を選択するか、&quot;Enter&quot;キーを押してください。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation>Webアプレット</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>使用中のyuzuはQtWebEngineをサポートしていないため、ゲームの説明書やWebページを正しく表示できません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation>ビルド中のシェーダー数</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>現在のエミュレーション速度。値が100%より高いか低い場合、エミュレーション速度がSwitchより速いか遅いことを示します。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>ゲームが現在表示している1秒あたりのフレーム数。これはゲームごと、シーンごとに異なります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Switchフレームをエミュレートするのにかかる時間で、フレームリミットやV-Syncは含まれません。フルスピードエミュレーションの場合、最大で16.67ミリ秒になります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation>DOCK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation>ASYNC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation>MULTICORE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation>VULKAN</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation>OPENGL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>最近使用したファイルを消去</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>古いゲームフォーマットの警告</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>このゲームでは、分解されたROMディレクトリフォーマットを使用しています。これは、NCA、NAX、XCI、またはNSPなどに取って代わられた古いフォーマットです。分解されたROMディレクトリには、アイコン、メタデータ、およびアップデートサポートがありません。&lt;br&gt;&lt;br&gt;yuzuがサポートするSwitchフォーマットの説明については、&lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;wikiをチェックしてください&lt;/a&gt;。このメッセージは二度と表示されません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>ROMロード中にエラーが発生しました!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>このROMフォーマットはサポートされていません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>ビデオコア初期化中にエラーが発生しました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>ビデオコアの実行中にyuzuでエラーが発生しました。詳細については、ログを参照してください。ログへのアクセスの詳細については、次のページを参照してください:&lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;ログファイルをアップロードする方法&lt;/a&gt;。最新のグラフィックドライバを使用していることを確認して下さい。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation>ROMロードエラー!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>不明なエラーが発生しました。詳細はログを確認して下さい。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>開始</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>データのセーブ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Modデータ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>”%1”フォルダを開けませんでした</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>フォルダが存在しません!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>シェーダキャッシュを開けませんでした</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>このタイトル用のシェーダキャッシュは存在しません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation>コンテンツ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation>アップデート</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation>DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation>エントリ削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation>インストールされているゲーム%1を削除しますか?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation>削除成功</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation>インストールされたゲームを正常に削除しました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation>%1削除エラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation>ゲームはNANDにインストールされておらず、削除できません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation>インストールされたアップデートを正常に削除しました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation>このタイトルのアップデートはインストールされていません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation>このタイトルにはDLCがインストールされていません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation>%1にインストールされたDLCを正常に削除しました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation>転送可能なシェーダーキャッシュを削除しますか?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation>カスタムゲーム設定を削除しますか?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation>ファイル削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation>転送可能なシェーダーキャッシュの削除エラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation>転送可能なシェーダーキャッシュが正常に削除されました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation>転送可能なシェーダーキャッシュを削除できませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation>カスタム設定の削除エラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation>このタイトルのカスタム設定は存在しません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation>カスタムゲーム設定を正常に削除しました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation>カスタムゲーム設定の削除に失敗しました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>RomFSの解析に失敗しました!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>RomFSファイルをコピー中にエラーが発生したか、ユーザー操作によりキャンセルされました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>フル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation>スケルトン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>RomFSダンプモードの選択</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>RomFSのダンプ方法を選択してください。&lt;br&gt;”完全”はすべてのファイルが新しいディレクトリにコピーされます。&lt;br&gt;”スケルトン”はディレクトリ構造を作成するだけです。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>RomFSを解析中・・・</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>RomFS解析成功!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>操作は成功しました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>”%1”を開けませんでした</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>ディレクトリの選択</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>プロパティ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>ゲームプロパティをロード出来ませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Switch実行ファイル (%1);;すべてのファイル (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>ファイルのロード</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>展開されているROMディレクトリを開く</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>無効なディレクトリが選択されました</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>選択されたディレクトリに”main”ファイルが見つかりませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation>インストール可能なスイッチファイル (*.nca *.nsp *.xci);;任天堂コンテンツアーカイブ (*.nca);;任天堂サブミッションパッケージ (*.nsp);;NXカートリッジイメージ (*.xci)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation>ファイルのインストール</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>&quot;%1&quot;ファイルをインストールしています・・・</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation>インストール結果</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>システムアプリケーション</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>システムアーカイブ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>システムアプリケーションアップデート</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>ファームウェアパッケージ(Type A)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>ファームウェアパッケージ(Type B)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>ゲーム</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>ゲームアップデート</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>ゲームDLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>差分タイトル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>NCAインストール種別を選択・・・</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>インストールするNCAタイトル種別を選択して下さい:
+(ほとんどの場合、デフォルトの”ゲーム”で問題ありません。)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>インストール失敗</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>選択されたNCAのタイトル種別が無効です。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>ファイルが存在しません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>ファイル”%1”が存在しません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>続行</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>表示エラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>yuzuアカウントが存在しません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>ゲームの互換性テストケースを送信するには、yuzuアカウントをリンクする必要があります。&lt;br&gt;&lt;br/&gt;yuzuアカウントをリンクするには、エミュレーション > 設定 > Web から行います。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation>URLオープンエラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation>URL&quot;%1&quot;を開けません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>amiiboファイル (%1);;すべてのファイル (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>amiiboのロード</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>amiiboデータファイルを開けませんでした</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>amiiboデータファイル”%1”を読み込めませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>amiiboデータファイルを読み込み中にエラーが発生した</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>amiiboデータを完全には読み取ることができませんでした。%1バイトを読み込もうとしましたが、%2バイトしか読み取れませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>amiiboデータ読み込み中にエラーが発生しました</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>amiiboデータをロードできませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>スクリーンショットのキャプチャ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG画像 (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>速度:%1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>速度:%1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>ゲーム:%1 FPS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>フレーム:%1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>ロードしようとしているゲームはプレイする前にスイッチからダンプされた追加のファイルを必要とします。&lt;br/&gt;&lt;br/&gt;これらのファイルのダンプの詳細については、次のWikiページを参照してください:&lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;スイッチコンソールからのシステムアーカイブと共有フォントをダンプする&lt;/a&gt;。&lt;br/&gt;&lt;br/&gt;ゲームリストに戻りますか?エミュレーションを続けると、クラッシュ、保存データの破損、またはその他のバグが発生する可能性があります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>yuzuはSwitchのシステムアーカイブ &quot;%1&quot; を見つけられませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>yuzuはSwitchのシステムアーカイブ &quot;%1&quot; &quot;%2&quot; を見つけられませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>システムアーカイブが見つかりません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>システムアーカイブが見つかりません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>yuzuはSwitchの共有フォント &quot;%1&quot; を見つけられませんでした。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>共有フォントが存在しません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>共有フォントが存在しません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>致命的なエラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>yuzuが致命的なエラーを検出しました。詳細については、ログを参照してください。ログへのアクセスの詳細については、次のページを参照してください。&lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;ログファイルをアップロードする方法&lt;/a&gt;。&lt;br/&gt;&lt;br/&gt;ゲームリストに戻りますか?エミュレーションを続けると、クラッシュ、保存データの破損、またはその他のバグが発生する可能性があります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>致命的なエラー発生</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>キーの再取得確認</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>すべてのキーを再作成しようとしています。
+これが何を意味するのか分からない場合、または何をしようとしているのか分からない場合、
+これは破壊的な可能性がある実行です。
+これがあなたが望むものであることを確認し、
+そしてオプションでバックアップを作成します。
+
+これにより、自動生成されたキーファイルが削除され、キー導出モジュールが再実行されます。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation>ヒューズがありません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation> - BOOT0がありません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation> - BCPKG2-1-Normal-Mainがありません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation> - PRODINFOがありません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation>派生コンポーネントがありません</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation>コンポーネントが見つからず、キーの導出が完了しない可能性があります。&lt;br&gt;ゲームとキーを取得するために、&lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;yuzuクイックスタートガイド&lt;/a&gt;の手順に従って下さい。&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>キーを作成中...
+システムのパフォーマンスによっては
+1分以上かかります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>派生キー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>RomFSダンプターゲットの選択</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>ダンプしたいRomFSを選択して下さい。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>yuzuを終了してもよろしいですか?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>エミュレーションを停止してもよろしいですか?セーブされていない進行状況は失われます。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>現在動作中のアプリケーションはyuzuに終了しないよう要求しています。
+
+無視してとにかく終了しますか?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation>OpenGLは使用できません!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation>yuzuはOpenGLサポート付きでコンパイルされていません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation>Vulkanは使用できません!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation>yuzuはVulkanサポート付きでコンパイルされていません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation>OpenGL4.3初期化エラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation>GPUがOpenGL 4.3をサポートしていないか、最新のグラフィックスドライバーではありません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation>OpenGL初期化エラー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation>GPUが1つ以上の必要なOpenGL拡張機能をサポートしていない可能性があります。最新のグラフィックドライバを使用していることを確認してください。&lt;br&gt;&lt;br&gt;サポートされていない拡張機能:&lt;br&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>名称</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>互換性</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>アドオン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>ファイル種別</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>サイズ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>セーブデータディレクトリを開く</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Modデータディレクトリを開く</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>シェーダキャッシュを開く</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation>削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation>インストールされているアップデートを削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation>全てのインストールされているDLCを削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation>シェーダーキャッシュを削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation>カスタム設定を削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation>全てのインストールされているコンテンツを削除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>RomFSをダンプ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>タイトルIDをクリップボードへコピー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>GameDBエントリを表示</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>プロパティ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>サブフォルダをスキャンする</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>ゲームディレクトリを削除する</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation>▲ 上へ移動</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation>▼ 下へ移動</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>ディレクトリの場所を開く</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>パーフェクト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>ゲームはオーディオ、またはグラフィックの不具合なしで完璧に動作し、回避策なしで期待通りに動作します。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>グレート</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>ゲームの動作にはグラフィック、またはオーディオの軽微な不具合がありますが、最初から最後までプレイ可能です。いくつかの回避策が必要な場合があります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>ゲームの動作にはグラフィック、またはオーディオの重大な不具合がありますが、回避策を使うことで最初から最後までプレイ可能です。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>NG</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>ゲームは動作しますが、グラフィック、またはオーディオに重大な不具合があります。回避策を使用しても不具合が原因で特定の場所から進めなくなります。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>イントロ/メニュー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>グラフィック、またはオーディオの重大な不具合のため、ゲームはプレイ不可能です。スタート画面から先に進めることは出来ません。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>起動せず</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>ゲームは起動時にクラッシュしました。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>未テスト</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>ゲームはまだテストされていません。</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>新しいゲームリストフォルダを追加するにはダブルクリックしてください。</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>フィルター:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>フィルターパターンを入力</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation>これらがインストールするファイルであることを確認してください。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation>アップデート、またはDLCをインストールすると、以前にインストールしたものが上書きされます。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation>インストール</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation>ファイルをNANDへインストール</translation>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>シェーダをロード中 387 / 1628</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>シェーダをロード中 %v / %m</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>予想時間 5分4秒</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>ロード中...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>シェーダをロード中 %1 / %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>起動中...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>予想時間 %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>ファイル(&amp;F)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>最近使用したファイル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>エミュレーション(&amp;E)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>表示(&amp;V)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>デバッグ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>ツール</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>ヘルプ(&amp;H)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation>ファイルをNANDへインストール...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>ファイルをロード...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>フォルダをロード...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>終了(&amp;E)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>実行(&amp;S)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>中断(&amp;P)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>停止(&amp;S)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>キーの再初期化...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>yuzuについて</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>単一ウィンドウモード</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>設定...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>ドックウィジェットヘッダーの表示</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>フィルターバーの表示</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>ステータスバーの表示</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation>ウィンドウサイズをリセット</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>フルスクリーン</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>再起動</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>amiiboをロード...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>互換性を報告</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation>Modページを開く</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation>クイックスタートガイドを開く</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation>FAQ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>yuzuディレクトリを開く</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>スクリーンショットをキャプチャ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation>現在のゲームの設定...</translation>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>マイクロプロファイル</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>インストール済みSDタイトル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>インストール済みNANDタイトル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>システムタイトル</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>新しいゲームディレクトリを追加する</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[未設定]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>十字キー %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>軸 %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>ボタン %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[不明]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation>クリック0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation>クリック1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation>クリック2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation>クリック3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation>クリック4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation>GC Axis %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation>GC Button %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[未使用]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>軸 %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation>GC Axis %1</translation>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>エラーが発生しました。
+もう一度試す、またはソフト開発者に連絡してください。
+
+エラーコード: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>%2 の %1 でエラーが発生しました。
+もう一度試す、またはソフト開発者に連絡してください。
+
+エラーコード: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>エラーが発生しました。
+エラーコード: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>ユーザー選択:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>ユーザー</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>プロファイル選択</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>テキストを入力:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>ソフトウェアキーボード</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>ホットキーを入力</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>コールスタック</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>ミューテックス 0x%1 待ち</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>待機:%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>オーナーハンドル: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>全オブジェクト待ち</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>以下のオブジェクトのうちの一つを待機中</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation>[%1]%2 %3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation>スレッドなしで待機</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>実行中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>準備完了</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>中断</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>HLEリターン待ち</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>休止中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>IPC返答待ち</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>オブジェクト待ち</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>ミューテックス待ち</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>条件変数待ち</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>アドレス決定待ち</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>休止</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>死亡</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation> PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>理想的</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>コア %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>不明なプロセッサ %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>プロセッサ = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>イデアルコア = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>アフィニティマスク = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>スレッドID = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>優先度 = %1(現在) / %2(通常)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>最終実行刻み = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>ミューテックス待ちではない</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>スレッドによる待機</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>待ちツリー</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/nl.ts b/dist/languages/nl.ts
new file mode 100644
index 000000000..0f5178458
--- /dev/null
+++ b/dist/languages/nl.ts
@@ -0,0 +1,4719 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="nl" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>Over yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu is een experimentele open-bron emulator voor de Nintendo Switch, in licentie gegeven onder GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;De software zou niet gebruikt moeten worden om games te spelen die je niet legaal verkregen hebt.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Broncode&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Bijdragers&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licentie&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is een handelsmerk van Nintendo. yuzu is op geen enkele manier met Nintendo verbonden.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation>Communiceren met de server...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>Rapporteer Compatibiliteit</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>Rapporteer Game Compatibiliteit</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Als je kiest een test case op te sturen naar de &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu compatibiliteitslijst&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, zal de volgende informatie worden verzameld en getoond op de site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Informatie (CPU / GPU / Besturingssysteem)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Welke versie van yuzu je draait&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Het verbonden yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>Perfect</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;De game werkt foutloos, zonder geluid of grafische problemen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>Goed</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game werkt met kleine grafische of geluid problemen en is speelbaar van start tot eind. Kan enkele tijdelijke oplossingen nodig hebben.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game werkt met grote grafische of geluid problemen, maar is speelbaar van start tot eind met tijdelijke oplossingen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>Slecht</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game werkt, maar met grote grafische of geluid problemen. Specifieke gebieden kunnen niet worden uitgespeeld vanwege problemen, zelfs met tijdelijke oplossingen. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is compleet onspeelbaar dankzij grote grafische of geluid problemen. Onmogelijk voorbij het startscherm te komen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Start Niet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;De game crasht wanneer je het probeert op te starten.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Onafhankelijk van snelheid of prestaties, Hoe goed speelt de game van start tot eind op deze versie van yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>Bedankt voor je inzending!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>Inzenden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>Communicatiefout</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>Er was een fout tijdens het insturen van de Testcase.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>Volgende</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>Geluid</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>Output Engine:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>Dit nabewerkings effect past de snelheid van het geluid zodanig aan dat de snelheid van de emulatie en van het geluid op elkaar afgestemd zijn. Dit zorgt er wel voor dat de latency van het geluid hoger word.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>Geluid Rekking Aanzetten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>Geluid Apparaat:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>Volume:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>GDB Stub Aanzetten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>Poort:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>Loggen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>Globale Log Filter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>Laat Log Venster Zien (Alleen voor Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>Open Log Locatie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>Homebrew</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>Argumenten Rij</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>Gebruik Uitgebreide Rapporteer Services</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>Deze optie hersteld wanneer je yuzu afsluit.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>Geavanceerd</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation>Kiosk (Quest) Modus</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>yuzu Configuratie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>Algemeen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>UI</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>Game Lijst</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>Systeem</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>Profielen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>Bestandssysteem</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>Bediening</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>Sneltoetsen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>Debug</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>Grafisch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>Geluid</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Web</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>Services</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>Opslag Folders</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>SD Kaart</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>Gamekaart</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>Pad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>Ingevoerd</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>Huidig Spel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>Patch Beheer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>Dump Uitgepakte NSO&apos;s</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>Dump ExeFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation>Mod Laad Root</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation>Dump Root</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>Caching</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>Cache Folder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation>Cache Spel Lijst Metadata</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>Herstel Metadata Cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>Selecteer Geëmuleerde NAND Folder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>Selecteer Geëmuleerde SD Folder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation>Selecteer Gamekaart Pad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>Selecteer Dump Folder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation>Selecteer Mod Laad Folder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>Selecteer Cache Folder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>De metadata cache is al leeg.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>De operatie is succesvol voltooid.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>De metadata cache kon niet worden verwijderd. Het wordt mogelijk gebruikt of bestaat niet.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>Algemeen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>Limiteer Snelheid Percentage</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>Bevestig sluiten terwijl emulatie nog bezig is</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation>Vraag voor gebruiker bij het opstartten van het spel.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>Pauzeer Emulatie wanneer yuzu op de achtergrond openstaat</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>Gebruik schijf shader cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>Gebruik asynchroon GPU emulatie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>Achtergrondkleur:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>Sneltoets Instellingen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation>Dubbel-klik op een binding om het te veranderen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>Actie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>Sneltoets</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>Context</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>Ongeldige Toets Volgorde</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>Speler 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>Speler 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>Speler 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>Speler 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>Speler 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>Speler 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>Speler 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>Speler 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>Geavanceerd</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>Configureer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Configureer Invoer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>Linker Stick</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>Gezicht Knoppen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>Rechter Stick</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>Configureer Muis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>Muisknoppen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>Voorwaarts:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>Terug:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>Links:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>Middel:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>Rechts:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>Herstellen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[niet ingesteld]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>Herstel Standaardwaarde</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[druk op knop]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>Profiel Beheer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>Huidige Gebruiker</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>Gebruikersnaam</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>Selecteer Afbeelding</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>Voeg Toe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>Hernoem</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>Verwijder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>Profiel beheer is alleen beschikbaar wanneer het spel niet bezig is.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>Voer een Gebruikersnaam in</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>Gebruikers</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>Voer een gebruikersnaam in voor de nieuwe gebruiker:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>Voer nieuwe gebruikersnaam in:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>Bevestig Verwijdering</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>Je staat op het punt een gebruiker met de naam &quot;%1&quot; te verwijderen. Weet je het zeker?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>Selecteer gebruiker&apos;s foto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>JPEG foto&apos;s (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>Fout tijdens verwijderen afbeelding</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>Er is een fout opgetreden bij het overschrijven van de vorige afbeelding in: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>Fout tijdens verwijderen bestand</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>Kan bestaand bestand niet verwijderen: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>Fout tijdens het maken van de map met afbeeldingen van de gebruiker</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>Fout tijdens het maken van map %1 om gebruikersafbeeldingen in te bewaren.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>Fout tijdens het kopiëren van de gebruiker afbeelding</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>Kan afbeelding niet kopiëren van %1 naar %2</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>BCAT is Nintendo&apos;s manier om informatie naar games te versturen om de gemeenschap te stimuleren of om nieuwe inhoud te ontgrendelen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation>BCAT Backend</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Leer meer over BCAT, Boxcat, en actuele Evenementen&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation>De boxcat service is offline of je bent niet verbonden met het internet.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>Er was een fout tijdens het processen van de boxcat evenement data. Contacteer de yuzu ontwikkelaars.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>De versie van yuzu die je gebruikt is te nieuw of te oud voor de server. Probeer te updaten naar de nieuwste officiële release van yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation>Er zijn momenteel geen evenementen op boxcat.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation>Yuzu haalt de laatste boxcat-status op...</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>Systeeminstellingen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>Noot: dit kan worden overschreven wanneer de regio instelling op automatisch selecteren staat.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>Japans (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>Engels (English)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>Frans (Français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>Duits (Deutsch)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>Italiaans (italiano)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>Spaans (Español)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>Chinees (正體中文 / 简体中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>Koreaans (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>Nederlands (Nederlands)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>Portugees (português)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>Russisch (Русский)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>Taiwanese</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>Brits Engels</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>Canadees Frans</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>Latijns Amerikaans Spaans</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>Vereenvoudigd Chinees</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>Traditioneel Chinees (正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>Handmatige RTC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>Taal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>RNG Seed</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>Mono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>Stereo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>Surround</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>Console ID:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>Geluid uitvoer mode</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation>d MMM jjjj u:mm:ss AP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>Herstel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>Systeeminstellingen zijn enkel toegankelijk wanneer er geen game draait.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>Dit vervangt je huidige virtuele Switch met een nieuwe. Je huidige virtuele Switch kan dan niet meer worden hersteld. Dit kan onverwachte effecten hebben in spellen. Dit werkt niet als je een oude config savegame gebruikt. Doorgaan?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>Waarschuwing</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>Console ID: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>Configureer Touchscreen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>Waarschuwing: Instellingen in deze pagina hebben invloed op de interne werking van yuzu&apos;s geemuleerde touchscreen. Veranderingen kunnen ongewenste resultaten hebben, zoals ervoor zorgen dat het touchscreen half of niet werkt. Gebruik deze pagina enkel als je weet wat je doet.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>Touch Parameters</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>Touch Diameter Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>Vinger</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>Touch Diameter X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>Rotatiehoek</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>Herstel Standaardwaardes</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>Algemeen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>Notitie: De taal veranderen past uw configuratie toe.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>Interface taal:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>Thema:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>Game Lijst</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>Toon Add-Ons Kolom</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>Icoon Grootte:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>Rij 1 Text:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>Rij 2 Text:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>Engels</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>yuzu Web Service</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>Door je gebruikersnaam en token te geven, ga je akkoord dat yuzu extra gebruiksdata verzameld, waaronder mogelijk gebruikersidentificatie-informatie.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>Verifieer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>Registreer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>Token:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>Gebruikersnaam:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>Wat is mijn token?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>Telemetrie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>Deel anonieme gebruiksdata met het yuzu team</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>Leer meer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>Telemetrie ID:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>Regenereer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Discord Presence</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Toon huidige game in je Discord status</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Leer meer&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Registreer&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Wat is mijn token?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>Telemetrie ID: 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>Niet gespecificeerd</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>Token niet geverifieerd</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>Token is niet geverifieerd. De verandering aan uw token zijn niet opgeslagen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>Verifiëren...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>Verificatie mislukt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>Verificatie mislukt. Check dat uw token correct is en dat uw internet werkt.</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Annonieme gegevens worden verzameld&lt;/a&gt; om yuzu te helpen verbeteren. &lt;br/&gt;&lt;br/&gt; Zou je jouw gebruiksgegevens met ons willen delen?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>Telemetrie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>Tekst Check Is Gefaald</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation>Web Applet Laden...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation>Web Applet Afsluit</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>Afsluiten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation>Om de webtoepassing af te sluiten, gebruik de bedieningselementen van het spel om afsluiten te selecteren, selecteer de optie &apos;Web Applet Afsluiten&apos; in de menubalk of druk op de &apos;Enter&apos; toets.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation>Web Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>Deze versie van yuzu is gebouwd zonder ondersteuning van QtWebEngine, wat betekent dat yuzu de gevraagde spelhandleiding of webpagina niet correct kan weergeven.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>Huidige emulatie snelheid. Waardes hoger of lager dan 100% betekent dat de emulatie sneller of langzamer loopt dan de Switch.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>Hoeveel frames per seconde de game op dit moment weergeeft. Dit zal veranderen van game naar game en van scène naar scène.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Tijd gebruikt om een frame van de Switch te emuleren, waarbij framelimiteren of v-sync niet wordt meegerekend. Voor emulatie op volledige snelheid zou dit maximaal 16.67 ms zijn.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>Recente Bestanden Verwijderen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>Waarschuwing Verouderd Spel Formaat</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>Je gebruikt gedeconstrueerd ROM map formaat voor dit Spel, dit is een verouderd formaat en is vervangen door formaten zoals NCA, NAX, XCI of NSP. Gedeconstrueerd ROM map heeft geen iconen, metadata en update understeuning.&lt;br&gt;&lt;br&gt;Voor een uitleg over welke Switch formaten yuzu ondersteund, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;kijk op onze wiki&lt;/a&gt;. Dit bericht word niet nog een keer weergegeven.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>Fout tijdens het laden van een ROM!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>Het formaat van de ROM is niet ondersteunt.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>Er is een fout opgetreden tijdens het initialiseren van de videokern.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>yuzu is een fout tegengekomen tijdens het uitvoeren van de video kern, kijk alstublieft naar de log for meer details. Voor meer informatie op het vinden van de log, kijk alstublieft naar de volgende pagina : &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;hoe upload je een log bestand&lt;/a&gt;. Bevestig dat je dat laaste grafische driver hebt voor je GPU.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>Een onbekende fout heeft plaatsgevonden. Kijk in de log voor meer details.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>Start</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>Save Data</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Mod Data</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>Fout tijdens het openen van %1 folder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>Folder bestaat niet!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>Fout Bij Het Openen Van Overdraagbare Shader Cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>Er bestaat geen shader cache voor deze game</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>RomFS Extractie Mislukt!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>Er was een fout tijdens het kopiëren van de RomFS bestanden of de gebruiker heeft de operatie geannuleerd.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>Vol</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation>Skelet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>Selecteer RomFS Dump Mode</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>Selecteer alstublieft hoe je de RomFS wilt dumpen.&lt;br&gt;Volledig kopieërd alle bestanden in een map terwijl &lt;br&gt; skelet maakt alleen het map structuur.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>RomFS uitpakken...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>RomFS Extractie Geslaagd!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>De operatie is succesvol voltooid.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>Fout bij openen %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>Selecteer Map</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>Eigenschappen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>De eigenschappen van de game kunnen niet geladen worden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Switch Executable (%1);;Alle bestanden (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>Laad Bestand</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>Open Gedecomprimeerd ROM Map</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>Ongeldige Map Geselecteerd</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>De map die je hebt geselecteerd bevat geen &apos;main&apos; bestand.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>Bestand &quot;%1&quot; Installeren...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>Systeem Applicatie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>Systeem Archief</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>Systeem Applicatie Update</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>Filmware Pakket (Type A)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>Filmware Pakket (Type B)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>Game</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>Game Update</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>Game DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>Delta Titel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>Selecteer NCA Installatie Type...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>Selecteer het type titel hoe je wilt dat deze NCA installeerd:
+(In de meeste gevallen is de standaard &apos;Game&apos; juist.)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>Installatie Mislukt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>Het type title dat je hebt geselecteerd voor de NCA is ongeldig.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>Bestand niet gevonden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>Bestand &quot;%1&quot; niet gevonden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>Doorgaan</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>Fout Weergave</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>Je yuzu account mist</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>Om game campatibiliteit te raporteren, moet je je yuzu account koppelen.&lt;br&gt;&lt;br/&gt; Om je yuzu account te koppelen, ga naar Emulatie &amp;gt; Configuratie &amp;gt; Web.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>Amiibo Bestand (%1);; Alle Bestanden (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>Laad Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>Fout tijdens het openen van het Amiibo gegevens bestand</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>Kan Amiibo bestand &quot;%1&quot; niet lezen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>Fout tijdens het lezen van het Amiibo gegevens bestand</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>Kan de volledige Amiibo gegevens niet lezen. Verwacht om %1 bytes te lezen, maar het is alleen mogelijk om %2 bytes te lezen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>Fout tijdens het laden van de Amiibo data</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>Kan de Amiibo gegevens niet laden.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>Screenshot Vastleggen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG afbeelding (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>Snelheid: %1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>Snelheid: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>Game: %1 FPS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>Frame: %1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>De game die je probeert te laden heeft extra bestanden nodig van je Switch voordat je het kan spelen. &lt;br/&gt;&lt;br/&gt;Voor meer informatie over het dumpen van deze bestanden, volg alsjeblieft onze wiki pagina: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Het dumpen van Systeem Archieven en de Gedeelde Lettertypen van een Switch console &lt;/a&gt;. &lt;br/&gt;&lt;br/&gt;Wil je terug gaan naar de game lijst? Verdergaan met de emulatie zal misschien gevolgen hebben als vastlopen, beschadigde opslag data, of andere problemen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>yuzu was niet in staat om de Switch systeem archieven te vinden. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>yuzu was niet in staat om de Switch systeem archieven te vinden. %1. %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>Systeem Archief Niet Gevonden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>Systeem Archief Mist</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>yuzu was niet in staat om de Switch shared fonts te vinden. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>Shared Fonts Niet Gevonden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>Gedeelde Lettertypes Niet Gevonden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>Fatale Fout</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>yuzu is een fatale fout tegengekomen, zie de log voor meer details. Voor meer informatie over toegang krijgen tot de log, zie de volgende pagina: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Hoe upload je een log bestand&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Zou je terug willen naar de game lijst? Doorgaan met emulatie kan resulteren in vastlapen, corrupte save gegevens, of andere problemen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>Fatale Fout opgetreden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>Bevestig Sleutel Herafleiding</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>Je bent op het punt al je sleutels geforceerd opnieuw te verkrijgen.
+Als je niet weet wat dit doet of wat je aan het doen bent,
+dit is potentieel een vernietigende actie.
+Zorg ervoor dat je zeker weet dat dit is wat je wilt doen
+en optioneel maak backups.
+
+Dit zal je automatisch gegenereerde sleutel bestanden verwijderen en de sleutel verkrijger module opnieuw starten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>Dit zal misschien een paar minuten duren gebaseerd
+op je systeem&apos;s performatie.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>Sleutels afleiden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>Selecteer RomFS Dump Doel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>Selecteer welke RomFS je zou willen dumpen.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>Weet je zeker dat je yuzu wilt sluiten?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>Weet je zeker dat je de emulatie wilt stoppen? Alle onopgeslagen voortgang will verloren gaan.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>De momenteel actieve toepassing heeft yuzu gevraagd om niet af te sluiten.
+
+Wilt u dit omzeilen en toch afsluiten?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>Naam</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>Compatibiliteit</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>Toevoegingen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>Bestands type</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>Grootte</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>Open Locatie Van Save Gegevens </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Open Mod Data Locatie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>Open Overdraagbare Shader Cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>Dump RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>Kopieer Titel ID naar Klembord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>Navigeer naar GameDB inzending</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>Eigenschappen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>Scan Subfolders</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>Verwijder Game Directory</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>Open Directory Locatie</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>Perfect</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>Game functioneerd foutloos, zonder auditieve of grafische glitches. Alle geteste functionaliteit werkt zoals bedoeld zonder dat er tijdelijke oplossingen nodig zijn.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>Goed</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>Game werkt met kleine grafische of auditieve glitches en is speelbaar van start tot eind. Kan enkele workarounds nodig hebben.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>Okay</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>Game werkt met grove grafische of auditieve glitches, maar is speelbaar van start tot eind met workarounds</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>Slecht</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>Game werkt, maar met grove grafische of auditieve glitches. Specifieke gebieden kunnen niet worden uitgespeeld vanwege glitches, zelfs met workarounds.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>Game is compleet onspeelbaar dankzij grove grafische of auditieve glitches. Onmogelijk voorbij het startscherm te gaan.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Start Niet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>De Game crasht wanneer hij probeert op te starten.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>Niet Getest</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>Deze Game is nog niet getest.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>Dubbel-klik om een ​​nieuwe map toe te voegen aan de lijst met games</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>Filter:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>Voer patroon in om te filteren:</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>Shaders Laden 387 / 1628</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>%v Shaders Laden van de %m</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>Geschatte Tijd 5m 4s</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>Laden...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>Shaders Laden %1 / %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>Starten...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>Geschatte Tijd %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>&amp;Bestand</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>Recente Bestanden</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>&amp;Emulatie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>&amp;Weergeven</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>Debugging</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>Hulpmiddelen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>&amp;Help</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>Laad Bestand...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>Laad Folder...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>A&amp;fsluiten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>&amp;Start</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>&amp;Pauzeren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>&amp;Stop</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>Sleutels opnieuw initialiseren...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>Over yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>Enkel Venster Modus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>Configureren...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>Dock Widget Rubriek Weergeven</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>Laat filter balk zien</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>Laat status balk zien</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>Volledig Scherm</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>Herstart</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>Laad Amiibo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>Raporteer Compatibiliteit</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>Open yuzu Folder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>Screenshot Vastleggen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>MicroProfiel</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>Geïnstalleerde SD Titels</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>Geïnstalleerde NAND Titels</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>Systeem Titels</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>Voeg Nieuwe Game Map Toe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[niet aangegeven]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>Hat %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>Axis %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>Knop %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[onbekend]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[ongebruikt]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>Axis %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>Er is een fout opgetreden.
+Probeer het opnieuw of neem contact op met de ontwikkelaar van de software.
+
+Fout Code: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>Er is een fout opgetreden bij %1 en %2.
+Probeer het opnieuw of neem contact op met de ontwikkelaar van de software.
+
+Fout Code: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>Er is een fout opgetreden.
+Fout Code: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>Selecteer een gebruiker:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>Gebruikers</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>Profiel keuzeschakelaar</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>Voer tekst in:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>Software Toetsenbord</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>Voer een hotkey in</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>Call stack</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>wachten op mutex 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>heeft wachtende: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>eigenaar handvat: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>wachten op alle objecten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>wachten op een van de volgende objecten</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>Bezig met uitvoeren</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>klaar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>gepauzeerd</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>wachten op HLE terugkeer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>slapen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>wachten op IPC antwoord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>wachten op objecten</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>wachten op mutex</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>wachten op conditie variabele</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>wachten op adres arbiter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>slapend</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>dood</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation> PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>ideaal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>kern %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>Onbekende processor %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>processor = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>ideale kern = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>affiniteit masker = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>draad id = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>prioriteit = %1(huidige) / %2(normaal)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>laatste lopende ticks = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>Niet wachtend op mutex</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>Wachtend door draad</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>Wacht Boom</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/pl.ts b/dist/languages/pl.ts
new file mode 100644
index 000000000..4cd9b6fca
--- /dev/null
+++ b/dist/languages/pl.ts
@@ -0,0 +1,4713 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="pl" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>O yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu jest eksperymentalnym emulatorem o otwartym kodzie źródłowym dla Nintendo Switch w ramach licencji GLPv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;To oprogramowanie nie powinno być używane do gier, których nie nabyłeś legalnie.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Strona&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kod źródłowy&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Współautorzy&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licencja&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; jest znakiem towarowym Nintendo. yuzu nie jest stowarzyszony w żaden sposób z Nintendo.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation>Konfiguracja zakończona!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>Zgłoś kompatybilność</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>Zgłoś kompatybilność gry</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Jeśli postanowisz wysłać wyniki testu na &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;listę kompatybilności yuzu&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, następujące informacja zostaną zebrane i wyświetlone na stronie:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Informacja o sprzęcie komputerowym (procesor / karta graficzna / system operacyjny)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Wersja yuzu, której używasz&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Połączone konto yuzu&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>Idealna</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gra działa bez zarzutu, bez błędów graficznych lub dźwiękowych.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>Świetna</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gra działa z pomniejszymi błędami dźwiękowymi lub graficznymi, jest grywalna od początku do końca. Może wymagać kilku obejść/poprawek.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>W porządku</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gra działa z większymi błędami dźwiękowymi lub graficznymi, ale jest grywalna od początku do końca. Może wymagać kilku obejść/poprawek.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>Zła</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gra działa z większymi błędami dźwiękowymi lub graficznymi. Niemożliwe jest przejście konkretnych miejsc nawet z obejściami.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gra w żadnym stopniu nie jest grywalna ze względu na poważne błędy graficzne lub dźwiękowe. Niemożliwe jest przejście ekranu początkowego.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Nie uruchomia się</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gra zawiesza się podczas próby uruchomienia się.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Pomijając prędkość lub wydajność, jak dobrze ta gra zachowuje się w tej wersji yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>Dziękujemy za Twoją opinię!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>Wysyłanie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>Błąd komunikacyjny</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>Wystąpił błąd podczas wysyłania wyników testu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>Następny</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>Dźwięk</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>Silnik wyjścia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>Ten efekt post-przetwarzania dostosowuje prędkość dźwięku tak, aby zgadzała się z dźwiękiem emulowanym pomagając przy tym zapobiec zacinaniu się dźwięku. Zwiększa jednak opóźnienie dźwięku.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>Włącz rozciąganie dźwięku</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>Urządzenie dźwiękowe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation>Ustaw głośność:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>Głośność</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation>Ogólne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation>Niebezpieczne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation>Włącz Debug Mode</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>Ustawienia CPU są dostępny gdy gra nie jest uruchomiona </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>Włącz namiastkę GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>Port</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>Logowanie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>Globalny filtr rejestrów</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>Pokaż okno rejestrów (tylko Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>Otwórz miejsce rejestrów</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>Homebrew</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>Linijka argumentu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>Zaawansowane</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation>Wyczyść</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation>Domyślne</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>Ustawienia yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>Ogólne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>UI</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>Lista Gier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>System</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>Profile</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>System plików</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>Sterowanie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>Skróty klawiszowe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation>CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>Wyszukiwanie usterek</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>Grafika</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation>Zaawansowane</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>Dźwięk</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Web</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>Usługi</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>Karta SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>Gamecard</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>Ścieżka</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>Obecna Gra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>Ogólne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation>Emulacja CPU Wielordzeniowa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>Potwierdź wyjście podczas emulacji</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation>Ustawienia API</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation>API:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation>Urządzenie:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation>Ustawienia Graficzne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation>Format obrazu:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation>Domyślne (16:9)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation>Wymuś 4:3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation>Wymuś 21:9</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation>Rozciągnij do Okna</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation>Ustaw kolor tła:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>Kolor tła</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation>Urządzenie graficzne OpenGL</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation>Domyślne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation>2x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation>4x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation>8x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation>16x</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>Ustawienia Skrótów Klawiszowych</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation>Wyczyść wszystko</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation>Przywróć domyślne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>Akcja</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>Skrót klawiszowy</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>Kontekst</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation>Przywróć ustawienia domyślne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation>Wyczyść</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>Gracz 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>Gracz 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>Gracz 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>Gracz 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>Gracz 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>Gracz 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>Gracz 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>Gracz 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>Zaawansowane</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation>Tryb Konsoli</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation>Zadokowany</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation>Niezadokowany</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation>Wibracje</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation>Ruch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>Ustaw</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation>Kontrolery</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation>1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation>2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation>3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation>4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation>5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation>6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation>7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation>8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation>Połączone</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation>Domyślne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation>Wyczyść</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Ustawienie wejścia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation>Kolory Joyconów</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation>Gracz 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation>Gracz 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation>Gracz 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation>Gracz 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation>Gracz 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation>Gracz 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation>Gracz 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation>Gracz 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation>Inne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation>Klawiatura</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation>Zaawansowane</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation>Ekran dotykowy</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation>Mysz</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation>Ruch / Dotyk</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation>Konfiguruj</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation>Debuguj kontroler</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Ustawienie wejścia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation>Połacz Kontroler</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation>Pro Controller</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation>Para Joyconów</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation>Lewy Joycon</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation>Prawy Joycon</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation>Handheld</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation>Urządzenie Wejściowe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation>Klawiatura/Mysz</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation>Profil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation>Zapisz</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation>Nowy</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation>Usuń</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>Lewa gałka</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation>Góra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation>Lewo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation>Prawo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation>Dół</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation>Naciśnięty</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation>Modyfikator</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation>Zasięg</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation>Martwa strefa: 0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation>Zasięg Modyfikatora: 0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation>D-Pad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation>L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation>ZL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation>Minus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation>Zrzut ekranu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation>Plus</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation>Home</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation>R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation>ZR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation>SL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation>SR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>Przednie klawisze</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation>B</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>Prawa gałka</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation>Martwa strefa: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation>Zasięg Modyfikatora: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation>[oczekiwanie]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation>Konfiguruj Ruch / Dotyk</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation>Ruch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation>Czułość:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation>Dotyk</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation>Kalibracja:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation>(100, 50) - (1800, 850)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation>Konfiguruj</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation>Serwer:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation>Port:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation>Pad:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation>Dowiedz się więcej</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation>Test</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation>Myszka (Prawy Przycisk)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation>Testowanie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation>Konfigurowanie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation>Test Udany</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation>Citra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>Ustaw mysz</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>Przyciski myszy</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>Do przodu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>Do tyłu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>Lewy</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>Środkowy</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>Prawy</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>Wyczyść</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation>Domyślne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[nie ustawione]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>Przywróć ustawienie domyślne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[naciśnij przycisk]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation>Informacje</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation>Nazwa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation>Identyfikator gry</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation>Nazwa pliku</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation>Format</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation>Wersja</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation>Rozmiar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation>Deweloper</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation>Dodatki</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation>Ogólne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation>System</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation>Grafika</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation>Dźwięk</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation>Właściwości</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation>Wersja</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>Menedżer Profili</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>Obecny użytkownik</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>Nazwa Użytkownika</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>Ustaw zdjęcie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>Dodaj</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>Zmień nazwę</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>Usuń</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>Menedżer Profili nie jest dostępny gdy gra jest uruchomiona.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>Wpisz nazwę użytkownika</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>Użytkownicy</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>Wprowadź nazwę dla nowego użytkownika:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>Wpisz nową nazwę użytkownika:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>Potwierdź usunięcie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>Zamierzasz usunąć użytkownika &quot;%1&quot;. Jesteś pewien?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>Ustaw zdjęcie użytkownika</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>Obrazki JPEG (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>Bład usunięcia zdjęcia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>Błąd podczas próby nadpisania poprzedniego zdjęcia dla: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>Błąd usunięcia pliku</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>Nie można usunąć istniejącego pliku: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>Błąd podczas tworzenia folderu ze zdjęciem użytkownika</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>Nie można utworzyć ścieżki %1 do przechowywania zdjęć użytkownika.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>Błąd kopiowania zdjęcia użytkownika</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>Nie można skopiować zdjęcia z %1 do %2</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>Ustawienia systemu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation>Region:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation>Automatyczny</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation>Domyślne</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation>CET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation>CST6CDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation>Cuba</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation>EET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation>Egipt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation>Irlandia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation>EST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation>EST5EDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation>GMT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation>GMT+0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation>GMT-0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation>GMT0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation>Greenwich</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation>Hongkong</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation>HST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation>Islandia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation>Iran</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation>Izrael</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation>Jamajka</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation>Japonia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation>Kwajalein</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation>Libia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation>MET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation>MST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation>MST7MDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation>Navajo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation>NZ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation>NZ-CHAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation>Polska</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation>Portugalia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation>PRC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation>PST8PDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation>ROC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation>ROK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>Uwaga: można to zmienić, gdy ustawienie regionu jest wybierane automatycznie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>Japoński (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>Angielski (English)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>Francuski (français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>Niemiecki (Deutsch)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>Włoski (italiano)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>Hiszpański (español)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>Chiński</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>Koreański (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>Duński (Holandia)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>Portugalski (português)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>Rosyjski (Русский)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>Tajwański</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>Angielski (Brytyjski)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>Fancuski (Kanada)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>Hiszpański (Latin American)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>Chiński (Uproszczony)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>Chiński tradycyjny (正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>Język</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>Ziarno RNG</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>Mono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>Stereo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>Surround</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>Indentyfikator konsoli:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>Tryb wyjścia dźwięku</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>Wygeneruj ponownie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>Ustawienia systemu są dostępne tylko wtedy, gdy gra nie jest uruchomiona.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>To zamieni twojego obecnego Switch&apos;a z nowym. Twojego obecnego Switch&apos;a nie będzie można przywrócić. To może wywołać nieoczekiwane problemy w grach. To może nie zadziałać, jeśli używasz nieaktualnej konfiguracji zapisu gry. Kontynuować?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>Ostrzeżenie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>Identyfikator konsoli: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>Skonfiguj ekran dotykowy</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>Ostrzeżenie: Ustawienia na tej stronie mają wpływ na działanie emulowanego ekranu dotykowego Yuzu. ch zmiana może spowodować niepożądane zachowanie, takie jak częściowo lub całkowicie nie działający ekran dotykowy. Powinieneś/naś używać tej strony tylko wtedy, gdy wiesz, co robisz.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>Parametry dotyku</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>Średnica dotyku Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>Palec</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>Średnica dotyku X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>Kąt rotacji</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>Przywróć domyślne</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>Lista Gier</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>Angielski</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>Usługa internetowa yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>Podając swoją nazwę użytkownika i token, zgadzasz się na umożliwienie yuzu zbierania dodatkowych danych o użytkowaniu, które mogą zawierać informacje umożliwiające identyfikację użytkownika.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>Zweryfikuj</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>Zaloguj się</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>Token:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>Nazwa użytkownika:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>Czym jest mój token?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>Telemetria</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>Udostępniaj anonimowe dane o użytkowaniu zespołowi yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>Dowiedz się więcej</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>Identyfikator telemetrii:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>Wygeneruj ponownie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Obecność na discordzie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Pokazuj obecną grę w twoim statusie Discorda</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Dowiedz się więcej&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Zaloguj się&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Czym jest mój token?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>Identyfikator telemetrii: 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>Weryfikowanie...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>Weryfikowanie nieudane</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Dane anonimowe są gromadzone&lt;/a&gt; aby ulepszyć yuzu. &lt;br/&gt;&lt;br/&gt;Czy chcesz udostępnić nam swoje dane o użytkowaniu?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>Telemetria</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>Sprawdzanie tekstu nie powiodło się</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>Aktualna prędkość emulacji. Wartości większe lub niższe niż 100% wskazują, że emulacja działa szybciej lub wolniej niż Switch.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>Ile klatek na sekundę gra aktualnie wyświetla. To będzie się różnić w zależności od gry, od sceny do sceny.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Czas potrzebny do emulacji klatki na sekundę Switcha, nie licząc ograniczania klatek ani v-sync. Dla emulacji pełnej szybkości powinno to wynosić co najwyżej 16,67 ms.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>Usuń &quot;Ostatnie pliki&quot;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>OSTRZEŻENIE! Nieaktualny format gry</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>Używasz zdekonstruowanego formatu katalogu ROM dla tej gry, który jest przestarzałym formatem, który został zastąpiony przez inne, takie jak NCA, NAX, XCI lub NSP. W zdekonstruowanych katalogach ROM brakuje ikon, metadanych i obsługi aktualizacji.&lt;br&gt;&lt;br&gt; Aby znaleźć wyjaśnienie różnych formatów Switch obsługiwanych przez yuzu,&lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt; sprawdź nasze wiki&lt;/a&gt;. Ta wiadomość nie pojawi się ponownie.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>Błąd podczas wczytywania ROMu!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>Ten format ROMu nie jest wspierany.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>Wystąpił błąd podczas inicjowania rdzenia wideo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>yuzu napotkał błąd podczas działania rdzenia wideo, proszę zobaczyć log po więcej szczegółów. Aby uzyskać więcej informacji na temat uzyskiwania dostępu do pliku log, zobacz następującą stronę: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Jak przesłać plik log? &lt;/a&gt;Upewnij się, że masz najnowsze sterowniki karty graficznej.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>Wystąpił nieznany błąd. Więcej informacji można znaleźć w pliku log.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>Start</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>Błąd podczas otwarcia folderu %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>Folder nie istnieje!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>Wypakowanie RomFS nieudane!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>Wystąpił błąd podczas kopiowania plików RomFS lub użytkownik anulował operację.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>Wybierz tryb zrzutu RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>Proszę wybrać w jaki sposób chcesz, aby zrzut pliku RomFS został wykonany. &lt;br&gt;Pełna kopia ze wszystkimi plikami do nowego folderu, gdy &lt;br&gt;skielet utworzy tylko strukturę folderu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>Wypakowywanie RomFS...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>Wypakowanie RomFS zakończone pomyślnie!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>Operacja zakończona sukcesem.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>Wybierz folder...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>Właściwości</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>Właściwości tej gry nie mogły zostać załadowane.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Plik wykonywalny Switcha (%1);;Wszystkie pliki (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>Załaduj plik...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>Otwórz folder wypakowanego ROMu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>Wybrano niewłaściwy folder</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>Folder wybrany przez ciebie nie zawiera &apos;głownego&apos; pliku.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>Instalowanie pliku &quot;%1&quot;...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>Aplikacja systemowa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>Archiwum systemu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>Aktualizacja aplikacji systemowej</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>Paczka systemowa (Typ A)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>Paczka systemowa (Typ B)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>Gra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>Aktualizacja gry</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>Dodatek do gry</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>Tytuł Delta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>Wybierz typ instalacji NCA...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>Wybierz typ tytułu, do którego chcesz zainstalować ten NCA, jako:
+(W większości przypadków domyślna &quot;gra&quot; jest w porządku.)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>Instalacja nieudana</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>Typ tytułu wybrany dla NCA jest nieprawidłowy.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>Nie znaleziono pliku</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>Nie znaleziono pliku &quot;%1&quot;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>Kontynuuj</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>Brakuje konta Yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>Aby przesłać test zgodności gry, musisz połączyć swoje konto yuzu.&lt;br&gt;&lt;br/&gt; Aby połączyć swoje konto yuzu, przejdź do opcji Emulacja &amp;gt; Konfiguracja &amp;gt; Sieć.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>Plik Amiibo (%1);;Wszyskie pliki (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>Załaduj Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>Błąd otwarcia pliku danych Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>Nie można otworzyć pliku Amiibo &quot;%1&quot; do odczytu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>Błąd podczas odczytu pliku danych Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>Nie można w pełni odczytać danych Amiibo. Oczekiwano odczytu %1 bajtów, ale był on w stanie odczytać tylko %2 bajty.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>Błąd podczas ładowania pliku danych Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>Nie można załadować danych Amiibo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>Zrób zrzut ekranu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>Obrazek PNG (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>Prędkość: %1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>Prędkość: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>Gra: %1 FPS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>Klatka: %1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>Gra, którą próbujesz wczytać, wymaga dodatkowych plików z Switch&apos;a, które zostaną zrzucone przed graniem.&lt;br/&gt;&lt;br/&gt; Aby uzyskać więcej informacji na temat wyrzucania tych plików, odwiedź następującą stronę wiki:&lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt; Zrzut archiw systemu i udostępnionych czcionek z konsoli Nintendo Switch&lt;/a&gt;. &lt;br/&gt;&lt;br/&gt;Czy chcesz wrócić do listy gier? Kontynuacja emulacji może spowodować awarie, uszkodzone dane zapisu lub inne błędy.
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>Archiwum systemu nie znalezione.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>Czcionki nie zostały znalezione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>Fatalny błąd</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>yuzu napotkał błąd, proszę zobaczyć log po więcej szczegółów. Aby uzyskać więcej informacji na temat uzyskiwania dostępu do pliku log, zobacz następującą stronę: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Jak przesłać plik log&lt;/a&gt;?&lt;br/&gt;&lt;br/&gt; Czy chcesz wrócić do listy gier? Kontynuacja emulacji może spowodować awarie, uszkodzone dane zapisu lub inne błędy.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>Potwierdź ponowną aktywacje klucza</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>Zamierzasz zmusić wszystkie swoje klucze do ponownej aktywacji.
+Jeśli nie wiesz, co to oznacza i co robisz,
+jest to potencjalnie destrukcyjne działanie.
+Upewnij się, że to jest to, czego chcesz
+i opcjonalnie tworzyć kopie zapasowe.
+
+Spowoduje to usunięcie wygenerowanych automatycznie plików kluczy i ponowne uruchomienie modułu pochodnego klucza.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>Wyprowadzanie kluczy...
+Zależnie od tego może potrwać do minuty
+na wydajność twojego systemu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>Wyprowadzanie kluczy...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>Wybierz cel zrzutu RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>Proszę wybrać RomFS, jakie chcesz zrzucić.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>Czy na pewno chcesz zamknąć yuzu?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>Czy na pewno chcesz zatrzymać emulację? Wszystkie niezapisane postępy zostaną utracone.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>Nazwa gry</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>Kompatybilność</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>Dodatki</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>Typ pliku</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>Rozmiar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>Otwórz lokalizację zapisów</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Otwórz lokalizację modyfikacji</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>Zrzuć RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>Kopiuj identyfikator gry do schowka</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>Nawiguj do wpisu kompatybilności gry</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>Właściwości</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>Perfekcyjnie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>Funkcje gry są bezbłędne, bez żadnych zakłóceń audio i graficznych, wszystkie przetestowane funkcje działają zgodnie z przeznaczeniem bez
+wszelkich potrzebnych obejść.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>Świetnie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>Funkcje gry z drobnymi usterkami graficznymi lub dźwiękowymi i można je odtwarzać od początku do końca. Może wymagać niektórych
+obejść.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>W porządku</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>Funkcje gry z dużymi usterkami graficznymi lub dźwiękowymi, ale gra jest odtwarzana od początku do końca z użyciem
+obejść.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>Zła</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>Funkcje gry, ale z dużymi usterkami graficznymi lub dźwiękowymi. Nie można wykonać postępu w określonych obszarach z powodu problemów
+nawet z obejściami.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>Gra jest całkowicie niemożliwa do zagrania z powodu poważnych usterków graficznych lub dźwiękowych. Nie można przejść ekran
+startowy.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Nie uruchamia się</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>Ta gra się zawiesza przy próbie startu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>Nie testowane</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>Ta gra nie została jeszcze przetestowana.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>Kliknij podwójnie aby dodać folder do listy gier</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>Filter:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>Wpisz typ do filtra</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>Uruchamianie...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>&amp;Plik</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>Ostatnie pliki</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>&amp;Emulacja</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>&amp;Widok</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>Debugowanie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>Narzędzia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>&amp;Pomoc</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>Załaduj plik...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>Załaduj folder...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>&amp;Wyjście</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>&amp;Start</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>&amp;Pauza</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>&amp;Stop</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>Reinicjalizuj klucze...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>O yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>Tryb jednego okna</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>Konfiguruj...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>Wyświetlaj nagłówki Dock Widget</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>Pokaż pasek fitrowania</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>Pokaż pasek statusu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>Pełny ekran</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>Zrestartuj</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>Załaduj Amiibo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>Zgłoś kompatybilność</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>Otwórz folder yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>Zrób zrzut ekranu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>MicroProfile</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[nie ustawione]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>Krzyżak %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>Oś %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>Przycisk %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[nieznane]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[nieużywane]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>Oś %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>Wybierz użytkownika:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>Wybór profilu</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>Wpisz tekst:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>Klawiatura systemowa</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>Stos wywołań</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>czekam na mutex 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>ma oczekujących: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>uchwyt właściciela: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>czekam na wszystkie objekty</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>oczekiwanie na jeden z następujących obiektów</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>Uruchomione</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>Gotowe</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>Spauzowana</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>czekam na powrót HLE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>spanie</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>czekam na odpowiedź IPC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>oczekiwanie na obiekty</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>czekam na mutex</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>czekam na arbitra adresu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>drzemiący</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>śmierć</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation> PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>rdzeń %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>Nieznany procesor %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>procesor = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>idealny rdzeń = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>maska powinowactwa = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>identyfikator wątku = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>piorytet = %1(obecny) / %2(normalny)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>ostatnie działające kleszcze = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>nie czekam na mutex</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>czekanie na wątek</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>Drzewo czekania</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/pt_BR.ts b/dist/languages/pt_BR.ts
new file mode 100644
index 000000000..c842793f4
--- /dev/null
+++ b/dist/languages/pt_BR.ts
@@ -0,0 +1,4757 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_BR" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>Sobre o yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu é um emulador experimental de código aberto para o Nintendo Switch licenciado sob a GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;Esse programa não deve ser utilizado para jogar jogos que você não obteve legalmente.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Site&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Código fonte&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contribuidores&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licença&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; é uma marca comercial da Nintendo. O yuzu não é afiliado com a Nintendo de nenhuma forma.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation>Comunicando com o servidor...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation>Toque no canto superior esquerdo &lt;br&gt;do seu touchpad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation>Agora toque no canto inferior direito &lt;br&gt;do seu touchpad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation>Configuração concluída!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>Informar compatibilidade</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>Informar compatibilidade de jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Ao enviar um caso de teste à &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;lista de compatibilidade do yuzu&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, as seguintes informações serão recolhidas e exibidas no site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Informações de hardware (CPU / GPU / sistema operacional)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Qual versão do yuzu você está usando&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;A conta do yuzu conectada&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>Perfeito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo funciona impecavelmente, sem falhas no áudio ou nos gráficos.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>Ótimo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo funciona com leves falhas gráficas ou de áudio e é jogável do início ao fim. Pode exigir algumas soluções alternativas.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>Razoável</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo funciona com grandes falhas gráficas ou de áudio, mas é jogável do início ao fim com o uso de soluções alternativas.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>Ruim</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo funciona, só que com problemas significativos nos gráficos ou no áudio. Não é possível progredir em áreas específicas por conta de tais problemas, mesmo com soluções alternativas.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;É impossível jogar o jogo devido a grandes problemas nos gráficos ou no áudio. Não é possível passar da tela inicial do jogo.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Não inicia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo trava ou se encerra abruptamente ao se tentar iniciá-lo.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sem considerar velocidade e desempenho, quão bem o jogo se comporta, do início ao fim, nesta versão do yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>Agradecemos pelo seu relatório!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>Enviando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>Erro de comunicação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>Um erro ocorreu ao enviar o caso de teste</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>Próximo</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>Áudio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>Mecanismo de saída:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>Este efeito de pós-processamento ajusta a velocidade do áudio para acompanhar a velocidade de emulação e ajuda a evitar cortes no áudio. No entanto, isto aumenta a latência do áudio.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>Ativar alongamento de áudio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>Dispositivo de áudio:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation>Usar volume global</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation>Definir volume:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>Volume:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation>Geral</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation>Precisão:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation>Preciso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation>Não seguro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation>Ativar modo de depuração</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation>Recomendamos definir a precisão para &quot;Preciso&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation>Ajustes de otimização não seguros de CPU </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation>Estes ajustes reduzem a precisão para aprimorar a velocidade.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation>Não usar FMA (melhora o desempenho em CPUs sem FMA)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esta opção melhora o desempenho reduzindo a precisão de instruções de multiplicação-adição unificada (FMA) em CPUs sem suporte nativo a este recurso.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation>FRSQRTE e FRECPE mais rápidos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esta opção melhora o desempenho de algumas instruções de ponto flutuante usando aproximações nativas menos precisas.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>Os ajustes de CPU só estão disponíveis enquanto o jogo não estiver em execução.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation>Ativando o modo de depuração de CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation>O modo de depuração de CPU é intencionado para uso por desenvolvedores. Deseja mesmo ativá-lo?</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation>Ative ou desative otimizações de CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;
+ &lt;b&gt;Apenas para depuração.&lt;/b&gt;
+ &lt;br&gt;
+ Se você não tem certeza do que estas opções fazem, mantenha-as todas ativadas.
+ &lt;br&gt;
+ Estes ajustes apenas têm efeito quando a precisão da CPU for definida como &quot;Ativar modo de depuração&quot;.
+ &lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation>Ativar tabelas de página em linha</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Esta otimização acelera acessos de memória pelo programa convidado.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Quando ativada, permite o acesso inline a PageTable::pointers no código emitido.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Quando desativada, força a passagem de todos os acessos de memória pelas funções Memory::Read/Memory::Write.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation>Ativar vinculação de blocos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esta otimização evita buscas do dispatcher ao permitir que blocos básicos emitidos pulem diretamente para outros blocos básicos se o PC de destino for estático.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation>Ativar buffer de pilha de retorno</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Esta otimização evita buscas do dispatcher ao monitorar possíveis endereços de retorno de instruções BL. Isto se aproxima do que ocorre em um buffer de pilha de retorno em um CPU real.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation>Ativar dispatcher rápido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Ativa um sistema de dispatch de dois níveis. Um dispatcher mais rápido, escrito em assembly e que possui um pequeno cache MRU de destinos de pulo, é usado primeiro. Caso falhe, o dispatcher mais lento escrito em C++ será usado em seu lugar.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation>Ativar eliminação de contexto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Ativa uma otimização da IR que reduz acessos desnecessários à estrutura de contexto da CPU.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation>Ativar propagação de constantes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Ativa otimizações da IR que envolvem propagação de constantes.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation>Ativar otimizações diversas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div&gt;Ativa otimizações diversas para a IR.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation>Ativar redução de checagem de desalinhamento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Quando ativada, um desalinhamento só será disparado quando um acesso cruza o limite de uma página.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Quando desativada, um desalinhamento será disparado em todos os acessos desalinhados.&lt;/div&gt;
+ </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>Os ajustes de CPU estão disponíveis apenas quando não houver nenhum jogo em execução.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>Ativar GDB stub</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>Porta:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>Registros de depuração</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>Filtro global de registros</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>Mostrar console de registros (apenas Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>Abrir local dos registros</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>Homebrew</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>Linha de argumentos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation>Gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation>Quando ativado, a API gráfica entra em um modo de depuração mais lento.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation>Ativar depuração de gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation>Quando ativado, desativa o macro compilador Just in Time. Ativar isto faz os jogos rodarem mais lentamente.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation>Desativar macro JIT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation>Extrair</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>Ativar serviços de relatório detalhado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>Isto será restaurado automaticamente assim que o yuzu for fechado.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>Avançado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation>Modo quiosque (Quest)</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation>Configurar controle de depuração</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation>Limpar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation>Padrão</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>Configurações do yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>Geral</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>Interface</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>Lista de jogos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>Perfis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>Sistema de arquivos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>Controles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>Teclas de atalho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation>CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>Depuração</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>Gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation>Avançado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation>GráficosAvançado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>Áudio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Rede</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>Serviços</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>Pastas de armazenamento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>Cartão SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>Cartão de jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>Caminho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>Inserido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>Jogo atual</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>Gerenciador de patches</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>Extrair NSOs descompactados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>Extrair ExeFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation>Raiz de carregamento de mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation>Extrair raiz</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>Ajustes de cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>Diretório do cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation>Metadados da lista de jogos em cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>Restaurar cache de metadados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>Selecione a pasta da NAND emulada...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>Selecione a pasta do SD emulado...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation>Selecione o local do Gamecard...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>Selecione a pasta de extração...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation>Selecione a pasta de carregamento de mods...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>Selecione a pasta de cache...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>O cache de metadados já está vazio.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>A operação foi concluída com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>O cache de metadados não pôde ser excluído. Ele pode estar em uso no momento ou não existe.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>Geral</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>Limitar percentual de velocidade</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation>Emulação de CPU multinúcleo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>Confirmar saída quando a emulação estiver em execução</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation>Escolher um usuário ao iniciar um jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>Pausar emulação quando a janela ficar em segundo plano</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation>Esconder cursor do mouse quando em inatividade</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation>Configurações de API</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation>API:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation>Dispositivo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation>Configurações gráficas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>Usar cache de shaders em disco</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>Usar emulação assíncrona da GPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation>Proporção de tela:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation>Padrão (16:9)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation>Forçar 4:3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation>Forçar 21:9</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation>Esticar para a janela</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation>Usar cor de fundo global</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation>Configurar cor de fundo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>Cor de fundo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation>Dispositivo gráfico do OpenGL</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation>Configurações gráficas avançadas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation>Nível de precisão:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation>A sincronização vertical (VSync) evita que as imagens do jogo pareçam cortadas, porém algumas placas gráficas apresentam redução de desempenho quando estiver ativa. Deixe-a ativada se você não reparar alguma diferença de desempenho.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation>Usar sincronização vertical (apenas OpenGL)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation>Ativar isto reduz engasgos de shaders. Ativa os shaders assembly do OpenGL em dispositivos compatíveis da Nvidia (é necessária a extensão NV_gpu_program5). Esta é uma opção experimental.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation>Usar shaders assembly (experimental, apenas OpenGL + Nvidia)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation>Realiza a compilação de shaders de forma assíncrona, o que pode reduzir engasgos de shaders. Esta opção é experimental.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation>Usar compilação assíncrona de shaders (experimental)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation>Usar tempo de resposta rápido da GPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation>Filtragem anisotrópica:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation>Padrão</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation>2x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation>4x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation>8x</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation>16x</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>Configurações de teclas de atalho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation>Clique duas vezes em um atalho para alterá-lo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation>Limpar tudo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation>Restaurar padrões</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>Ação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>Atalho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>Contexto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>Combinação de teclas já utilizada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation>A sequência de teclas pressionada já esta atribuída para: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation>Restaurar padrão</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation>Limpar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation>A sequência de teclas padrão já esta atribuida para: %1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation>ConfigurarEntrada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>Jogador 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>Jogador 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>Jogador 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>Jogador 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>Jogador 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>Jogador 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>Jogador 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>Jogador 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>Avançado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation>Modo do console</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation>Na base</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation>Fora da base</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation>Vibração</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation>Movimento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>Configurar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation>Controles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation>1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation>2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation>3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation>4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation>5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation>6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation>7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation>8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation>Conectado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation>Padrões</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation>Limpar</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Configurar entrada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation>Cores dos Joycon</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation>Jogador 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation>Joycon esq.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation>Botão L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation>Joycon dir.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation>Botão R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation>Jogador 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation>Jogador 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation>Jogador 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation>Jogador 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation>Jogador 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation>Jogador 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation>Jogador 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation>Outro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation>Teclado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation>Avançado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation>Touchscreen</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation>Mouse</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation>Movimento/toque</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation>Configurar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation>Controle de depuração</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Configurar controles</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation>Conectar controle</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation>Pro Controller</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation>Par de Joycons</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation>Joycon Esquerdo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation>Joycon Direito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation>Portátil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation>Dispositivo de entrada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation>Qualquer</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation>Teclado/mouse</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation>Perfil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation>Salvar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation>Novo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation>Excluir</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>Analógico esquerdo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation>Cima</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation>Esquerda</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation>Direita</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation>Baixo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation>Pressionado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation>Modificador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation>Alcance</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation>Zona morta: 0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation>Alcance de modificador: 0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation>D-pad</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation>L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation>ZL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation>Menos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation>Capturar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation>Mais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation>Botão Home</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation>R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation>ZR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation>SL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation>SR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>Botões de rosto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation>B</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>Analógico direito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation>Zona morta: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation>Alcance de modificador: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation>[esperando]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation>Configurar movimento/toque</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation>Movimento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation>Fonte dos dados de movimento:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation>Sensibilidade:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation>Toque</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation>Fonte dos dados de toque:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation>Calibração:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation>(100, 50) - (1800, 850)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation>Configurar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation>Usar mapeamento de botões:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation>Configuração CemuhookUDP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation>Você pode utilizar qualquer dispositivo de entrada compatível com o Cemuhook UDP para prover dados de movimento e toque.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation>Servidor:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation>Porta:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation>Direcionais:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation>Direcional 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation>Direcional 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation>Direcional 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation>Direcional 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation>Saiba mais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation>Teste</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation>Mouse (botão direito)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation>CemuhookUDP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation>Janela do emulador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Saiba mais&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation>Testando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation>Configurando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation>Teste bem-sucedido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation> Dados foram recebidos do servidor com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation>O teste falhou</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation>Não foi possível receber dados válidos do servidor.&lt;br&gt;Verifique se o servidor foi configurado corretamente e o endereço e porta estão corretos.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation>Citra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation>Um teste UDP ou configuração de calibração está em curso no momento.&lt;br&gt;Aguarde até a sua conclusão.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>Configurar mouse</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>Botões do mouse</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>Dianteiro:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>Traseiro:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>Esquerdo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>Meio:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>Direito:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>Limpar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation>Padrões</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[não definido]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>Restaurar padrão</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[pressione uma tecla]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation>Informações</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation>Nome</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation>ID do título</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation>Nome do arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation>Versão</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation>Tamanho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation>Desenvolvedor</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation>Adicionais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation>Geral</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation>Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation>Gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation>Gráficos avanç.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation>Áudio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation>Propriedades</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation>Usar configuração global (%1)</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation>Nome do patch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation>Versão</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>Gerenciador de perfis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>Usuário atual</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>Nome de usuário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>Definir imagem</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>Adicionar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>Renomear</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>Excluir</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>Esta tela só fica disponível apenas quando não houver nenhum jogo em execução.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>Escreva o nome de usuário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>Usuários</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>Digite o nome do novo usuário:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>Digite um novo nome de usuário:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>Confirmar exclusão</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>Você está prestes a excluir o usuário &quot;%1&quot;. Tem certeza?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>Selecione a imagem do usuário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>Imagens JPEG (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>Erro ao excluir a imagem</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>Ocorreu um erro ao tentar substituir a imagem anterior em: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>Erro ao excluir arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>Não foi possível excluir o arquivo existente: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>Erro ao criar a pasta de imagens do usuário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>Não foi possível criar a pasta %1 para armazenar as imagens do usuário.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>Erro ao copiar a imagem do usuário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>Não foi possível copiar a imagem de %1 para %2</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>BCAT é a maneira que a Nintendo usa para enviar dados aos jogos para engajar sua comunidade e desbloquear conteúdo adicional.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation>Backend do BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Saiba mais sobre o BCAT, Boxcat e eventos atuais&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation>O serviço Boxcat está offline ou você não está conectado à internet.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>Ocorreu um erro ao processar os dados de eventos do Boxcat. Entre em contato com os desenvolvedores do yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>A versão do yuzu que você está usando é ou recente demais ou antiga demais para o servidor. Tente atualizar para a versão oficial mais recente do yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation>Não há eventos no Boxcat atualmente.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation>Eventos Boxcat atuais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation>O yuzu está baixando o status mais recente do Boxcat...</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>Configurações de sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation>Região:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation>Automático</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation>Padrão</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation>CET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation>CST6CDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation>Cuba</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation>EET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation>Egito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation>Eire</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation>EST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation>EST5EDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation>GB-Eire</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation>GMT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation>GMT+0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation>GMT-0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation>GMT0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation>Greenwich</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation>Hongkong</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation>HST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation>Islândia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation>Irã</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation>Israel</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation>Jamaica</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation>Japão</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation>Ilhas Marshall</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation>Líbia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation>MET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation>MST</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation>MST7MDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation>Navajo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation>NZ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation>NZ-CHAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation>Polônia </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation>Portugal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation>PRC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation>PST8PDT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation>ROC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation>ROK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation>Singapura</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation>Turquia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation>UCT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation>Universal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation>UTC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation>W-SU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation>WET</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation>Zulu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation>EUA</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation>Europa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation>Austrália</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation>China</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation>Coréia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation>Taiwan</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation>Fuso horário:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>Nota: isso pode ser substituído caso a configuração de região automática esteja ativada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>Japônes (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>Inglês (English)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>Francês (français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>Alemão (Deutsch)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>Italiano (italiano)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>Espanhol (español)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>Chinês</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>Coreano (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>Holandês (Nederlands)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>Português</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>Russo (Русский)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>Taiwanês</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>Inglês britânico (British English)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>Francês canadense (Canadian French)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>Espanhol latino-americano</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>Chinês simplificado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>Chinês tradicional (正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>Data e hora personalizada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>Idioma</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>Semente RNG</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>Mono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>Estéreo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>Surround</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>ID do console:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>Modo de saída de som</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation>d MMM yyyy h:mm:ss AP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>Regerar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>As configurações de sistema são acessíveis apenas quando não houver nenhum jogo em execução.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>Isto substituirá o seu Switch virtual atual por um novo. O seu Switch virtual atual não poderá ser recuperado. Isto pode causar efeitos inesperados em jogos. Isto pode falhar caso você use um jogo salvo com configurações desatualizadas registradas nele. Continuar?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>Aviso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>ID do console: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation>Configurar mapeamento de toque</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation>Mapeamento:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation>Novo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation>Excluir</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation>Renomear</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation>Clique na área inferior para adicionar um ponto, e então pressione um botão para mapear.
+Mova os pontos para mudar a posição, ou clique duas vezes nas células da tabela para editar os valores.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation>Excluir ponto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation>Botão</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation>Novo perfil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation>Insira o nome do novo perfil.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation>Excluir perfil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation>Excluir perfil %1?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation>Renomear perfil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation>Novo nome:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation>[pressione a tecla]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>Configurar tela de toque</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>Aviso: Os ajustes nesta página afetam o funcionamento interno da tela de toque emulada do yuzu. Alterá-los pode resultar em comportamentos indesejáveis, tais como a tela de toque funcionar parcialmente ou não responder por completo. Apenas faça alterações caso você saiba o que está fazendo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>Parâmetros de toque</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>Diâmetro de toque Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>Dedo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>Diâmetro de toque X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>Ângulo rotacional</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>Restaurar padrões</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>Geral</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>Nota: alterar o idioma aplicará as suas configurações.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>Idioma da interface:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>Tema:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>Lista de jogos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>Mostrar coluna de adicionais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>Tamanho do ícone:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>Texto da 1ª linha:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>Texto da 2ª linha:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation>Capturas de tela</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation>Perguntar onde salvar capturas de tela (apenas Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation>Pasta para capturas de tela:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation>Selecione a pasta de capturas de tela...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>Inglês</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>yuzu Web Service</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>Ao informar seu usuário e token, você concorda em permitir ao yuzu recolher dados de uso adicionais, que podem incluir informações de identificação de usuário.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>Verificar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>Cadastrar-se</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>Token:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>Nome de usuário:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>Qual é o meu token?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>Telemetria</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>Compartilhar anonimamente dados de uso com a equipe do yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>Saiba mais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>ID de telemetria:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>Gerar um novo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Presença no Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Mostrar o jogo atual no seu status do Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Saiba mais&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Cadastrar-se&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Qual é o meu token?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>ID de telemetria: 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>Não especificado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>Token não verificado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>O token não foi verificado. A alteração no seu token não foi salva.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>Verificando...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>Falha na verificação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>Falha na verificação. Verifique se o seu token foi inserido corretamente e se a sua conexão à internet está funcionando.</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Dados anônimos são recolhidos&lt;/a&gt; para ajudar a melhorar o yuzu. &lt;br/&gt;&lt;br/&gt;Gostaria de compartilhar os seus dados de uso conosco?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>Telemetria</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>Falha na verificação de texto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation>Carregando applet web...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation>Sair do applet web</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>Sair</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation>Para sair do aplicativo web, use os controles fornecidos pelo jogo para sair dele, selecione a opção &quot;Sair do applet web&quot; na barra de menu ou pressione a tecla &quot;Enter&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation>Applet web</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>Esta versão do yuzu foi compilada sem suporte a QtWebEngine, o que significa que o yuzu não pode exibir adequadamente o manual do jogo ou a página da web solicitada.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation>A quantidade de shaders sendo construídos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>Velocidade atual de emulação. Valores maiores ou menores que 100% indicam que a emulação está rodando mais rápida ou lentamente que em um Switch.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>Quantos quadros por segundo o jogo está exibindo atualmente. Isto irá variar de jogo para jogo e cena para cena.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Tempo que leva para emular um quadro do Switch, sem considerar o limitador de taxa de quadros ou a sincronização vertical. Um valor menor ou igual a 16.67 ms indica que a emulação está em velocidade plena.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation>NA BASE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation>ASYNC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation>MULTINÚCLEO</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation>VULKAN</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation>OPENGL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>Limpar arquivos recentes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>Aviso - formato de jogo desatualizado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>Você está usando neste jogo o formato de ROM desconstruída e extraída em uma pasta, que é um formato desatualizado que foi substituído por outros, como NCA, NAX, XCI ou NSP. Pastas desconstruídas de ROMs não possuem ícones, metadados e suporte a atualizações.&lt;br&gt;&lt;br&gt;Para saber mais sobre os vários formatos de ROMs de Switch compatíveis com o yuzu, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;confira a nossa wiki&lt;/a&gt;. Esta mensagem não será exibida novamente.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>Erro ao carregar a ROM!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>O formato da ROM não é suportado.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>Ocorreu um erro ao inicializar o núcleo de vídeo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>O yuzu encontrou um erro ao executar o núcleo de vídeo. Consulte o registro para mais detalhes. Para mais informações em como acessar o registro, veja a seguinte página: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Como enviar o arquivo de registro&lt;/a&gt;. Verifique se você está usando o driver de vídeo mais atualizado.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation>Erro ao carregar a ROM!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>Ocorreu um erro desconhecido. Consulte o registro para mais detalhes.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>Iniciar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>Dados de jogos salvos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Dados de mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>Erro ao abrir a pasta %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>A pasta não existe!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>Erro ao abrir o cache de shaders transferível</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>Não existe um cache de shaders para este título.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation>Conteúdo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation>Atualização</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation>DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation>Remover item</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation>Remover o jogo instalado %1?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation>Removido com sucesso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation>O jogo base foi removido com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation>Erro ao remover %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation>O jogo base não está instalado na NAND e não pode ser removido.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation>A atualização instalada foi removida com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation>Não há nenhuma atualização instalada para este título.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation>Não há nenhum DLC instalado para este título.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation>%1 DLC(s) instalados foram removidos com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation>Excluir o cache de shaders transferível?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation>Remover configurações customizadas do jogo?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation>Remover arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation>Erro ao remover cache de shaders transferível</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation>O cache de shaders transferível foi removido com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation>Falha ao remover o cache de shaders transferível.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation>Erro ao remover as configurações customizadas do jogo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation>Não há uma configuração customizada para este título.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation>As configurações customizadas do jogo foram removidas com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation>Falha ao remover as configurações customizadas do jogo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>Falha ao extrair RomFS!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>Houve um erro ao copiar os arquivos RomFS ou o usuário cancelou a operação.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>Extração completa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation>Apenas estrutura</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>Selecione o modo de extração do RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>Selecione a forma como você gostaria que o RomFS seja extraído.&lt;br&gt;&quot;Extração completa&quot; copiará todos os arquivos para a nova pasta, enquanto que &lt;br&gt;&quot;Apenas estrutura&quot; criará apenas a estrutura de pastas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>Extraindo RomFS...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>Extração do RomFS concluida!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>A operação foi concluída com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>Erro ao abrir %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>Selecionar pasta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>Propriedades</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>As propriedades do jogo não puderam ser carregadas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Executável do Switch (%1);;Todos os arquivos (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>Carregar arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>Abrir pasta da ROM extraída</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>Pasta inválida selecionada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>A pasta que você selecionou não contém um arquivo &apos;main&apos;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation>Arquivo de Switch instalável (*.nca *.nsp *.xci);; Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation>Instalar arquivos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>Instalando arquivo &quot;%1&quot;...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation>Resultados da instalação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>Aplicativo do sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>Arquivo do sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>Atualização de aplicativo do sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>Pacote de firmware (tipo A)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>Pacote de firmware (tipo B)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>Jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>Atualização de jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>DLC de jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>Título delta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>Selecione o tipo de instalação do NCA...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>Selecione o tipo de título como o qual você gostaria de instalar este NCA:
+(Na maioria dos casos, o padrão &apos;Jogo&apos; serve bem.)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>Falha ao instalar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>O tipo de título que você selecionou para o NCA é inválido.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>Arquivo não encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>Arquivo &quot;%1&quot; não encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>Continuar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>Tela de erro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>Conta do yuzu faltando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>Para enviar um caso de teste de compatibilidade de jogo, você precisa entrar com a sua conta do yuzu.&lt;br&gt;&lt;br/&gt;Para isso, vá para Emulação &amp;gt; Configurar... &amp;gt; Rede.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation>Erro ao abrir URL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation>Não foi possível abrir o URL &quot;%1&quot;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>Arquivo Amiibo (%1);; Todos os arquivos (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>Carregar Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>Erro ao abrir arquivo de dados do Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>Não foi possível abrir o arquivo de Amiibo &quot;%1&quot; para leitura.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>Erro ao ler arquivo de dados de Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>Não foi possível ler completamente os dados do Amiibo. O yuzu esperava ler %1 bytes, mas foi capaz de ler apenas %2 bytes.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>Erro ao carregar dados do Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>Não foi possível carregar os dados do Amiibo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>Capturar tela</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>Imagem PNG (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>Velocidade: %1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>Velocidade: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>Jogo: %1 FPS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>Quadro: %1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>O jogo que você está tentando carregar precisa que arquivos adicionais do seu Switch sejam extraídos antes de jogá-lo.&lt;br/&gt;&lt;br/&gt;Para saber mais sobre como extrair esses arquivos, visite a seguinte página da wiki: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Extraindo arquivos de sistema e fontes compartilhadas de um Switch&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt; Gostaria de voltar para a lista de jogos? Continuar com a emulação pode resultar em travamentos, dados salvos corrompidos ou outros problemas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>O yuzu não foi capaz de encontrar um arquivo de sistema do Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>O yuzu não foi capaz de encontrar um arquivo de sistema do Switch. %1. %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>Arquivo do sistema não encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>Arquivo de sistema faltando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>O yuzu não foi capaz de encontrar as fontes compartilhadas do Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>Fontes compartilhadas não encontradas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>Fonte compartilhada faltando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>Erro fatal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>O yuzu encontrou um erro fatal. Consulte o registro para mais detalhes. Para mais informações sobre como acessar o registro, consulte a seguinte página: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Como enviar o arquivo de registro&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Gostaria de voltar para a lista de jogos? Continuar com a emulação pode resultar em travamentos, dados salvos corrompidos ou outros problemas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>Erro fatal encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>Confirmar rederivação de chave</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>Você está prestes a rederivar todas as suas chaves forçadamente.
+Se você não sabe o que isso significa ou o que você está fazendo,
+esta é uma ação potencialmente destrutiva.
+Por favor, confirme que você quer mesmo fazer isto
+e opcionalmente faça cópias de segurança.
+
+Isto excluirá o seus arquivos de chaves geradas automaticamente, e reexecutar o módulo de derivação de chaves.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation>Faltando fusíveis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation> - Faltando BOOT0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation> - Faltando BCPKG2-1-Normal-Main</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation> - Faltando PRODINFO</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation>Faltando componentes de derivação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation>Há componentes faltando que podem impedir a conclusão do processo de derivação de chaves. &lt;br&gt;Por favor, siga &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;o guia de iniciação rápida&lt;/a&gt; para obter todas as suas chaves e jogos. &lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>Derivando chaves...
+Isto pode demorar até um minuto, dependendo
+do desempenho do seu sistema.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>Derivando chaves</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>Selecionar alvo de extração do RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>Selecione qual RomFS você quer extrair.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>Você deseja mesmo fechar o yuzu?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>Deseja mesmo parar a emulação? Qualquer progresso não salvo será perdido.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>O aplicativo rodando no momento solicitou ao yuzu para não sair.
+
+Deseja ignorar isso e sair mesmo assim?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation>OpenGL não disponível!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation>O yuzu não foi compilado com suporte para OpenGL.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation>Vulkan não disponível!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation>O yuzu não foi compilado com suporte para Vulkan.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation>Erro ao inicializar OpenGL 4.3!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation>Sua GPU pode não suportar OpenGL 4.3, ou você não tem os drivers gráficos mais recentes.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation>Erro ao inicializar o OpenGL!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation>Sua GPU pode não suportar uma ou mais extensões necessárias do OpenGL. Por favor, verifique se você possui a última versão dos drivers gráficos.&lt;br&gt;&lt;br&gt;Extensões não supportadas:&lt;br&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>Nome</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>Compatibilidade</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>Adicionais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>Tipo de arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>Tamanho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>Abrir local dos jogos salvos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Abrir local dos dados de mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>Abrir cache de shaders transferível</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation>Remover</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation>Remover atualização instalada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation>Remover todos os DLCs instalados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation>Remover cache de shaders</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation>Remover configuração customizada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation>Remover todo o conteúdo instalado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>Extrair RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>Copiar ID do título para a área de transferência</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>Abrir artigo do jogo no GameDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>Propriedades</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>Examinar subpastas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>Remover pasta de jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation>▲ Mover para cima</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation>▼ Mover para baixo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>Abrir local da pasta</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>Perfeito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>O jogo funciona impecavelmente, sem falhas gráficas ou de áudio. Todas as funcionalidades testadas
+do jogo funcionam como deveriam, sem nenhuma solução alternativa necessária.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>Ótimo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>O jogo funciona com leves falhas gráficas ou de áudio e é jogável do início ao fim. Pode exigir
+algumas soluções alternativas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>Razoável</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>O jogo funciona com graves falhas gráficas ou de áudio, mas é jogável do início ao fim
+com o uso de soluções alternativas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>Ruim</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>O jogo funciona, só que com problemas significativos nos gráficos ou no áudio. Não é possível progredir em áreas
+específicas por conta de tais problemas, mesmo com soluções alternativas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>Intro/menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>É impossível jogar o jogo devido a grandes problemas nos gráficos ou no áudio. Não é possível passar da
+tela inicial do jogo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Não inicia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>O jogo trava ou se encerra abruptamente ao se tentar iniciá-lo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>Não testado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>Esse jogo ainda não foi testado.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>Clique duas vezes para adicionar uma pasta à lista de jogos</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>Filtro:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>Digite o padrão para filtrar</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation>Por favor, confirme que esses são os arquivos que deseja instalar.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation>Instalar uma atualização ou DLC irá sobrescrever a instalada anteriormente.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation>Instalar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation>Instalar arquivos para a NAND</translation>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>Carregando shaders 387/1628</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>Carregando shaders (%v de %m)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>Tempo estimado 5m 4s</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>Carregando...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>Carregando shaders %1/%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>Iniciando...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>Tempo estimado %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>&amp;Arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>Arquivos recentes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>&amp;Emulação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>&amp;Exibir</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>Depuração</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>Ferramentas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>&amp;Ajuda</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation>Instalar arquivos para a NAND...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>Carregar arquivo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>Carregar pasta...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>S&amp;air</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>&amp;Iniciar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>&amp;Pausar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>&amp;Parar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>Reinicializar chaves...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>Sobre o yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>Modo de janela única</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>Configurar...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>Exibir barra de títulos de widgets afixados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>Exibir barra de filtro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>Exibir barra de status</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation>Restaurar tamanho padrão de janela</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>Tela cheia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>Reiniciar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>Carregar Amiibo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>Informar compatibilidade</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation>Abrir pagina de mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation>Abrir o guia de iniciação rápida</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation>FAQ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>Abrir pasta do yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>Capturar tela</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation>Configurar jogo atual..</translation>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>MicroProfile</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>Títulos instalados no SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>Títulos instalados na NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>Títulos do sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>Adicionar pasta de jogos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[não definido]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>Hat %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>Eixo %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>Botão %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[desconhecido]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation>Clique 0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation>Clique 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation>Clique 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation>Clique 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation>Clique 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation>Eixo GC %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation>Botão GC %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[não utilizado]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>Eixo %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation>Eixo GC %1</translation>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>Ocorreu um erro.
+Tente novamente ou entre em contato com o desenvolvedor do software.
+
+Código de erro: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>Ocorreu um erro em %1 em %2.
+Tente novamente ou entre em contato com o desenvolvedor do software.
+
+Código de erro: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>Ocorreu um erro.
+Código do erro: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>Selecione um usuário:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>Usuários</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>Seletor de perfil</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>Digite o texto:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>Teclado de software</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>Digite uma combinação de teclas</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>Pilha de chamadas</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>esperando pelo mutex 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>possui os waiters %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>manejo de proprietário: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>esperando por todos os objetos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>esperando por um dos seguintes objetos</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation>[%1]%2 %3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation>não aguardando pelo thread</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>rodando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>pronto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>pausado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>esperando pelo retorno do HLE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>dormindo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>esperando para resposta do IPC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>esperando por objetos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>esperando por mutex</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>aguardando por variável da condição</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>esperando para endereção o árbitro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>inativo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>morto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation>PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>ideal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>núcleo %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>Processador desconhecido %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>processador = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>núcleo ideal = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>máscara de afinidade = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>thread id = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>prioridade = %1(atual) / %2(normal)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>últimos ticks executados = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>não aguardando para mutex</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>aguardado pelo thread</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>Árvore de espera</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/pt_PT.ts b/dist/languages/pt_PT.ts
new file mode 100644
index 000000000..5ba0bcf3b
--- /dev/null
+++ b/dist/languages/pt_PT.ts
@@ -0,0 +1,4725 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_PT" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>Sobre Yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu é um emulador experimental de código aberto para a Nintendo Switch licenciado sob GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;Este software não deve ser usado para jogar jogos que você não tenha obtido legalmente.&lt;/span&gt;&lt;/p&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Site&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Código Fonte&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contribuidores&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licença&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; é uma marca comercial da Nintendo. Yuzu não é afiliado com a Nintendo de qualquer forma.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>Reportar Compatibilidade</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>Reportar compatibilidade de jogos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Se você optar por enviar um caso de teste para a&lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;lista de compatibilidade do yuzu&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;As seguintes informações serão coletadas e exibidas no site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Informações de Hardware (CPU / GPU / Sistema operativo)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Que versão do yuzu você está executando&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;A conta yuzu conectada&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>Perfeito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Jogo funciona na perfeição sem falhas de áudio ou gráficas.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>Ótimo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo funciona com pequenas falhas gráficas ou de áudio e pode ser jogado do início ao fim. Pode exigir algumas soluções alternativas.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo funciona com grandes falhas gráficas ou de áudio, mas o jogo é jogável do início ao fim com soluções alternativas.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>Mau</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo funciona, mas com grandes falhas gráficas ou de áudio. Não é possível progredir em áreas específicas devido a falhas, mesmo com soluções alternativas.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>Introdução / Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo não é jogável devido a grandes falhas gráficas ou de áudio. Não é possível passar da tela inicial.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Não Inicia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;O jogo trava ao tentar iniciar.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independente da velocidade ou performance, como este jogo funciona de principio ao fim nesta versão do yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>Obrigado pelo seu envio!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>Entregando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>Erro de comunicação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>Ocorreu um erro enquanto enviava o caso de teste</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>Próximo</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>Motor de Saída:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>Este efeito de pós-processamento ajusta a velocidade do áudio para corresponder à velocidade de emulação e ajuda a evitar o engasgue do audio. Isto, no entanto, aumenta a latência de áudio.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>Activar alongamento de audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>Dispositivo de áudio:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>Volume:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>Activar GDB Stub</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>Porta:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>Entrando</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>Filtro de registro global</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>Mostrar o registro da consola (Apenas Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>Abrir a localização do registro</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>Homebrew</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>Argumentos String</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>Ativar o Reporte de Serviços detalhado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>Isto vai ser resetado automáticamente quando o yuzu fechar.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>Avançado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation>Modo Quiosque</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>Configuração yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>Geral</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>IU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>Lista de Jogos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>Perfis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>Sistema de Ficheiros</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>Controlos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>Teclas de Atalhos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>Depurar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>Gráficos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>Audio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Rede</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>Serviços</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>Diretórios de armazenamento</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>Cartão SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>Cartão de jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>Caminho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>Inserido</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>Jogo Atual</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>Gestor de Patch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>Dump NSOs Descompactados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>Dump ExeFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation>Raiz dos Mods</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation>Raiz do Dump</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>Armazenamento em cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>Diretório do cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation>Metadata da Lista de Jogos em Cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>Resetar a Cache da Metadata</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>Selecione o Diretório NAND Emulado...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>Selecione o Diretório SD Emulado...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation>Selecione o Diretório do Cartão de Jogo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>Selecionar o diretório do Dump...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation>Selecionar o Diretório do Mod Load ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>Selecionar o diretório do Cache</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>O cache de metadata já está vazio.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>A operação foi completa com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>Não foi possível excluir o cache de metadata. Pode estar em uso ou inexistente.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>Geral</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>Percentagem do limitador de velocidade</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>Confirme a saída enquanto a emulação está em execução</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation>Solicitar para o utilizador na inicialização do jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>Pausar o emulador quando estiver em segundo plano</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>Usar cache do disk shader</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>Usar emulação assíncrona de GPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>Cor de fundo:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>Definições de Teclas de Atalho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation>Clique duas vezes numa ligação para alterá-la.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>Ação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>Tecla de Atalho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation> Contexto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>Sequência de teclas em conflito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>Jogador 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>Jogador 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>Jogador 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>Jogador 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>Jogador 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>Jogador 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>Jogador 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>Jogador 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>Avançado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>Configurar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Configurar Entrada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>Analógico Esquerdo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>Botôes de Rosto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>Analógico Direito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>Configurar Rato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>Botões do Rato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>Frente:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>Atrás:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>Esquerda:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>Meio:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>Direita:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>Limpar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[não configurado]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>Restaurar Padrões</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[pressiona a tecla]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>Gestor de Perfis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>Utilizador Atual</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>Nome de Utilizador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>Definir Imagem</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>Adicionar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>Renomear</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>Remover</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>O gestor de perfis só está disponível apenas quando o jogo não está em execução.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>Introduza o Nome de Utilizador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>Utilizadores</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>Introduza um nome de utilizador para o novo utilizador:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>Introduza um novo nome de utilizador:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>Confirmar para eliminar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>Estás preste a eliminar o utilizador com o nome &quot;%1&quot;. Tens a certeza?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>Definir Imagem de utilizador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>Imagens JPEG (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>Error ao eliminar a imagem</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>Ocorreu um erro ao tentar substituir imagem anterior em: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>Erro ao eliminar o arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>Não é possível eliminar o arquivo existente: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>Erro ao criar o diretório de imagens do utilizador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>Não é possível criar o diretório %1 para armazenar imagens do utilizador.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>Erro ao copiar a imagem do utilizador</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>Não é possível copiar a imagem de %1 para %2</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>O BCAT é a forma pela qual a Nintendo envia dados aos jogos para envolver a sua comunidade e desbloquear conteúdos adicionais.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation>BCAT Backend</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Saiba mais sobre o BCAT, Boxcat e eventos atuais&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation>O serviço boxcat está offline ou não estás ligado à Internet.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>Ocorreu um erro ao processar os dados do evento boxcat. Entre em contato com os desenvolvedores do yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>A versão em uso do yuzu é muito nova ou muito antiga para o servidor. Tente atualizar para a ultima versão oficial do yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation>De momento, não há eventos no boxcat.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation>Yuzu está a atualizar o boxcat ...</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>Configurações de Sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>Nota: isto pode ser substituído quando a configuração da região é de seleção automática</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>Japonês (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>Inglês</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>Francês (français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>Alemão (Deutsch)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>Italiano (italiano)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>Espanhol (español)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>Chinês</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>Coreano (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>Holandês (Nederlands)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>Português (português)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>Russo (Русский)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>Taiwanês</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>Inglês Britânico</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>Francês Canadense</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>Espanhol Latino-Americano</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>Chinês Simplificado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>Chinês Tradicional (正 體 中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>RTC personalizado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>Língua</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>Semente de RNG</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>Mono</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>Estéreo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>Surround</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>ID da consola:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>Modo de saída de som</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation>d MMM yyyy h:mm:ss AP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>Regenerar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>As configurações do sistema estão disponíveis apenas quando o jogo não está em execução.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>Isto substituirá o seu Switch virtual actual por um novo. Seu Switch virtual actual não será recuperável. Isso pode ter efeitos inesperados nos jogos. Isto pode falhar, se você usar uma gravação de jogo de configuração desatualizado. Continuar?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>Aviso</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>ID da Consola: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>Configurar Ecrã Táctil</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>Aviso: As configurações nesta página afectam o funcionamento interno da tela de toque emulada do yuzu. Alterá-los pode resultar em um comportamento indesejável, como a tela de toque não funcionando parcialmente ou até mesmo na sua totatildade. Você só deve usar esta página se souber o que está fazendo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>Parâmetros de Toque</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>Diâmetro de Toque Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>Dedo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>Diâmetro de Toque X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>Ângulo rotacional</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>Restaurar Padrões</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>Geral</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>Nota: Alterar o idioma aplicará sua configuração.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>Idioma da interface:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>Tema:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>Lista de Jogos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>Mostrar coluna de Add-Ons</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>Tamanho do ícone:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>Linha 1 Texto:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>Linha 2 Texto:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>Inglês</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Formato</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>Serviço Web do Yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>Ao fornecer seu nome de usuário e token, você concorda em permitir que o yuzu colete dados de uso adicionais, que podem incluir informações de identificação do usuário.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>Verificar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>Inscrever-se</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>Token: </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>Nome de usuário:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>O que é o meu token?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>Telemetria</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>Compartilhar dados de uso anônimos com a equipa Yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>Saber mais</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>ID de Telemetria:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>Regenerar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Presença do Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Mostrar o Jogo Atual no seu Estado de Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Saber mais&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Inscrever-se&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;O que é o meu Token?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>ID de Telemetria: 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>Não especificado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>Token não verificado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>O token não foi verificado. A alteração do token não foi gravada.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>A verificar...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>Verificação Falhada</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>Verificação Falhada. Verifique se introduziu seu nome de utilizador e o token correctamente e se a conexão com a Internet está operacional.</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Dados anônimos são coletados&lt;/a&gt;para ajudar a melhorar o yuzu.&lt;br/&gt;&lt;br/&gt;Gostaria de compartilhar seus dados de uso conosco?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>Telemetria</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>Falha na verificação de texto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation>A Carregar o Web Applet ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation>Sair do Web Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>Sair</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation>Para sair do aplicativo web, use os controlos fornecidos pelo jogo para selecionar sair, selecione a opção &apos;Sair do Web Applet&apos; na barra de menus ou pressione a tecla &apos;Enter&apos;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation>Web Applet</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>Esta versão do yuzu foi criada sem o suporte ao QtWebEngine, o que significa que o yuzu não pode exibir corretamente o manual do jogo ou a página da web solicitada.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>Velocidade da emulação actual. Valores acima ou abaixo de 100% indicam que a emulação está sendo executada mais depressa ou mais devagar do que a Switch</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>Quantos quadros por segundo o jogo está exibindo de momento. Isto irá variar de jogo para jogo e de cena para cena.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Tempo gasto para emular um frame da Switch, sem contar o a limitação de quadros ou o v-sync. Para emulação de velocidade máxima, esta deve ser no máximo 16.67 ms.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>Limpar Arquivos Recentes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>Aviso de Formato de Jogo Desactualizado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>Você está usando o formato de directório ROM desconstruído para este jogo, que é um formato desactualizado que foi substituído por outros, como NCA, NAX, XCI ou NSP. Os directórios de ROM não construídos não possuem ícones, metadados e suporte de actualização.&lt;br&gt;&lt;br&gt;Para uma explicação dos vários formatos de Switch que o yuzu suporta,&lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;Verifique a nossa Wiki&lt;/a&gt;. Esta mensagem não será mostrada novamente.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>Erro ao carregar o ROM!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>O formato do ROM não é suportado.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>Ocorreu um erro ao inicializar o núcleo do vídeo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>yuzu encontrou um erro ao executar o núcleo de vídeo, consulte o log para obter mais detalhes. Para obter mais informações sobre como acessar o log, consulte a seguinte página:&lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Como carregar o arquivo de log&lt;/a&gt;Assegure-se que tem os drivers gráficos mais recentes para sua GPU.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>Ocorreu um erro desconhecido. Por favor, veja o log para mais detalhes.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>Começar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>Save Data</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Mod Data</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>Erro ao abrir a pasta %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>A Pasta não existe!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>Erro ao abrir os Shader Cache transferíveis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>O Shader Cache para este titulo não existe.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>A Extração de RomFS falhou!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>Houve um erro ao copiar os arquivos RomFS ou o usuário cancelou a operação.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>Cheio</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation>Esqueleto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>Selecione o modo de despejo do RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>Por favor, selecione a forma como você gostaria que o RomFS fosse despejado&lt;br&gt;Full irá copiar todos os arquivos para o novo diretório enquanto&lt;br&gt;skeleton criará apenas a estrutura de diretórios.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>Extraindo o RomFS ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>Extração de RomFS Bem-Sucedida!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>A operação foi completa com sucesso.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>Erro ao abrir %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>Selecione o Diretório</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>Propriedades</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>As propriedades do jogo não puderam ser carregadas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Executáveis Switch (%1);;Todos os Ficheiros (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>Carregar Arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>Abrir o directório ROM extraído</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>Diretório inválido selecionado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>O diretório que você selecionou não contém um arquivo &apos;Main&apos;.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>Instalando arquivo &quot;%1&quot;...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>Aplicação do sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>Arquivo do sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>Atualização do aplicativo do sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>Pacote de Firmware (Tipo A)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>Pacote de Firmware (Tipo B)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>Jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>Actualização do Jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>DLC do Jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>Título Delta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>Selecione o tipo de instalação do NCA ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>Por favor, selecione o tipo de título que você gostaria de instalar este NCA como:
+(Na maioria dos casos, o padrão &apos;Jogo&apos; é suficiente).</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>Falha na instalação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>O tipo de título que você selecionou para o NCA é inválido.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>Arquivo não encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>Arquivo &quot;%1&quot; não encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>Continuar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>Visualização de erros</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>Conta Yuzu Ausente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>Para enviar um caso de teste de compatibilidade de jogos, você deve vincular sua conta yuzu.&lt;br&gt;&lt;br/&gt;Para vincular sua conta yuzu, vá para Emulação &amp;gt; Configuração &amp;gt; Rede.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>Arquivo Amiibo (%1);; Todos os Arquivos (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>Carregar Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>Erro ao abrir o arquivo de dados do Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>Não é possível abrir o arquivo Amiibo &quot;%1&quot; para leitura.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>Erro ao ler o arquivo de dados do Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>Não é possível ler completamente os dados do Amiibo. Espera-se que leia %1 bytes, mas só conseguiu ler %2 bytes.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>Erro ao carregar dados do Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>Não foi possível carregar os dados do Amiibo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>Captura de Tela</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>Imagem PNG (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>Velocidade: %1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>Velocidade: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>Jogo: %1 FPS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>Quadro: %1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>O jogo que você está tentando carregar requer arquivos adicionais do seu Switch para serem despejados antes de jogar.&lt;br/&gt;&lt;br/&gt;Para obter mais informações sobre como despejar esses arquivos, consulte a seguinte página da wiki:&lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Despejando arquivos do sistema e as fontes compartilhadas de uma consola Switch&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Você gostaria de regressar para a lista de jogos? Continuar a emulação pode resultar em falhas, dados de salvamento corrompidos ou outros erros.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>O yuzu não conseguiu localizar um arquivo de sistema do Switch. % 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>O yuzu não conseguiu localizar um arquivo de sistema do Switch: %1. %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>Arquivo do Sistema Não Encontrado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>Arquivo de Sistema em falta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>yuzu não conseguiu localizar as fontes compartilhadas do Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>Fontes compartilhadas não encontradas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>Fontes compartilhadas em falta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>Erro fatal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>yuzu encontrou um erro fatal, por favor veja o registro para mais detalhes. Para mais informações sobre como acessar o registro, por favor, veja a seguinte página:&lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Como carregar o arquivo de registro&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Você gostaria de regressar para a lista de jogos? Continuar a emulação pode resultar em falhas, dados de salvamento corrompidos ou outros erros.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>Ocorreu um Erro fatal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>Confirme a rederivação da chave</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>Você está prestes a forçar a rederivação de todas as suas chaves.
+Se você não sabe o que isso significa ou o que você está fazendo,
+esta é uma acção potencialmente destrutiva.
+Por favor, certifique-se que isto é o que você quer
+e opcionalmente faça backups.
+
+Isso irá excluir os seus arquivos de chave gerados automaticamente e executará novamente o módulo de derivação de chave.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>Derivando chaves ...
+Isto pode demorar até um minuto, dependendo
+do desempenho do seu sistema.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>Derivando Chaves</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>Selecione o destino de despejo do RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>Por favor, selecione qual o RomFS que você gostaria de despejar.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>Tem a certeza que quer fechar o yuzu?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>Tem a certeza de que quer parar a emulação? Qualquer progresso não salvo será perdido.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>O aplicativo atualmente em execução solicitou que o yuzu não fechasse.
+
+Deseja ignorar isso e sair mesmo assim?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>Nome</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>Compatibilidade</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>Acrescentos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>Tipo de Arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>Tamanho</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>Abrir Localização de Dados Salvos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Abrir a Localização de Dados do Mod</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>Abrir Shader Cache transferíveis</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>Despejar RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>Copiar título de ID para a área de transferência</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>Navegue para a Entrada da Base de Dados de Jogos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>Propriedades</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>Examinar Sub-pastas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>Remover diretório do Jogo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>Abrir Localização do diretório</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>Perfeito</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>O Jogo Funciona na Perfeição sem falhas de áudio ou gráficas, todas as funcionalidades testadas funcionam como planeadas sem
+quaisquer soluções alternativas necessárias.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>Ótimo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>O Jogo funciona com pequenas falhas gráficas ou de áudio e pode ser jogado do principio ao fim. Pode exigir algumas
+soluções alternativas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>O Jogo funciona com grandes falhas gráficas ou de áudio, mas o jogo é jogável do principio ao fim com
+soluções alternativas.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>Mau</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>Jogo Funcional, mas com grandes falhas gráficas ou de áudio. Incapaz de progredir em áreas específicas devido a falhas
+mesmo com soluções alternativas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>Introdução / Menu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>O Jogo não é jogável devido a grandes falhas gráficas ou de áudio. Não é possível passar da Tela
+Inicial</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Não Inicia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>O jogo trava ao tentar iniciar.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>Não Testado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>O jogo ainda não foi testado.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>Clique duas vezes para adicionar uma nova pasta à lista de jogos</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>Filtro:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>Digite o padrão para filtrar</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>A Carregar Shaders 387 / 1628</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>A Carregar Shaders %v por %m</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>Tempo Estimado 5m 4s</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>A Carregar...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>A Carregar Shaders %1 / %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>A iniciar...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>Tempo Estimado %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>&amp;Arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>Arquivos Recentes</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>&amp;Emulação</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>&amp;Vista</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>Depuração</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>Ferramentas</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>&amp;Ajuda</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>Carregar Arquivo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>Carregar Pasta</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>&amp;Sair</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>&amp;Começar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>&amp;Pausa</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>&amp;Parar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>Reinicialize as chaves ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>Sobre yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>Modo de Janela Única</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>Configurar ...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>Exibir Cabeçalhos de Ferramenta de Doca</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>Mostrar Barra de Filtros</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>Mostrar Barra de Estado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>Tela Cheia</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>Reiniciar</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>Carregar Amiibo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>Reportar Compatibilidade</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>Abrir Pasta yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>Captura de Tela</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>Micro Perfil</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>Títulos SD instalados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>Títulos NAND instalados</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>Títulos do sistema</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>Adicionar novo diretório de jogos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[não configurado]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>Hat %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>Eixo %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>Botão %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[Desconhecido]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[sem uso]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>Eixo %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>Ocorreu um erro.
+Tente novamente ou entre em contato com o desenvolvedor do software.
+
+Código do Erro: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>Ocorreu um erro em %1 até %2.
+Tente novamente ou entre em contato com o desenvolvedor do software.
+
+Código do Erro: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>Ocorreu um erro.
+Código de Erro: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>Selecione um usuário:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>Utilizadores</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>Selector de perfil</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>Digite o texto:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>Teclado de Software</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>Introduza a tecla de atalho</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>Pilha de Chamadas</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>esperando por mutex 0x% 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>has waiters: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>owner handle: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>esperando por todos os objetos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>esperando por todos os objectos</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>correr</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>preparado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>pausado</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>esperando pelo retorno de HLE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>dormindo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>aguardando resposta do IPC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>esperando por objectos</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>esperando por mutex</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>A espera da variável de condição</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>esperando pelo árbitro de endereço</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>dormente</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>morto</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation>PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>ideal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>núcleo %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>Processador desconhecido %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>processador = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>núcleo ideal =% 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>máscara de afinidade =% 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>id do segmento =% 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>prioridade =%1(atual) / %2(normal)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>últimos tiques em execução =%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>não esperar por mutex</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>esperado por tópico</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>Esquema de espera</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/ru_RU.ts b/dist/languages/ru_RU.ts
new file mode 100644
index 000000000..357b8e416
--- /dev/null
+++ b/dist/languages/ru_RU.ts
@@ -0,0 +1,4720 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ru_RU" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>О yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu - экспериментальный эмулятор для Nintendo Switch с открытым исходным кодом, лицензированный под GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;Это ПО не должно использоваться для запуска игр, которые были получены нелегально.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Веб-сайт&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Исходный код&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Авторы&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Лицензия&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; является торговой маркой Nintendo. yuzu никак не связан с Nintendo.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>Сообщить о совместимости</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>Сообщить о совместимости игры</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Если вы захотите отправить отчет в &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Список Совместимости yuzu&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, Следующая информация будет собрана и отображена на сайте:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Информация об Аппаратном Обеспечении (ЦП / ГП / Операционная Система)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Версия yuzu&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Подключенный аккаунт yuzu&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>Идеально</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Игра функционирует отлично, без звуковых и графических артефактов.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>Отлично</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Игра работает с небольшими графическими или звуковыми артефактами и может быть пройдена от начала до конца. Могут потребоваться обходные пути.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>Нормально</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Игра работает с существенными графическими или звуковыми артефактами, но с обходными путями может быть пройдена.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>Плохо</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Игра работает, но с существенными графическими или звуковыми артефактами. В некоторых зонах нельзя продвинуться даже с обходными путями.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>Вступление/Меню</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;В игру невозможно играть из-за графических или звуковых артефактов. Невозможно продвинуться дальше Стартового Экрана.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Не Запускается</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Игра падает при старте.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Независимо от скорости и производительности, насколько хорошо эта игра работает от начала до конца в текущей версии yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>Спасибо за ваш отчет!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>Отправка</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>Ошибка соединения</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>Произошла ошибка при отправке Отчета</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>Далее</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>Звук</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>Механизм вывода:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>Этот эффект пост-обработки регулирует скорость звука в соответствии со скоростью эмуляции и помогает предотвратить заикание звука. Это, однако, увеличивает задержку звука.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>Включить растяжение звука</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>Звуковое Устройство:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>Громкость:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>Включить GDB Stub</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>Порт:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>Журналирование</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>Глобальный Фильтр Журнала</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>Показывать Журнал в Консоли (Только Для Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>Открыть Расположение Журнала</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>Homebrew</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>Строка Аргументов</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>Включить Службы Подробных Отчётов</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>Это будет автоматически сброшено после закрытия yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>Дополнительно</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>Параметры yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>Основное</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>Интерфейс</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>Список Игр</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>Система</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>Профили</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>Файловая система</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>Управление</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>Горячие клавиши</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>Отладка</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>Графика</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>Звук</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>Веб</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>Сервисы</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>Директории Хранения</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>SD карта</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>Картридж</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>Путь</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>Вставлен</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>Текущая Игра</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>Управление Патчами</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>Дампить Распакованные NCO</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>Дампить ExeFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>Кэширование</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>Директория Кэша</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>Сбросить Кэш Метаданных</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>Выбрать Папку Для Эмулируемого NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>Выбрать Папку Для Эмулируемого SD</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>Выберите Папку с Дампами</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>Выбрать Папку с Кэшем...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>Кэш метаданных уже пустой.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>Операция выполнена успешно.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>Кэш метаданных не может быть удален. Он может использоваться или отсутствовать.</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>Основное</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>Ограничить Скорость в Процентах</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>Подтверждать выход во время эмуляции</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>Приостанавливать эмуляцию, когда в фоновом режиме</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>Использовать кэш шейдеров на диске</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>Использовать асинхронную эмуляцию ГП</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>Фоновый Цвет:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>Настройки Горячих Клавиш</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>Действие</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>Сочетание</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>Контекст</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>Конфликтующее Сочетание Клавиш</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>Игрок 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>Игрок 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>Игрок 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>Игрок 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>Игрок 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>Игрок 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>Игрок 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>Игрок 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>Дополнительно</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>Настроить</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>Настроить Ввод</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>Левый Стик</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>Основные Кнопки</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>Правый Стик</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>Настроить Мышь</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>Кнопки на Мыши</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>Вперед:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>Назад:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>Левая:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>Средняя:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>Правая:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>Очистить</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[не задано]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>Настройки по Умолчанию</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[нажмите кнопку]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>Управление Профилями</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>Текущий Пользователь</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>Имя Пользователя</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>Добавить Изображение</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>Добавить</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>Переименовать</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>Удалить</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>Управление профилями доступно только тогда, когда игра не запущена.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>Введите Имя Пользователя</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>Пользователи</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>Введите имя пользователя для нового профиля:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>Введите новое имя пользователя:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>Подтвердите Удаление</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>Вы собираетесь удалить пользователя &quot;%1&quot;. Вы уверены?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>Выберите Изображение для Пользователя</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>JPEG Images (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>Ошибка при удалении изображения</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>Ошибка при попытке перезаписи предыдущего изображения в: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>Ошибка при удалении файла</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>Не получилось удалить существующий файл: %1.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>Ошибка при создании папки пользовательских изображений</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>Не получилось создать папку %1 для хранения изображений пользователя.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>Ошибка при копировании изображения пользователя</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>Не получилось скопировать изображение из %1 в %2</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>BCAT - это способ Nintendo отправлять данные в игры, чтобы привлечь сообщество и разблокировать дополнительный контент.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>Произошла ошибка при обработке данных событий boxcat. Свяжитесь с разработчиками yuzu.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>Используемая вами версия yuzu слишком новая или слишком старая по сравнению с версией на сервере. Попробуйте обновить yuzu до последней официальной версии.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>Настройки Системы</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>Примечание: может быть перезаписано если регион выбирается автоматически</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>Японский (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>Английский (English)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>Французский (français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>Немецкий (Deutsch)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>Итальянский (italiano)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>Испанский (español)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>Китайский (Chinese)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>Корейский (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>Голландский (Nederlands)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>Португальский (português)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>Русский</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>Тайваньский</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>Британский Английский</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>Канадский Французский</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>Латиноамериканский Испанский</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>Упрощенный Китайский</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>Традиционный Китайский (正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>Пользовательский RTC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>Язык</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>Зерно RNG</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>Моно</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>Стерео</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>Объёмный звук</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>Идентификатор Консоли:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>Режим вывода звука</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>Перегенерировать</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>Настройки системы доступны только тогда, когда игра не запущена.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>Это заменит ваш текущий виртуальный Switch новым. Ваш текущий виртуальный Switch будет безвозвратно потерян. Это может иметь неожиданные последствия в играх. Может не сработать, если вы используете устаревшую конфигурацию сохраненных игр. Продолжить?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>Внимание</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>Идентификатор Консоли: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>Настроить Сенсорный Экран</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>Внимание: Настройки на этой странице влияют на внутреннюю работу эмулируемого сенсорного экрана yuzu. Их изменение может привести к нежелательному поведению, как например частичная или полная неработоспособность сенсорного экрана. Используйте их, только если вы знаете, что делаете.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>Параметры Касания</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>Диаметр Касания Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>Палец</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>Диаметр Касания X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>Угол Поворота</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>Настройки по Умолчанию</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>Основное</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>Примечание: Изменение языка приведет к применению настроек.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>Язык интерфейса:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>Тема:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>Список Игр</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>Показывать Столбец Дополнений</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>Размер Иконок:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>Текст 1 Строки:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>Текст 2 Строки:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>Английский</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>yuzu Веб Сервис</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>Предоставляя ваше имя пользователя и токен, вы разрешаете yuzu собирать дополнительную информацию об использовании, которая может включать данные идентифицирующие пользователя.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>Подтвердить</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>Регистрация</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>Токен:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>Имя Пользователя:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>Что такое токен?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>Телеметрия</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>Делиться анонимной информацией об использовании с командой yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>Узнать больше</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>ID Телеметрии:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>Перегенерировать</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Интеграция с Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>Показывать Текущую Игру в вашем Статусе Discord</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Узнать больше&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Регистрация&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Что такое токен?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>ID Телеметрии: 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>Отсутствует</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>Токен не подтвержден</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>Токен не подтвержден. Ваш токен не был изменен.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>Проверка...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>Ошибка подтверждения</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>Ошибка подтверждения. Убедитесь в том, что токен введен корректно, и ваше интернет соединение активно.</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Анонимные данные собираются&lt;/a&gt; для улучшения yuzu. &lt;br/&gt;&lt;br/&gt;Хотели бы вы делиться данными об использовании с нами?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>Телеметрия</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>Ошибка Проверки Текста</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>Выход</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>Эта версия yuzu была собрана без поддержки QtWebEngine, что означает, что yuzu не может нормально отобразить руководство к игре или запрошенную веб-страницу.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>Текущая скорость эмуляции. Значения выше или ниже 100% указывают на то, что эмуляция идет быстрее или медленнее, чем на Switch.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>Количество кадров в секунду в данный момент. Значение будет меняться от игры к игре и от сцене к сцене.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>Время, которое нужно для эмуляции 1 кадра Switch, не принимая во внимание ограничение FPS или v-sync. Для полноскоростной эмуляции значение должно быть не больше 16,67 мс.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>Очистить Недавние Файлы</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>Предупреждение Устаревший Формат Игры</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>Для этой игры вы используете разархивированный формат РОМа, который является устаревшим и был заменен другими, такими как NCA, NAX, XCI или NSP. В разархивированных каталогах РОМа отсутствуют значки, метаданные и поддержка обновлений. &lt;br&gt;&lt;br&gt;Для получения информации о различных форматах Switch, поддерживаемых yuzu, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;просмотрите нашу вики&lt;/a&gt;. Это сообщение больше не будет отображаться.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>Ошибка при загрузке РОМа!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>Формат РОМа не поддерживается.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>Произошла ошибка при инициализации видеоядра.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>yuzu обнаружил ошибку во время работы видеоядра. Проверьте журнал для подробностей. Информацию о доступе к журналу можно найти на этой странице: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Как Отправить Файл Журнала.&lt;/a&gt; Убедитесь, что у вас установлены последние графические драйверы.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>Произошла неизвестная ошибка. Пожалуйста, проверьте лог для подробностей.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>Начать</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>Данные Сохранений</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Данные Модов</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>Ошибка при Открытии Папки %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>Папка не существует!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>Ошибка при Открытии Переносного Кеша Шейдеров</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>Шейдерный кеш для этого идентификатора не существует.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>Не удалось извлечь RomFS!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>Произошла ошибка при копировании файлов RomFS или пользователь отменил операцию.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>Полный</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>Выберите Режим Дампа RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>Пожалуйста, выберите, как вы хотите выполнить дамп RomFS. &lt;br&gt;Полное скопирует все файлы в новый каталог, в то время как &lt;br&gt;Структура создаст только структуру каталогов.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>Извлечение RomFS...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>Извлечение RomFS Прошло Успешно!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>Операция выполнена.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>Ошибка Открытия %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>Выбрать Путь</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>Свойства</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>Не удалось загрузить свойства игры.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Исполняемый файл Switch (%1);;Все файлы (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>Загрузить Файл</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>Открыть Папку Извлечённого РОМа</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>Выбран Неверный Каталог</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>Каталог, который вы выбрали, не содержит «основного» файла.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>Установка файла &quot;%1&quot;...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>Системное Приложение</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>Системный Архив</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>Обновление Системного Приложения</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>Контейнер Прошивки (Тип А)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>Контейнер Прошивки (Тип Б)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>Игра</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>Обновление Игры</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>Загружаемый Контент</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>Delta Название</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>Выберите Тип Установки NCA...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>Пожалуйста, выберите тип приложения, который вы хотите установить для этого NCA:
+ (В большинстве случаев, простое «Игра» подходит.)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>Ошибка Установки</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>Тип приложения, который вы выбрали для NCA, недействителен.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>Файл не найден</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>Файл &quot;%1&quot; не найден</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>Продолжить</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>Показ Ошибок</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>Отсутствует Аккаунт yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>Чтобы отправить отчет о совместимости игры, необходимо привязать свою учетную запись yuzu.&lt;br&gt;&lt;br/&gt;Чтобы привязать свою учетную запись yuzu, перейдите в раздел Эмуляция &amp;gt; Настройка &amp;gt; Веб.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>Файл Amiibo (%1);; Все Файлы (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>Загрузить Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>Ошибка открытия файла данных Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>Невозможно открыть файл Amiibo &quot;%1&quot; для чтения.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>Ошибка чтения файла данных Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>Невозможно полностью прочитать данные Amiibo. Ожидалось прочитать %1 байт, но удалось прочитать только %2 байт.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>Ошибка загрузки данных Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>Невозможно загрузить данные Amiibo.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>Сделать Скриншот</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG Image (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>Скорость: %1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>Скорость: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>Игра: %1 FPS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>Один кадр: %1 ms</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>Игра, которую вы пытаетесь загрузить, требует, чтобы дополнительные файлы были сдамплены с вашего Switch перед началом игры. &lt;br/&gt;&lt;br/&gt;Для получения дополнительной информации о дампе этих файлов см. следующую вики-страницу: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Дамп Системных Архивов и Общих Шрифтов с консоли&lt;/a&gt;. &lt;br/&gt;&lt;br/&gt;Хотите вернуться к списку игр? Продолжение эмуляции может привести к сбоям, повреждению сохраненных данных или другим ошибкам.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>yuzu не удалось найти системный архив Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>yuzu не удалось найти системный архив Switch: %1. %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>Системный Архив Не Найден</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>Отсутствует Системный Архив</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>yuzu не удалось найти общие шрифты Switch. %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>Общие Шрифты Не Найдены</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>Общие Шрифты Отсутствуют</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>Фатальная Ошибка</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>yuzu столкнулся с фатальной ошибкой, смотрите подробности в журнале. Информацию о доступе к журналу можно найти на этой странице: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Как Отправить Файл Журнала&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Хотите вернуться в список игр? Продолжение эмуляции может привести к сбоям, повреждению сохраненных данных или другим ошибкам.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>Обнаружена Фатальная ошибка</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>Подтвердите Перерасчет Ключа</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>Вы собираетесь принудительно пересчитать все ваши ключи.
+Если вы не знаете, что это значит или что вы делаете,
+это потенциально разрушительное действие.
+Пожалуйста, убедитесь, что это то, что вы хотите
+и при желании сделайте резервные копии.
+
+Это удалит ваши автоматически сгенерированные файлы ключей и повторно запустит модуль расчета ключей.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>Получение ключей...
+Это может занять до минуты в зависимости
+от производительности вашей системы.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>Получение Ключей</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>Выберите Цель для Дампа RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>Пожалуйста, выберите, какой RomFS вы хотите сдампить.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>Вы уверены, что хотите закрыть yuzu?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>Вы уверены, что хотите остановить эмуляцию? Любой несохраненный прогресс будет потерян.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>Запущенное в настоящий момент приложение просит yuzu не завершать работу.
+
+Проигнорировать и выйти в любом случае?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>Имя</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>Совместимость</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>Дополнения</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>Тип Файла</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>Размер</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>Открыть Папку Сохранений</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>Открыть Папку Модов</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>Открыть Переносной Кеш Шейдеров</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>Сдампить RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>Скопировать ID приложения в буфер обмена</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>Перейти к записи GameDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>Свойства</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>Сканировать Подпапки</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>Удалить Папку с Играми</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>Открыть Расположение Папки</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>Идеально</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>Игра идёт безупречно, без звуковых или графических артефактов, все протестированные функции работают без обходных путей.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>Отлично</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>Игра работает с небольшими графическими или звуковыми артефактами и может быть пройдена от начала до конца. Могут потребоваться обходные пути.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>Нормально</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>Игра работает с существенными графическими или звуковыми артефактами, но с обходными путями может быть пройдена.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>Плохо</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>Игра работает, но с существенными графическими или звуковыми артефактами. В некоторых зонах нельзя продвинуться даже с обходными путями.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>Вступление/Меню</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>В игру невозможно играть из-за графических или звуковых артефактов. Невозможно продвинуться дальше Стартового Экрана.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>Не Запускается</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>Игра падает при запуске.</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>Не Проверено</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>Игру ещё не проверяли на совместимость.</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>Двойной клик, чтобы добавить новую папку в список игр</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>Поиск:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>Введите текст для поиска</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>Загрузка Шейдера 387 / 1628</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>Загрузка Шейдера %v из %m</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>Примерное время 5м 4с</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>Загрузка...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>Загрузка Шейдеров %1 / %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>Запуск...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>Примерное Время %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>&amp;Файл</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>Недавние Файлы</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>&amp;Эмуляция</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>&amp;Вид</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>Отладка</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>Инструменты</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>&amp;Помощь</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>Загрузить Файл...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>Загрузить Папку...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>&amp;Выход</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>&amp;Начать</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>&amp;Пауза</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>&amp;Стоп</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>Переинициализировать ключи...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>О yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>Режим Одного Окна</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>Настроить...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>Отображать Заголовки Виджетов Дока</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>Показать Панель Поиска</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>Показать Панель Статуса</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>Полный Экран</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>Перезапустить</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>Загрузить Amiibo…</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>Сообщить о Совместимости</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>Открыть Папку yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>Сделать Скриншот</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>МикроПрофиль</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>Установленные SD Игры</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>Установленные NAND Игры</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>Системные Игры</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>Добавить Новую Папку с Играми</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[не задано]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>Д-Пад %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>Ось %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>Кнопка %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[неизвестно]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[не используется]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>Ось %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>Произошла ошибка.
+Пожалуйста попробуйте еще раз или свяжитесь с разработчиком ПО.
+
+Код Ошибки: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>Произошла ошибка на %1 в %2.
+Пожалуйста попробуйте еще раз или свяжитесь с разработчиком ПО.
+
+Код Ошибки: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>Произошла ошибка.
+Код Ошибки: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>Выберите Пользователя:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>Пользователи</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>Выбор Профиля</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>Введите текст:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>Программная Клавиатура</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>Введите сочетание</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>Стэк вызовов</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>ожидание мьютекса 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>ожидающие: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>ссылка на владельца: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>в ожидании всех объектов</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>в ожидании одного из объектов</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>работает</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>готов</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>приостановлен</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>ожидание возврата HLE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>сон</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>ожидание ответа IPC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>ожидание объектов</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>ожидание мьютекса</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>ожидание условной переменной </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>ожидание адресного арбитра</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>бездействует</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>мертв</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation> PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>идеально</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>ядро %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>Неизвестный процессор %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>процессор = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>идеальное ядро = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>маска сходства = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>id потока = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>приоритет = %1(текущий) / %2(обычный)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>последние тики = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>не ожидает мьютекс</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>ожидается потоком</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>Дерево Ожидания</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/languages/zh_CN.ts b/dist/languages/zh_CN.ts
new file mode 100644
index 000000000..f953f224a
--- /dev/null
+++ b/dist/languages/zh_CN.ts
@@ -0,0 +1,4747 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_CN" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="14"/>
+ <source>About yuzu</source>
+ <translation>关于 yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="30"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="60"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:28pt;&quot;&gt;yuzu&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="73"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="86"/>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu 是一个实验性的开源 Nintendo Switch 模拟器,以 GPLv2.0+ 授权。&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;这个软件不应该用来运行非法取得的游戏。&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="118"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;网站&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;源代码&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;贡献者&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;许可证&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/aboutdialog.ui" line="134"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:7pt;&quot;&gt;&amp;quot;Nintendo Switch&amp;quot; 是任天堂的商标。yuzu 与任天堂没有任何关系。&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>CalibrationConfigurationDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="25"/>
+ <source>Communicating with the server...</source>
+ <translation>正在与服务器通信…</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="26"/>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="44"/>
+ <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
+ <translation>触摸你的触摸板&lt;br&gt;的左上角。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="47"/>
+ <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
+ <translation>触摸你的触摸板&lt;br&gt;的右下角。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="50"/>
+ <source>Configuration completed!</source>
+ <translation>配置完成!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="55"/>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+</context>
+<context>
+ <name>CompatDB</name>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="20"/>
+ <source>Report Compatibility</source>
+ <translation>报告兼容性</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="27"/>
+ <location filename="../../src/yuzu/compatdb.ui" line="63"/>
+ <source>Report Game Compatibility</source>
+ <translation>报告游戏兼容性</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="36"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;如果您选择向 &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu 兼容性列表&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;提交测试用例的话,以下信息将会被收集并显示在网站上:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;设备硬件信息 (CPU / GPU / 操作系统)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;您正在使用的 yuzu 版本&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;已关联的 yuzu 账户信息&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="72"/>
+ <source>Perfect</source>
+ <translation>完美</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions flawlessly with no audio or graphical glitches.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;游戏运行完美,没有音频或图形问题。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="89"/>
+ <source>Great </source>
+ <translation>良好</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="96"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;游戏运行时会有非常轻微的图像或音频问题,但是能从头玩到尾。可能需要一些技巧才能完成游戏。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="106"/>
+ <source>Okay</source>
+ <translation>一般</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="113"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;游戏运行时会有很多图像或音频错误,但是在使用一些特殊技巧之后能完整地完成游戏。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="123"/>
+ <source>Bad</source>
+ <translation>较差</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="130"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;游戏能运行,但是会有大量图像或音频错误。即使使用一些技巧也无法通过游戏的某些区域。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="140"/>
+ <source>Intro/Menu</source>
+ <translation>开场 / 菜单</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="147"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;游戏完全没法玩,图像或音频有重大错误。通过开场菜单后无法继续。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="157"/>
+ <source>Won&apos;t Boot</source>
+ <translation>无法打开</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="170"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The game crashes when attempting to startup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;在启动游戏时直接崩溃了。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="182"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;body&gt;&lt;html&gt;&lt;head/&gt;&lt;p&gt;在不考虑速度或帧率的情况下,使用此版本 yuzu 玩这款游戏的情况如何?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.ui" line="206"/>
+ <source>Thank you for your submission!</source>
+ <translation>感谢您向我们提交信息!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="61"/>
+ <source>Submitting</source>
+ <translation>提交中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="74"/>
+ <source>Communication error</source>
+ <translation>网络错误</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="75"/>
+ <source>An error occured while sending the Testcase</source>
+ <translation>在提交测试用例时发生错误。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/compatdb.cpp" line="77"/>
+ <source>Next</source>
+ <translation>下一步</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureAudio</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="17"/>
+ <source>Audio</source>
+ <translation>声音</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="25"/>
+ <source>Output Engine:</source>
+ <translation>输出引擎:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="37"/>
+ <source>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</source>
+ <translation>这种后处理效果可以调整音频速度以匹配模拟速度,并有助于防止音频卡顿。 但是会增加音频延迟。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="40"/>
+ <source>Enable audio stretching</source>
+ <translation>启动音频拉伸</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="49"/>
+ <source>Audio Device:</source>
+ <translation>音频设备:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="77"/>
+ <source>Use global volume</source>
+ <translation>使用全局音量</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="82"/>
+ <source>Set volume:</source>
+ <translation>音量:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="90"/>
+ <source>Volume:</source>
+ <translation>音量:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.ui" line="135"/>
+ <source>0 %</source>
+ <translation>0 %</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="98"/>
+ <source>%1%</source>
+ <comment>Volume percentage (e.g. 50%)</comment>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpu</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/>
+ <source>Form</source>
+ <translation>类型</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="22"/>
+ <source>General</source>
+ <translation>通用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="30"/>
+ <source>Accuracy:</source>
+ <translation>精度:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="38"/>
+ <source>Accurate</source>
+ <translation>精确</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="43"/>
+ <source>Unsafe</source>
+ <translation>低精度</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="48"/>
+ <source>Enable Debug Mode</source>
+ <translation>启用调试模式</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="61"/>
+ <source>We recommend setting accuracy to &quot;Accurate&quot;.</source>
+ <translation>我们推荐将精度设置为“精确”。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="75"/>
+ <source>Unsafe CPU Optimization Settings</source>
+ <translation>低精度 CPU 优化选项</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="84"/>
+ <source>These settings reduce accuracy for speed.</source>
+ <translation>这些设置项提高了速度,但精度有所降低。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
+ <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
+ <translation>低精度 FMA (在 CPU 不支持 FMA 指令集的情况下提高性能)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="94"/>
+ <source>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;该选项通过降低积和熔加运算的精度而提高模拟器在不支持 FMA 指令集 CPU 上的运行速度。&lt;/div&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="103"/>
+ <source>Faster FRSQRTE and FRECPE</source>
+ <translation>快速 FRSQRTE 和 FRECPE</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
+ <source>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;该选项通过使用精度较低的近似值来提高某些浮点函数的运算速度。&lt;/div&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="133"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>只有当游戏不在运行时,CPU 设置才可用。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="43"/>
+ <source>Setting CPU to Debug Mode</source>
+ <translation>CPU 调试模式</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu.cpp" line="44"/>
+ <source>CPU Debug Mode is only intended for developer use. Are you sure you want to enable this?</source>
+ <translation>CPU 调试模式仅用于开发人员。您确定要打开这个选项吗?</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureCpuDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>类型</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="22"/>
+ <source>Toggle CPU Optimizations</source>
+ <translation>切换 CPU 优化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
+ <source>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is &quot;Debug Mode&quot;.
+ &lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;
+&lt;b&gt;仅供调试使用。&lt;/b&gt;
+&lt;br&gt;
+如果您不确定这些选项的作用,则保持它们的启用状态。
+&lt;br&gt;
+这些选项仅在 CPU 精度处于“调试模式”时生效。
+&lt;/div&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="46"/>
+ <source>Enable inline page tables</source>
+ <translation>启用内嵌页表</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="49"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div style=&quot;white-space: nowrap&quot;&gt;这个选项提升了来宾程序的内存访问速度。&lt;/div&gt;
+&lt;div style=&quot;white-space: nowrap&quot;&gt;启用内嵌到 PageTable::指向已发射代码的指针。&lt;/div&gt;
+&lt;div style=&quot;white-space: nowrap&quot;&gt;禁用此选项将强制通过 Memory::Read/Memory::Write 函数进行内存访问。&lt;/div&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
+ <source>Enable block linking</source>
+ <translation>启用块链接</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="63"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;该选项通过允许发出的基本块直接跳转到其他基本块(如果目标 PC 是静态的)来避免调度器的查找。&lt;/div&gt;
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
+ <source>Enable return stack buffer</source>
+ <translation>启用返回堆栈缓冲区</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="75"/>
+ <source>
+ &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;该选项通过跟踪 BL 指令的潜在返回地址来避免调度器查找。这近似于 CPU 返回堆栈缓冲区的情况。&lt;/div&gt;
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
+ <source>Enable fast dispatcher</source>
+ <translation>启用快速调度</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="87"/>
+ <source>
+ &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;启用两层调度系统。首先使用一个更快的调度程序跳转至目标 MRU 缓存。如果失败,调度返回到较慢的 C++ 调度程序。&lt;/div&gt;
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
+ <source>Enable context elimination</source>
+ <translation>启用上下文消除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="99"/>
+ <source>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;启用 IR 优化,以减少 CPU 对上下文结构的不必要访问。&lt;/div&gt;
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
+ <source>Enable constant propagation</source>
+ <translation>启用恒定传播</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="111"/>
+ <source>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;启用涉及恒定传播的 IR 优化。&lt;/div&gt;
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
+ <source>Enable miscellaneous optimizations</source>
+ <translation>启用其他优化</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="123"/>
+ <source>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div&gt;启用其他的 IR 优化。&lt;/div&gt;
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="132"/>
+ <source>Enable misalignment check reduction</source>
+ <translation>减少偏差检查</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="135"/>
+ <source>
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </source>
+ <translation>
+&lt;div style=&quot;white-space: nowrap&quot;&gt;启用时,只有当访问越过页面边界时才会触发偏移。&lt;/div&gt;
+&lt;div style=&quot;white-space: nowrap&quot;&gt;禁用时,所有未对齐的访问都会触发偏移。&lt;/div&gt;
+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="163"/>
+ <source>CPU settings are available only when game is not running.</source>
+ <translation>只有当游戏不在运行时,CPU 设置才可用。</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebug</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="22"/>
+ <source>GDB</source>
+ <translation>GDB</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="30"/>
+ <source>Enable GDB Stub</source>
+ <translation>开启 GDB 调试</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="50"/>
+ <source>Port:</source>
+ <translation>端口:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="71"/>
+ <source>Logging</source>
+ <translation>日志</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="79"/>
+ <source>Global Log Filter</source>
+ <translation>全局日志过滤器</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="93"/>
+ <source>Show Log Console (Windows Only)</source>
+ <translation>显示日志窗口(仅限 Windows)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="100"/>
+ <source>Open Log Location</source>
+ <translation>打开日志位置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="112"/>
+ <source>Homebrew</source>
+ <translation>自制游戏</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="120"/>
+ <source>Arguments String</source>
+ <translation>参数字符串</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="135"/>
+ <source>Graphics</source>
+ <translation>图形</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="144"/>
+ <source>When checked, the graphics API enters in a slower debugging mode</source>
+ <translation>启用时,图形 API 将进入较慢的调试模式。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="147"/>
+ <source>Enable Graphics Debugging</source>
+ <translation>启用图形调试</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="157"/>
+ <source>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</source>
+ <translation>启用时,将禁用宏即时编译器。这会降低游戏运行速度。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="160"/>
+ <source>Disable Macro JIT</source>
+ <translation>禁用宏 JIT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="170"/>
+ <source>Dump</source>
+ <translation>转储</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="176"/>
+ <source>Enable Verbose Reporting Services</source>
+ <translation>启用详细报告服务</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
+ <source>This will be reset automatically when yuzu closes.</source>
+ <translation>当 yuzu 关闭时会自动重置。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
+ <source>Advanced</source>
+ <translation>高级选项</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug.ui" line="207"/>
+ <source>Kiosk (Quest) Mode</source>
+ <translation>Kiosk (Quest) 模式</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDebugController</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
+ <source>Configure Debug Controller</source>
+ <translation>调试控制器设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
+ <source>Clear</source>
+ <translation>清除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
+ <source>Defaults</source>
+ <translation>系统默认</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureDialog</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
+ <source>yuzu Configuration</source>
+ <translation>yuzu 设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="48"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="51"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="86"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="120"/>
+ <source>General</source>
+ <translation>通用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="132"/>
+ <source>UI</source>
+ <translation>界面</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="59"/>
+ <source>Game List</source>
+ <translation>游戏列表</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="64"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="67"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="121"/>
+ <source>System</source>
+ <translation>系统</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="72"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="75"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="122"/>
+ <source>Profiles</source>
+ <translation>用户配置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="80"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="83"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="133"/>
+ <source>Filesystem</source>
+ <translation>文件系统</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="91"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="123"/>
+ <source>Controls</source>
+ <translation>控制</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="99"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="124"/>
+ <source>Hotkeys</source>
+ <translation>热键</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="104"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="107"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="125"/>
+ <source>CPU</source>
+ <translation>CPU</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="112"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="115"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="144"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="147"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="126"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="130"/>
+ <source>Debug</source>
+ <translation>调试</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="120"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="123"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="89"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="127"/>
+ <source>Graphics</source>
+ <translation>图形</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="128"/>
+ <source>Advanced</source>
+ <translation>高级选项</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="131"/>
+ <source>GraphicsAdvanced</source>
+ <translation>高级图形选项</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="136"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="139"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="90"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="129"/>
+ <source>Audio</source>
+ <translation>声音</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="152"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="155"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="131"/>
+ <source>Web</source>
+ <translation>网络</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="160"/>
+ <location filename="../../src/yuzu/configuration/configure.ui" line="163"/>
+ <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="134"/>
+ <source>Services</source>
+ <translation>服务</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureFilesystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/>
+ <source>Form</source>
+ <translation>类型</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="22"/>
+ <source>Storage Directories</source>
+ <translation>存储目录</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="28"/>
+ <source>NAND</source>
+ <translation>NAND</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="35"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="111"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="140"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="230"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="48"/>
+ <source>SD Card</source>
+ <translation>SD 卡</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="81"/>
+ <source>Gamecard</source>
+ <translation>游戏卡带</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="87"/>
+ <source>Path</source>
+ <translation>路径</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="97"/>
+ <source>Inserted</source>
+ <translation>已插入</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="104"/>
+ <source>Current Game</source>
+ <translation>当前游戏</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="121"/>
+ <source>Patch Manager</source>
+ <translation>补丁管理</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="149"/>
+ <source>Dump Decompressed NSOs</source>
+ <translation>转储已解压的 NSO 文件</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="156"/>
+ <source>Dump ExeFS</source>
+ <translation>转储 ExeFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="165"/>
+ <source>Mod Load Root</source>
+ <translation>Mod 加载根目录</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="172"/>
+ <source>Dump Root</source>
+ <translation>转储根目录</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="198"/>
+ <source>Caching</source>
+ <translation>缓存中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="204"/>
+ <source>Cache Directory</source>
+ <translation>缓存目录</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="239"/>
+ <source>Cache Game List Metadata</source>
+ <translation>缓存游戏列表数据</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="246"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="128"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="133"/>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="138"/>
+ <source>Reset Metadata Cache</source>
+ <translation>重置缓存数据</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="92"/>
+ <source>Select Emulated NAND Directory...</source>
+ <translation>选择模拟 NAND 目录...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="95"/>
+ <source>Select Emulated SD Directory...</source>
+ <translation>选择模拟 SD 卡目录...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="98"/>
+ <source>Select Gamecard Path...</source>
+ <translation>选择游戏卡带路径...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="101"/>
+ <source>Select Dump Directory...</source>
+ <translation>选择转储目录...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="104"/>
+ <source>Select Mod Load Directory...</source>
+ <translation>选择 Mod 载入目录...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="107"/>
+ <source>Select Cache Directory...</source>
+ <translation>选择缓存目录...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="129"/>
+ <source>The metadata cache is already empty.</source>
+ <translation>缓存数据已为空。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="134"/>
+ <source>The operation completed successfully.</source>
+ <translation>操作已成功完成。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="139"/>
+ <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
+ <translation>缓存数据删除失败。它可能不存在或正在被使用。</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGeneral</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="22"/>
+ <source>General</source>
+ <translation>通用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="32"/>
+ <source>Limit Speed Percent</source>
+ <translation>运行速度限制</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="39"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="57"/>
+ <source>Multicore CPU Emulation</source>
+ <translation>多核 CPU 仿真</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="64"/>
+ <source>Confirm exit while emulation is running</source>
+ <translation>在游戏运行时退出需要确认</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="71"/>
+ <source>Prompt for user on game boot</source>
+ <translation>游戏启动时提示选择用户</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="78"/>
+ <source>Pause emulation when in background</source>
+ <translation>模拟器位于后台时暂停模拟</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_general.ui" line="85"/>
+ <source>Hide mouse on inactivity</source>
+ <translation>自动隐藏鼠标光标</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphics</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="22"/>
+ <source>API Settings</source>
+ <translation>API 设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="46"/>
+ <source>API:</source>
+ <translation>API:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="67"/>
+ <source>Device:</source>
+ <translation>设备:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="83"/>
+ <source>Graphics Settings</source>
+ <translation>图形设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="89"/>
+ <source>Use disk shader cache</source>
+ <translation>使用磁盘着色器缓存</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="96"/>
+ <source>Use asynchronous GPU emulation</source>
+ <translation>使用 GPU 异步模拟</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="118"/>
+ <source>Aspect Ratio:</source>
+ <translation>屏幕纵横比:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="126"/>
+ <source>Default (16:9)</source>
+ <translation>默认 (16:9)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="131"/>
+ <source>Force 4:3</source>
+ <translation>强制 4:3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="136"/>
+ <source>Force 21:9</source>
+ <translation>强制 21:9</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="141"/>
+ <source>Stretch to Window</source>
+ <translation>拉伸窗口</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="186"/>
+ <source>Use global background color</source>
+ <translation>使用全局背景颜色</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="191"/>
+ <source>Set background color:</source>
+ <translation>设置背景颜色:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="199"/>
+ <source>Background Color:</source>
+ <translation>背景颜色:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="196"/>
+ <source>OpenGL Graphics Device</source>
+ <translation>OpenGL 图形设备</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureGraphicsAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
+ <source>Form</source>
+ <translation>类型</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="22"/>
+ <source>Advanced Graphics Settings</source>
+ <translation>高级图形选项</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="43"/>
+ <source>Accuracy Level:</source>
+ <translation>精度:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="72"/>
+ <source>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don&apos;t notice a performance difference.</source>
+ <translation>垂直同步可防止画面产生撕裂感。但启用垂直同步后,某些设备性能可能会有所降低。如果您没有感到性能差异,请保持启用状态。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
+ <source>Use VSync (OpenGL only)</source>
+ <translation>启用垂直同步 (仅限 OpenGL 模式)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="82"/>
+ <source>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</source>
+ <translation>在支持 NV_gpu_program5 的 Nvidia 设备上启用 OpenGL 程序集着色器。启用此项将减少着色器卡顿。实验性功能。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
+ <source>Use assembly shaders (experimental, Nvidia OpenGL only)</source>
+ <translation>启用程序集着色器 (实验性,仅限 Nvidia OpenGL)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="92"/>
+ <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source>
+ <translation>启用异步着色器编译,这可能会减少着色器卡顿。实验性功能。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
+ <source>Use asynchronous shader building (experimental)</source>
+ <translation>启用异步着色器编译 (实验性)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="102"/>
+ <source>Use Fast GPU Time</source>
+ <translation>启用快速 GPU 时钟</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="124"/>
+ <source>Anisotropic Filtering:</source>
+ <translation>各向异性过滤:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="132"/>
+ <source>Default</source>
+ <translation>系统默认</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="137"/>
+ <source>2x</source>
+ <translation>2×</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="142"/>
+ <source>4x</source>
+ <translation>4×</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="147"/>
+ <source>8x</source>
+ <translation>8×</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="152"/>
+ <source>16x</source>
+ <translation>16×</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureHotkeys</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
+ <source>Hotkey Settings</source>
+ <translation>热键设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="22"/>
+ <source>Double-click on a binding to change it.</source>
+ <translation>双击已绑定的项目以改变设定。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="42"/>
+ <source>Clear All</source>
+ <translation>全部清除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="49"/>
+ <source>Restore Defaults</source>
+ <translation>恢复默认</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Action</source>
+ <translation>作用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Hotkey</source>
+ <translation>热键</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="74"/>
+ <source>Context</source>
+ <translation>位置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="96"/>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="183"/>
+ <source>Conflicting Key Sequence</source>
+ <translation>按键冲突</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="97"/>
+ <source>The entered key sequence is already assigned to: %1</source>
+ <translation>输入的密钥序列已分配给: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="171"/>
+ <source>Restore Default</source>
+ <translation>恢复默认</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
+ <source>Clear</source>
+ <translation>清除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="184"/>
+ <source>The default key sequence is already assigned to: %1</source>
+ <translation>默认密钥序列已分配给: %1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInput</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/>
+ <source>ConfigureInput</source>
+ <translation>输入设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/>
+ <source>Player 1</source>
+ <translation>玩家 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/>
+ <source>Player 2</source>
+ <translation>玩家 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/>
+ <source>Player 3</source>
+ <translation>玩家 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/>
+ <source>Player 4</source>
+ <translation>玩家 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/>
+ <source>Player 5</source>
+ <translation>玩家 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/>
+ <source>Player 6</source>
+ <translation>玩家 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/>
+ <source>Player 7</source>
+ <translation>玩家 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/>
+ <source>Player 8</source>
+ <translation>玩家 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/>
+ <source>Advanced</source>
+ <translation>高级</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
+ <source>Console Mode</source>
+ <translation>控制台模式</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
+ <source>Docked</source>
+ <translation>Docked</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
+ <source>Undocked</source>
+ <translation>Undocked</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
+ <source>Vibration</source>
+ <translation>震动</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="212"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="231"/>
+ <source>Motion</source>
+ <translation>体感</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="267"/>
+ <source>Configure</source>
+ <translation>设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="302"/>
+ <source>Controllers</source>
+ <translation>控制器</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="330"/>
+ <source>1</source>
+ <translation>1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="371"/>
+ <source>2</source>
+ <translation>2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="381"/>
+ <source>3</source>
+ <translation>3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="391"/>
+ <source>4</source>
+ <translation>4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="401"/>
+ <source>5</source>
+ <translation>5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="411"/>
+ <source>6</source>
+ <translation>6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="421"/>
+ <source>7</source>
+ <translation>7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="431"/>
+ <source>8</source>
+ <translation>8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="441"/>
+ <source>Connected</source>
+ <translation>已连接</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="500"/>
+ <source>Defaults</source>
+ <translation>系统默认</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input.ui" line="543"/>
+ <source>Clear</source>
+ <translation>清除</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>输入设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
+ <source>Joycon Colors</source>
+ <translation>Joycon 颜色</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
+ <source>Player 1</source>
+ <translation>玩家 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
+ <source>L Body</source>
+ <translation>左侧主体</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
+ <source>L Button</source>
+ <translation>左侧按键</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
+ <source>R Body</source>
+ <translation>右侧主体</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
+ <source>R Button</source>
+ <translation>右侧按键</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
+ <source>Player 2</source>
+ <translation>玩家 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/>
+ <source>Player 3</source>
+ <translation>玩家 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/>
+ <source>Player 4</source>
+ <translation>玩家 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/>
+ <source>Player 5</source>
+ <translation>玩家 5</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/>
+ <source>Player 6</source>
+ <translation>玩家 6</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/>
+ <source>Player 7</source>
+ <translation>玩家 7</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/>
+ <source>Player 8</source>
+ <translation>玩家 8</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
+ <source>Other</source>
+ <translation>其他</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
+ <source>Keyboard</source>
+ <translation>键盘</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2552"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2575"/>
+ <source>Advanced</source>
+ <translation>高级选项</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2582"/>
+ <source>Touchscreen</source>
+ <translation>触摸屏</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
+ <source>Mouse</source>
+ <translation>鼠标</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
+ <source>Motion / Touch</source>
+ <translation>体感/触摸</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
+ <source>Configure</source>
+ <translation>设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/>
+ <source>Debug Controller</source>
+ <translation>控制器调试</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureInputPlayer</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/>
+ <source>Configure Input</source>
+ <translation>输入设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
+ <source>Connect Controller</source>
+ <translation>已连接控制器</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="88"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="358"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="379"/>
+ <source>Pro Controller</source>
+ <translation>Pro Controller</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="93"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="359"/>
+ <source>Dual Joycons</source>
+ <translation>双 Joycons 手柄</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="98"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="360"/>
+ <source>Left Joycon</source>
+ <translation>左 Joycon 手柄</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="103"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/>
+ <source>Right Joycon</source>
+ <translation>右 Joycon 手柄</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="108"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="365"/>
+ <source>Handheld</source>
+ <translation>掌机模式</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="119"/>
+ <source>Input Device</source>
+ <translation>输入设备</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="141"/>
+ <source>Any</source>
+ <translation>任意</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="146"/>
+ <source>Keyboard/Mouse</source>
+ <translation>键盘/鼠标</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="182"/>
+ <source>Profile</source>
+ <translation>用户配置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="215"/>
+ <source>Save</source>
+ <translation>保存</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="231"/>
+ <source>New</source>
+ <translation>新建</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="247"/>
+ <source>Delete</source>
+ <translation>删除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="310"/>
+ <source>Left Stick</source>
+ <translation>左摇杆</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="368"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="410"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="944"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="983"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2457"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2496"/>
+ <source>Up</source>
+ <translation>上</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="441"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="480"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1014"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1053"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2527"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2566"/>
+ <source>Left</source>
+ <translation>左</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="490"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="529"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1063"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2576"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2615"/>
+ <source>Right</source>
+ <translation>右</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="572"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="611"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1145"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1184"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2658"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2697"/>
+ <source>Down</source>
+ <translation>下</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="642"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="681"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2728"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2767"/>
+ <source>Pressed</source>
+ <translation>按下</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="691"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="730"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2777"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2816"/>
+ <source>Modifier</source>
+ <translation>轻推</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="740"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2826"/>
+ <source>Range</source>
+ <translation>灵敏度</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="773"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2859"/>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="816"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2899"/>
+ <source>Deadzone: 0%</source>
+ <translation>摇杆死区:0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="840"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
+ <source>Modifier Range: 0%</source>
+ <translation>摇杆灵敏度:0%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="886"/>
+ <source>D-Pad</source>
+ <translation>十字方向键</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1270"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1309"/>
+ <source>L</source>
+ <translation>L</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1319"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1358"/>
+ <source>ZL</source>
+ <translation>ZL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1423"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1462"/>
+ <source>Minus</source>
+ <translation>-</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1472"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1511"/>
+ <source>Capture</source>
+ <translation>截图</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1542"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1581"/>
+ <source>Plus</source>
+ <translation>+</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1591"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1630"/>
+ <source>Home</source>
+ <translation>Home</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1695"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
+ <source>R</source>
+ <translation>R</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1744"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1783"/>
+ <source>ZR</source>
+ <translation>ZR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1848"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1887"/>
+ <source>SL</source>
+ <translation>SL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1897"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1936"/>
+ <source>SR</source>
+ <translation>SR</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2044"/>
+ <source>Face Buttons</source>
+ <translation>主要按键</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2102"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2141"/>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2172"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2211"/>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2221"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2260"/>
+ <source>A</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2303"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2342"/>
+ <source>B</source>
+ <translation>B</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2390"/>
+ <source>Right Stick</source>
+ <translation>右摇杆</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="338"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="618"/>
+ <source>Deadzone: %1%</source>
+ <translation>摇杆死区:%1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="345"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/>
+ <source>Modifier Range: %1%</source>
+ <translation>摇杆灵敏度:%1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/>
+ <source>[waiting]</source>
+ <translation>[等待中]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMotionTouch</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/>
+ <source>Configure Motion / Touch</source>
+ <translation>体感/触摸设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="20"/>
+ <source>Motion</source>
+ <translation>体感</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="28"/>
+ <source>Motion Provider:</source>
+ <translation>体感设备:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="42"/>
+ <source>Sensitivity:</source>
+ <translation>灵敏度:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="76"/>
+ <source>Touch</source>
+ <translation>触摸</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="84"/>
+ <source>Touch Provider:</source>
+ <translation>触摸设备:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="98"/>
+ <source>Calibration:</source>
+ <translation>触摸校准:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="105"/>
+ <source>(100, 50) - (1800, 850)</source>
+ <translation>(100, 50) - (1800, 850)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="121"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="154"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="227"/>
+ <source>Configure</source>
+ <translation>设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="138"/>
+ <source>Use button mapping:</source>
+ <translation>使用按键映射:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="166"/>
+ <source>CemuhookUDP Config</source>
+ <translation>CemuhookUDP 设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="172"/>
+ <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
+ <translation>您可以使用任何与 Cemuhook 兼容的 UDP 输入源来提供体感和触摸输入。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="187"/>
+ <source>Server:</source>
+ <translation>服务器:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="208"/>
+ <source>Port:</source>
+ <translation>端口:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="229"/>
+ <source>Pad:</source>
+ <translation>Pad:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="237"/>
+ <source>Pad 1</source>
+ <translation>Pad 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="242"/>
+ <source>Pad 2</source>
+ <translation>Pad 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
+ <source>Pad 3</source>
+ <translation>Pad 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="252"/>
+ <source>Pad 4</source>
+ <translation>Pad 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="264"/>
+ <source>Learn More</source>
+ <translation>了解更多</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="277"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="250"/>
+ <source>Test</source>
+ <translation>测试</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="78"/>
+ <source>Mouse (Right Click)</source>
+ <translation>鼠标 (右键)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="79"/>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="84"/>
+ <source>CemuhookUDP</source>
+ <translation>CemuhookUDP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="83"/>
+ <source>Emulator Window</source>
+ <translation>模拟器窗口</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="101"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;了解更多&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="192"/>
+ <source>Testing</source>
+ <translation>测试中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="209"/>
+ <source>Configuring</source>
+ <translation>配置中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="241"/>
+ <source>Test Successful</source>
+ <translation>测试成功</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="242"/>
+ <source>Successfully received data from the server.</source>
+ <translation>已成功地从服务器获取数据。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="244"/>
+ <source>Test Failed</source>
+ <translation>测试失败</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="245"/>
+ <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
+ <translation>无法从服务器获取数据。&lt;br&gt;请验证服务器是否正在运行,以及地址和端口是否配置正确。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="272"/>
+ <source>Citra</source>
+ <translation>Citra</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="273"/>
+ <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
+ <translation>UDP 测试或触摸校准正在进行中。&lt;br&gt;请耐心等待。</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureMouseAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="14"/>
+ <source>Configure Mouse</source>
+ <translation>鼠标设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="25"/>
+ <source>Mouse Buttons</source>
+ <translation>鼠标按键</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="35"/>
+ <source>Forward:</source>
+ <translation>前:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="75"/>
+ <source>Back:</source>
+ <translation>后:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="103"/>
+ <source>Left:</source>
+ <translation>左:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="131"/>
+ <source>Middle:</source>
+ <translation>中:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="197"/>
+ <source>Right:</source>
+ <translation>右:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="270"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="109"/>
+ <source>Clear</source>
+ <translation>清除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.ui" line="289"/>
+ <source>Defaults</source>
+ <translation>系统默认</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="111"/>
+ <source>[not set]</source>
+ <translation>[未设置]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="113"/>
+ <source>Restore Default</source>
+ <translation>恢复默认</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="200"/>
+ <source>[press key]</source>
+ <translation>[请按一个键]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGame</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="14"/>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="28"/>
+ <source>Info</source>
+ <translation>信息</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="87"/>
+ <source>Name</source>
+ <translation>名称</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="94"/>
+ <source>Title ID</source>
+ <translation>游戏 ID</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="131"/>
+ <source>Filename</source>
+ <translation>文件名</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="158"/>
+ <source>Format</source>
+ <translation>格式</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="165"/>
+ <source>Version</source>
+ <translation>版本</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="172"/>
+ <source>Size</source>
+ <translation>大小</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="179"/>
+ <source>Developer</source>
+ <translation>开发商</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="225"/>
+ <source>Add-Ons</source>
+ <translation>附加项</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="230"/>
+ <source>General</source>
+ <translation>通用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="235"/>
+ <source>System</source>
+ <translation>系统</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="240"/>
+ <source>Graphics</source>
+ <translation>图形</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="245"/>
+ <source>Adv. Graphics</source>
+ <translation>高级图形</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="250"/>
+ <source>Audio</source>
+ <translation>声音</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="38"/>
+ <source>Properties</source>
+ <translation>属性</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="131"/>
+ <source>Use global configuration (%1)</source>
+ <translation>使用全局设置 (%1)</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigurePerGameAddons</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
+ <source>Form</source>
+ <translation>类型</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="48"/>
+ <source>Patch Name</source>
+ <translation>补丁名称</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="49"/>
+ <source>Version</source>
+ <translation>版本</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureProfileManager</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/>
+ <source>Form</source>
+ <translation>类型</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="22"/>
+ <source>Profile Manager</source>
+ <translation>用户配置管理</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="39"/>
+ <source>Current User</source>
+ <translation>当前用户</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="77"/>
+ <source>Username</source>
+ <translation>用户名</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="107"/>
+ <source>Set Image</source>
+ <translation>设置图像</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="127"/>
+ <source>Add</source>
+ <translation>添加</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="137"/>
+ <source>Rename</source>
+ <translation>重命名</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="147"/>
+ <source>Remove</source>
+ <translation>移除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="159"/>
+ <source>Profile management is available only when game is not running.</source>
+ <translation>只有当游戏不在运行时,才能进行用户配置的管理。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="54"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="72"/>
+ <source>Enter Username</source>
+ <translation>输入用户名</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="135"/>
+ <source>Users</source>
+ <translation>用户</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="199"/>
+ <source>Enter a username for the new user:</source>
+ <translation>输入新用户的用户名:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="219"/>
+ <source>Enter a new username:</source>
+ <translation>输入新的用户名:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="244"/>
+ <source>Confirm Delete</source>
+ <translation>确认删除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="245"/>
+ <source>You are about to delete user with name &quot;%1&quot;. Are you sure?</source>
+ <translation>您确定要删除用户名为 “%1” 的用户吗?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/>
+ <source>Select User Image</source>
+ <translation>选择用户图像</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="270"/>
+ <source>JPEG Images (*.jpg *.jpeg)</source>
+ <translation>JPEG 图像 (*.jpg *.jpeg)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/>
+ <source>Error deleting image</source>
+ <translation>删除图像时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="280"/>
+ <source>Error occurred attempting to overwrite previous image at: %1.</source>
+ <translation>尝试覆盖该用户的现有图像时出错: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/>
+ <source>Error deleting file</source>
+ <translation>删除文件时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="289"/>
+ <source>Unable to delete existing file: %1.</source>
+ <translation>无法删除文件: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/>
+ <source>Error creating user image directory</source>
+ <translation>创建用户图像目录时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="297"/>
+ <source>Unable to create directory %1 for storing user images.</source>
+ <translation>无法创建存储用户图像的目录 %1 。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/>
+ <source>Error copying user image</source>
+ <translation>复制用户图像时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="303"/>
+ <source>Unable to copy image from %1 to %2</source>
+ <translation>无法将图像从 %1 复制到 %2</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureService</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="14"/>
+ <source>Form</source>
+ <translation>类型</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="22"/>
+ <source>BCAT</source>
+ <translation>BCAT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="34"/>
+ <source>BCAT is Nintendo&apos;s way of sending data to games to engage its community and unlock additional content.</source>
+ <translation>BCAT 是任天堂向游戏发送数据的一种方式,以此吸引游戏玩家,并可能解锁额外的内容。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="50"/>
+ <source>BCAT Backend</source>
+ <translation>BCAT 后端</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.ui" line="79"/>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;了解关于 BCAT、Boxcat 和当前事件的更多信息&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="81"/>
+ <source>The boxcat service is offline or you are not connected to the internet.</source>
+ <translation>Boxcat 服务处于离线状态,或者您没有连接到互联网。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="84"/>
+ <source>There was an error while processing the boxcat event data. Contact the yuzu developers.</source>
+ <translation>处理 Boxcat 事件数据时出错。请联系 yuzu 开发者。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="88"/>
+ <source>The version of yuzu you are using is either too new or too old for the server. Try updating to the latest official release of yuzu.</source>
+ <translation>您使用的 yuzu 版本过新或过旧。尝试更新到官方的最新版本。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="94"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>There are currently no events on boxcat.</source>
+ <translation>当前 Boxcat 上没有事件。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="109"/>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="111"/>
+ <source>Current Boxcat Events</source>
+ <translation>当前 Boxcat 事件</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_service.cpp" line="121"/>
+ <source>Yuzu is retrieving the latest boxcat status...</source>
+ <translation>Yuzu 正在检索 Boxcat 的最新状态...</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureSystem</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="22"/>
+ <source>System Settings</source>
+ <translation>系统设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="30"/>
+ <source>Region:</source>
+ <translation>地区:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="38"/>
+ <source>Auto</source>
+ <translation>自动</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="43"/>
+ <source>Default</source>
+ <translation>系统默认</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="48"/>
+ <source>CET</source>
+ <translation>欧洲中部时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="53"/>
+ <source>CST6CDT</source>
+ <translation>古巴标准时间&amp;古巴夏令时</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="58"/>
+ <source>Cuba</source>
+ <translation>古巴</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="63"/>
+ <source>EET</source>
+ <translation>东欧时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="68"/>
+ <source>Egypt</source>
+ <translation>埃及</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="73"/>
+ <source>Eire</source>
+ <translation>爱尔兰</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="78"/>
+ <source>EST</source>
+ <translation>东部标准时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="83"/>
+ <source>EST5EDT</source>
+ <translation>东部标准时间&amp;东部夏令时</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="88"/>
+ <source>GB</source>
+ <translation>国家标准时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="93"/>
+ <source>GB-Eire</source>
+ <translation>爱尔兰国家标准时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="98"/>
+ <source>GMT</source>
+ <translation>格林威治标准时间 (GMT)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="103"/>
+ <source>GMT+0</source>
+ <translation>GMT+0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="108"/>
+ <source>GMT-0</source>
+ <translation>GMT-0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="113"/>
+ <source>GMT0</source>
+ <translation>GMT0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="118"/>
+ <source>Greenwich</source>
+ <translation>格林威治</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="123"/>
+ <source>Hongkong</source>
+ <translation>中国香港</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="128"/>
+ <source>HST</source>
+ <translation>美国夏威夷时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="133"/>
+ <source>Iceland</source>
+ <translation>冰岛</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="138"/>
+ <source>Iran</source>
+ <translation>伊朗</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="143"/>
+ <source>Israel</source>
+ <translation>以色列</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="148"/>
+ <source>Jamaica</source>
+ <translation>牙买加</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="153"/>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="272"/>
+ <source>Japan</source>
+ <translation>日本</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="158"/>
+ <source>Kwajalein</source>
+ <translation>夸贾林环礁</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="163"/>
+ <source>Libya</source>
+ <translation>利比亚</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="168"/>
+ <source>MET</source>
+ <translation>中欧时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="173"/>
+ <source>MST</source>
+ <translation>山区标准时间 (北美)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="178"/>
+ <source>MST7MDT</source>
+ <translation>山区标准时间&amp;山区夏令时 (北美)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="183"/>
+ <source>Navajo</source>
+ <translation>纳瓦霍</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="188"/>
+ <source>NZ</source>
+ <translation>新西兰时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="193"/>
+ <source>NZ-CHAT</source>
+ <translation>新西兰-查塔姆群岛</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="198"/>
+ <source>Poland</source>
+ <translation>波兰</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="203"/>
+ <source>Portugal</source>
+ <translation>葡萄牙</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="208"/>
+ <source>PRC</source>
+ <translation>中国标准时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="213"/>
+ <source>PST8PDT</source>
+ <translation>太平洋标准时间&amp;太平洋夏令时</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="218"/>
+ <source>ROC</source>
+ <translation>ROC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="223"/>
+ <source>ROK</source>
+ <translation>ROK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="228"/>
+ <source>Singapore</source>
+ <translation>新加坡</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="233"/>
+ <source>Turkey</source>
+ <translation>土耳其</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="238"/>
+ <source>UCT</source>
+ <translation>UCT</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="243"/>
+ <source>Universal</source>
+ <translation>世界时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="248"/>
+ <source>UTC</source>
+ <translation>协调世界时</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="253"/>
+ <source>W-SU</source>
+ <translation>欧洲-莫斯科时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="258"/>
+ <source>WET</source>
+ <translation>西欧时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="263"/>
+ <source>Zulu</source>
+ <translation>祖鲁</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="277"/>
+ <source>USA</source>
+ <translation>美国</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="282"/>
+ <source>Europe</source>
+ <translation>欧洲</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="287"/>
+ <source>Australia</source>
+ <translation>澳大利亚</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="292"/>
+ <source>China</source>
+ <translation>中国</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="297"/>
+ <source>Korea</source>
+ <translation>朝鲜</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="302"/>
+ <source>Taiwan</source>
+ <translation>中国台湾</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="310"/>
+ <source>Time Zone:</source>
+ <translation>时区:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="317"/>
+ <source>Note: this can be overridden when region setting is auto-select</source>
+ <translation>注意:当“地区”设置是“自动选择”时,此设置可能会被覆盖。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="321"/>
+ <source>Japanese (日本語)</source>
+ <translation>日语 (日本語)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="326"/>
+ <source>English</source>
+ <translation>英语</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="331"/>
+ <source>French (français)</source>
+ <translation>法语 (français)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="336"/>
+ <source>German (Deutsch)</source>
+ <translation>德语 (Deutsch)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="341"/>
+ <source>Italian (italiano)</source>
+ <translation>意大利语 (italiano)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="346"/>
+ <source>Spanish (español)</source>
+ <translation>西班牙语 (español)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="351"/>
+ <source>Chinese</source>
+ <translation>中文</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="356"/>
+ <source>Korean (한국어)</source>
+ <translation>韩语 (한국어)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="361"/>
+ <source>Dutch (Nederlands)</source>
+ <translation>荷兰语 (Nederlands)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="366"/>
+ <source>Portuguese (português)</source>
+ <translation>葡萄牙语 (português)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="371"/>
+ <source>Russian (Русский)</source>
+ <translation>俄语 (Русский)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="376"/>
+ <source>Taiwanese</source>
+ <translation>台湾中文</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="381"/>
+ <source>British English</source>
+ <translation>英式英语</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="386"/>
+ <source>Canadian French</source>
+ <translation>加拿大法语</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="391"/>
+ <source>Latin American Spanish</source>
+ <translation>拉美西班牙语</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="396"/>
+ <source>Simplified Chinese</source>
+ <translation>简体中文</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="401"/>
+ <source>Traditional Chinese (正體中文)</source>
+ <translation>繁体中文 (正體中文)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
+ <source>Custom RTC</source>
+ <translation>自定义系统时间</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="416"/>
+ <source>Language</source>
+ <translation>语言</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="423"/>
+ <source>RNG Seed</source>
+ <translation>随机数生成器种子</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/>
+ <source>Mono</source>
+ <translation>单声道</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="436"/>
+ <source>Stereo</source>
+ <translation>立体声</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="441"/>
+ <source>Surround</source>
+ <translation>环绕声</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/>
+ <source>Console ID:</source>
+ <translation>设备 ID:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="456"/>
+ <source>Sound output mode</source>
+ <translation>声音输出模式</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="470"/>
+ <source>d MMM yyyy h:mm:ss AP</source>
+ <translation>d MMM yyyy h:mm:ss AP</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="507"/>
+ <source>Regenerate</source>
+ <translation>重置 ID</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.ui" line="532"/>
+ <source>System settings are available only when game is not running.</source>
+ <translation>只有当游戏不在运行时,系统设置才可用。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="197"/>
+ <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source>
+ <translation>这将使用一个新的虚拟 Switch 取代你当前的虚拟 Switch。您当前的虚拟 Switch 将无法恢复。在部分游戏中可能会出现意外效果。如果你使用一个过时的配置存档这可能会失败。确定要继续吗?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="201"/>
+ <source>Warning</source>
+ <translation>警告</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_system.cpp" line="209"/>
+ <source>Console ID: 0x%1</source>
+ <translation>设备 ID: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchFromButton</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
+ <source>Configure Touchscreen Mappings</source>
+ <translation>配置触摸屏映射</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
+ <source>Mapping:</source>
+ <translation>映射:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
+ <source>New</source>
+ <translation>新建</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/>
+ <source>Delete</source>
+ <translation>删除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
+ <source>Rename</source>
+ <translation>重命名</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
+ <source>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</source>
+ <translation>单击屏幕底部区域添加点位,然后按下按键进行绑定。
+拖动点位以改变位置,或双击列表项更改绑定。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
+ <source>Delete Point</source>
+ <translation>删除点位</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Button</source>
+ <translation>按键</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>X</source>
+ <comment>X axis</comment>
+ <translation>X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="80"/>
+ <source>Y</source>
+ <comment>Y axis</comment>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>New Profile</source>
+ <translation>保存自定义设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="200"/>
+ <source>Enter the name for the new profile.</source>
+ <translation>为新的自定义设置命名。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete Profile</source>
+ <translation>删除自定义设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="211"/>
+ <source>Delete profile %1?</source>
+ <translation>真的要删除自定义设置 %1 吗?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>Rename Profile</source>
+ <translation>重命名自定义设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="224"/>
+ <source>New name:</source>
+ <translation>新名称:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="233"/>
+ <source>[press key]</source>
+ <translation>[请按一个键]</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureTouchscreenAdvanced</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/>
+ <source>Configure Touchscreen</source>
+ <translation>触摸屏设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
+ <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
+ <translation>警告:此页面中的设置会影响 yuzu 的模拟触摸屏的内部工作方式。改变它们可能造成不良后果,例如触摸屏完全或部分失效。如果您不知道自己在做什么,请不要使用此页面。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
+ <source>Touch Parameters</source>
+ <translation>触摸参数</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
+ <source>Touch Diameter Y</source>
+ <translation>触摸直径 Y</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="78"/>
+ <source>Finger</source>
+ <translation>手指</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
+ <source>Touch Diameter X</source>
+ <translation>触摸直径 X</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="115"/>
+ <source>Rotational Angle</source>
+ <translation>旋转角度</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="149"/>
+ <source>Restore Defaults</source>
+ <translation>恢复默认</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureUi</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/>
+ <source>Form</source>
+ <translation>类型</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="20"/>
+ <source>General</source>
+ <translation>通用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="28"/>
+ <source>Note: Changing language will apply your configuration.</source>
+ <translation>注意: 切换语言将应用您的配置。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="40"/>
+ <source>Interface language:</source>
+ <translation>界面语言:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="54"/>
+ <source>Theme:</source>
+ <translation>主题:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="71"/>
+ <source>Game List</source>
+ <translation>游戏列表</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="79"/>
+ <source>Show Add-Ons Column</source>
+ <translation>显示“附加项”列</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="88"/>
+ <source>Icon Size:</source>
+ <translation>图标大小:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="102"/>
+ <source>Row 1 Text:</source>
+ <translation>第一行:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="116"/>
+ <source>Row 2 Text:</source>
+ <translation>第二行:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="133"/>
+ <source>Screenshots</source>
+ <translation>捕获截图</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="141"/>
+ <source>Ask Where To Save Screenshots (Windows Only)</source>
+ <translation>询问保存截图的位置 (仅限 Windows )</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="150"/>
+ <source>Screenshots Path: </source>
+ <translation>截图保存位置:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.ui" line="160"/>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="64"/>
+ <source>Select Screenshots Path...</source>
+ <translation>选择截图保存位置...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="131"/>
+ <source>&lt;System&gt;</source>
+ <translation>&lt;System&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="132"/>
+ <source>English</source>
+ <translation>英语</translation>
+ </message>
+</context>
+<context>
+ <name>ConfigureWeb</name>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="22"/>
+ <source>yuzu Web Service</source>
+ <translation>yuzu 网络服务</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="28"/>
+ <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
+ <translation>提供您的用户名和令牌意味着您同意让 yuzu 收集额外的使用数据,其中可能包括用户识别信息。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="155"/>
+ <source>Verify</source>
+ <translation>验证</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="53"/>
+ <source>Sign up</source>
+ <translation>注册</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="63"/>
+ <source>Token: </source>
+ <translation>令牌:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="74"/>
+ <source>Username: </source>
+ <translation>用户名:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="91"/>
+ <source>What is my token?</source>
+ <translation>我的令牌是?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="116"/>
+ <source>Telemetry</source>
+ <translation>使用数据共享</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="122"/>
+ <source>Share anonymous usage data with the yuzu team</source>
+ <translation>与 yuzu 团队共享匿名使用数据</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="129"/>
+ <source>Learn more</source>
+ <translation>了解更多</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="138"/>
+ <source>Telemetry ID:</source>
+ <translation>数据 ID:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="154"/>
+ <source>Regenerate</source>
+ <translation>重新生成</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="168"/>
+ <source>Discord Presence</source>
+ <translation>Discord 状态</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.ui" line="174"/>
+ <source>Show Current Game in your Discord Status</source>
+ <translation>在您的 Discord 状态中显示当前游戏</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="69"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;了解更多&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="73"/>
+ <source>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Sign up&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://profile.yuzu-emu.org/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;注册&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="77"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;What is my token?&lt;/span&gt;&lt;/a&gt;</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/yuzu-web-service/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;我的令牌是?&lt;/span&gt;&lt;/a&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="81"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="126"/>
+ <source>Telemetry ID: 0x%1</source>
+ <translation>数据 ID: 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="92"/>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="166"/>
+ <source>Unspecified</source>
+ <translation>未指定</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/>
+ <source>Token not verified</source>
+ <translation>令牌未被验证</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="119"/>
+ <source>Token was not verified. The change to your token has not been saved.</source>
+ <translation>令牌未被验证。您对用户名和令牌的更改尚未保存。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="145"/>
+ <source>Verifying...</source>
+ <translation>验证中...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="167"/>
+ <source>Verification failed</source>
+ <translation>验证失败</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_web.cpp" line="168"/>
+ <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
+ <translation>验证失败。请检查您输入的令牌是否正确,并且确保您的互联网连接正常。</translation>
+ </message>
+</context>
+<context>
+ <name>GMainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="165"/>
+ <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;Anonymous data is collected&lt;/a&gt; to help improve yuzu. &lt;br/&gt;&lt;br/&gt;Would you like to share your usage data with us?</source>
+ <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;我们收集匿名数据&lt;/a&gt;来帮助改进 yuzu 。&lt;br/&gt;&lt;br/&gt;您愿意和我们分享您的使用数据吗?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="168"/>
+ <source>Telemetry</source>
+ <translation>使用数据共享</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="326"/>
+ <source>Text Check Failed</source>
+ <translation>文本检查失败</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="339"/>
+ <source>Loading Web Applet...</source>
+ <translation>正在加载 Web 应用程序...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="387"/>
+ <source>Exit Web Applet</source>
+ <translation>退出 Web 应用程序</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="405"/>
+ <source>Exit</source>
+ <translation>退出</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="406"/>
+ <source>To exit the web application, use the game provided controls to select exit, select the &apos;Exit Web Applet&apos; option in the menu bar, or press the &apos;Enter&apos; key.</source>
+ <translation>若要退出 Web 应用程序,请使用游戏内提供的方式退出,在菜单栏中选择“退出 Web 应用程序”选项,或者按 &quot;Enter&quot; 键。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="458"/>
+ <source>Web Applet</source>
+ <translation>Web 应用程序</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="459"/>
+ <source>This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot properly display the game manual or web page requested.</source>
+ <translation>此版本的 yuzu 没有 QtWebEngine 的支持。这意味着 yuzu 无法正确显示所请求的游戏手册或网页。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="507"/>
+ <source>The amount of shaders currently being built</source>
+ <translation>当前正在构建的着色器的数量</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="510"/>
+ <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
+ <translation>当前的模拟速度。高于或低于 100% 的值表示模拟正在运行得比实际 Switch 更快或更慢。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="513"/>
+ <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
+ <translation>游戏当前运行的帧率。这将因游戏和场景的不同而有所变化。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="517"/>
+ <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
+ <translation>在不计算速度限制和垂直同步的情况下,模拟一个 Switch 帧的实际时间。若要进行全速模拟,这个数值不应超过 16.67 毫秒。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="537"/>
+ <source>DOCK</source>
+ <translation>DOCK</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="556"/>
+ <source>ASYNC</source>
+ <translation>异步</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="576"/>
+ <source>MULTICORE</source>
+ <translation>多核</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>VULKAN</source>
+ <translation>VULKAN</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="588"/>
+ <source>OPENGL</source>
+ <translation>OPENGL</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="647"/>
+ <source>Clear Recent Files</source>
+ <translation>清除最近文件</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="990"/>
+ <source>Warning Outdated Game Format</source>
+ <translation>过时游戏格式警告</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="991"/>
+ <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
+ <translation>目前使用的游戏为解体的 ROM 目录格式,这是一种过时的格式,已被其他格式替代,如 NCA,NAX,XCI 或 NSP。解体的 ROM 目录缺少图标、元数据和更新支持。&lt;br&gt;&lt;br&gt;有关 yuzu 支持的各种 Switch 格式的说明,&lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;请查看我们的 wiki&lt;/a&gt;。此消息将不会再次出现。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1003"/>
+ <location filename="../../src/yuzu/main.cpp" line="1036"/>
+ <source>Error while loading ROM!</source>
+ <translation>加载 ROM 时出错!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1004"/>
+ <source>The ROM format is not supported.</source>
+ <translation>该 ROM 格式不受支持。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1008"/>
+ <source>An error occurred initializing the video core.</source>
+ <translation>在初始化视频核心时发生错误。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1009"/>
+ <source>yuzu has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.Ensure that you have the latest graphics drivers for your GPU.</source>
+ <translation>yuzu 在运行视频核心时遇到错误,请查看日志了解更多详细信息。有关查看日志的更多信息,请参阅以下页面:&lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;。请确保您的 GPU 安装了最新的图形驱动程序。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1028"/>
+ <source>Error while loading ROM! </source>
+ <translation>加载 ROM 时出错!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1037"/>
+ <source>An unknown error occurred. Please see the log for more details.</source>
+ <translation>发生了未知错误。请查看日志了解详情。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1169"/>
+ <source>Start</source>
+ <translation>开始</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1274"/>
+ <source>Save Data</source>
+ <translation>保存数据</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1318"/>
+ <source>Mod Data</source>
+ <translation>Mod 数据</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1330"/>
+ <source>Error Opening %1 Folder</source>
+ <translation>打开 %1 文件夹时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1331"/>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Folder does not exist!</source>
+ <translation>文件夹不存在!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1349"/>
+ <source>Error Opening Transferable Shader Cache</source>
+ <translation>打开可转移着色器缓存时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1350"/>
+ <location filename="../../src/yuzu/main.cpp" line="1544"/>
+ <source>A shader cache for this title does not exist.</source>
+ <translation>这个游戏的着色器缓存不存在。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1414"/>
+ <source>Contents</source>
+ <translation>目录</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1416"/>
+ <source>Update</source>
+ <translation>游戏更新</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1418"/>
+ <source>DLC</source>
+ <translation>DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Entry</source>
+ <translation>删除项目</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1425"/>
+ <source>Remove Installed Game %1?</source>
+ <translation>删除已安装的游戏 %1 ?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1455"/>
+ <location filename="../../src/yuzu/main.cpp" line="1471"/>
+ <location filename="../../src/yuzu/main.cpp" line="1502"/>
+ <location filename="../../src/yuzu/main.cpp" line="1549"/>
+ <location filename="../../src/yuzu/main.cpp" line="1570"/>
+ <source>Successfully Removed</source>
+ <translation>删除成功</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1456"/>
+ <source>Successfully removed the installed base game.</source>
+ <translation>成功删除已安装的游戏。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1459"/>
+ <location filename="../../src/yuzu/main.cpp" line="1474"/>
+ <location filename="../../src/yuzu/main.cpp" line="1497"/>
+ <source>Error Removing %1</source>
+ <translation>删除 %1 时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1460"/>
+ <source>The base game is not installed in the NAND and cannot be removed.</source>
+ <translation>该游戏未安装于 NAND 中,无法删除。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1472"/>
+ <source>Successfully removed the installed update.</source>
+ <translation>成功删除已安装的游戏更新。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1475"/>
+ <source>There is no update installed for this title.</source>
+ <translation>这个游戏没有任何已安装的更新。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1498"/>
+ <source>There are no DLC installed for this title.</source>
+ <translation>这个游戏没有任何已安装的 DLC 。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1503"/>
+ <source>Successfully removed %1 installed DLC.</source>
+ <translation>成功删除游戏 %1 安装的 DLC 。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1510"/>
+ <source>Delete Transferable Shader Cache?</source>
+ <translation>删除着色器缓存?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1512"/>
+ <source>Remove Custom Game Configuration?</source>
+ <translation>移除自定义游戏设置?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1518"/>
+ <source>Remove File</source>
+ <translation>删除文件</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1543"/>
+ <location filename="../../src/yuzu/main.cpp" line="1552"/>
+ <source>Error Removing Transferable Shader Cache</source>
+ <translation>删除着色器缓存时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1550"/>
+ <source>Successfully removed the transferable shader cache.</source>
+ <translation>成功删除着色器缓存。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1553"/>
+ <source>Failed to remove the transferable shader cache.</source>
+ <translation>删除着色器缓存失败。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1564"/>
+ <location filename="../../src/yuzu/main.cpp" line="1573"/>
+ <source>Error Removing Custom Configuration</source>
+ <translation>移除自定义游戏设置时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1565"/>
+ <source>A custom configuration for this title does not exist.</source>
+ <translation>这个游戏的自定义设置不存在。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1571"/>
+ <source>Successfully removed the custom game configuration.</source>
+ <translation>成功移除自定义游戏设置。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1574"/>
+ <source>Failed to remove the custom game configuration.</source>
+ <translation>移除自定义游戏设置失败。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1580"/>
+ <source>RomFS Extraction Failed!</source>
+ <translation>RomFS 提取失败!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1581"/>
+ <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
+ <translation>复制 RomFS 文件时出错,或用户取消了操作。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Full</source>
+ <translation>完整</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1633"/>
+ <source>Skeleton</source>
+ <translation>框架</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1635"/>
+ <source>Select RomFS Dump Mode</source>
+ <translation>选择 RomFS 转储模式</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1636"/>
+ <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
+ <translation>请选择希望 RomFS 转储的方式。&lt;br&gt;“Full” 会将所有文件复制到新目录中,而&lt;br&gt;“Skeleton” 只会创建目录结构。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <source>Extracting RomFS...</source>
+ <translation>正在提取 RomFS...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1649"/>
+ <location filename="../../src/yuzu/main.cpp" line="1822"/>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1656"/>
+ <source>RomFS Extraction Succeeded!</source>
+ <translation>RomFS 提取成功!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1657"/>
+ <source>The operation completed successfully.</source>
+ <translation>操作成功完成。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1698"/>
+ <source>Error Opening %1</source>
+ <translation>打开 %1 时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1705"/>
+ <source>Select Directory</source>
+ <translation>选择目录</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1731"/>
+ <source>Properties</source>
+ <translation>属性</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1732"/>
+ <source>The game properties could not be loaded.</source>
+ <translation>无法加载该游戏的属性信息。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1744"/>
+ <source>Switch Executable (%1);;All Files (*.*)</source>
+ <comment>%1 is an identifier for the Switch executable file extensions.</comment>
+ <translation>Switch 可执行文件 (%1);;所有文件 (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1748"/>
+ <source>Load File</source>
+ <translation>加载文件</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1760"/>
+ <source>Open Extracted ROM Directory</source>
+ <translation>打开提取的 ROM 目录</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1771"/>
+ <source>Invalid Directory Selected</source>
+ <translation>选择的目录无效</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1772"/>
+ <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
+ <translation>选择的目录不包含 “main” 文件。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1782"/>
+ <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
+ <translation>可安装的 Switch 文件 (*.nca *.nsp *.xci);;任天堂内容档案 (*.nca);;任天堂应用包 (*.nsp);;NX 卡带镜像 (*.xci)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1787"/>
+ <source>Install Files</source>
+ <translation>安装文件</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1832"/>
+ <source>Installing file &quot;%1&quot;...</source>
+ <translation>正在安装文件 &quot;%1&quot;...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1880"/>
+ <source>Install Results</source>
+ <translation>安装结果</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1977"/>
+ <source>System Application</source>
+ <translation>系统应用</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1978"/>
+ <source>System Archive</source>
+ <translation>系统档案</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1979"/>
+ <source>System Application Update</source>
+ <translation>系统应用更新</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1980"/>
+ <source>Firmware Package (Type A)</source>
+ <translation>固件包 (A型)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1981"/>
+ <source>Firmware Package (Type B)</source>
+ <translation>固件包 (B型)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1982"/>
+ <source>Game</source>
+ <translation>游戏</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1983"/>
+ <source>Game Update</source>
+ <translation>游戏更新</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1984"/>
+ <source>Game DLC</source>
+ <translation>游戏 DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1985"/>
+ <source>Delta Title</source>
+ <translation>差量程序</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1988"/>
+ <source>Select NCA Install Type...</source>
+ <translation>选择 NCA 安装类型...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1989"/>
+ <source>Please select the type of title you would like to install this NCA as:
+(In most instances, the default &apos;Game&apos; is fine.)</source>
+ <translation>请选择此 NCA 的程序类型:
+(在大多数情况下,选择默认的“游戏”即可。)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1995"/>
+ <source>Failed to Install</source>
+ <translation>安装失败</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="1996"/>
+ <source>The title type you selected for the NCA is invalid.</source>
+ <translation>选择的 NCA 程序类型无效。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2037"/>
+ <source>File not found</source>
+ <translation>找不到文件</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2038"/>
+ <source>File &quot;%1&quot; not found</source>
+ <translation>文件 &quot;%1&quot; 未找到</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2060"/>
+ <location filename="../../src/yuzu/main.cpp" line="2867"/>
+ <source>Continue</source>
+ <translation>继续</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2101"/>
+ <source>Error Display</source>
+ <translation>错误显示</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2111"/>
+ <source>Missing yuzu Account</source>
+ <translation>未设置 yuzu 账户</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2112"/>
+ <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
+ <translation>要提交游戏兼容性测试用例,您必须设置您的 yuzu 帐户。&lt;br&gt;&lt;br/&gt;要设置您的 yuzu 帐户,请转到模拟 &amp;gt; 设置 &amp;gt; 网络。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2122"/>
+ <source>Error opening URL</source>
+ <translation>打开 URL 时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2123"/>
+ <source>Unable to open the URL &quot;%1&quot;.</source>
+ <translation>无法打开 URL : &quot;%1&quot; 。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2287"/>
+ <source>Amiibo File (%1);; All Files (*.*)</source>
+ <translation>Amiibo 文件 (%1);; 全部文件 (*.*)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2288"/>
+ <source>Load Amiibo</source>
+ <translation>加载 Amiibo</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2307"/>
+ <source>Error opening Amiibo data file</source>
+ <translation>打开 Amiibo 数据文件时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2308"/>
+ <source>Unable to open Amiibo file &quot;%1&quot; for reading.</source>
+ <translation>无法打开 Amiibo 文件 %1。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2316"/>
+ <source>Error reading Amiibo data file</source>
+ <translation>读取 Amiibo 数据文件时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2317"/>
+ <source>Unable to fully read Amiibo data. Expected to read %1 bytes, but was only able to read %2 bytes.</source>
+ <translation>无法完全读取 Amiibo 数据。应读取 %1 个字节,但实际仅能读取 %2 个字节。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2325"/>
+ <source>Error loading Amiibo data</source>
+ <translation>加载 Amiibo 数据时出错</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2326"/>
+ <source>Unable to load Amiibo data.</source>
+ <translation>无法加载 Amiibo 数据。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2364"/>
+ <source>Capture Screenshot</source>
+ <translation>捕获截图</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2365"/>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG 图像 (*.png)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2418"/>
+ <source>Speed: %1% / %2%</source>
+ <translation>速度: %1% / %2%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2422"/>
+ <source>Speed: %1%</source>
+ <translation>速度: %1%</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2424"/>
+ <source>Game: %1 FPS</source>
+ <translation>FPS: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2425"/>
+ <source>Frame: %1 ms</source>
+ <translation>帧延迟:%1 毫秒</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2473"/>
+ <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.&lt;br/&gt;&lt;br/&gt;For more information on dumping these files, please see the following wiki page: &lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>您正尝试启动的游戏需要从 Switch 转储的其他文件。&lt;br/&gt;&lt;br/&gt;有关转储这些文件的更多信息,请参阅以下 wiki 页面:&lt;a href=&apos;https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/&apos;&gt;Dumping System Archives and the Shared Fonts from a Switch Console&lt;/a&gt;。&lt;br/&gt;&lt;br/&gt;您要退出并返回至游戏列表吗?继续模拟可能会导致崩溃,存档损坏或其他错误。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2488"/>
+ <source>yuzu was unable to locate a Switch system archive. %1</source>
+ <translation>Yuzu 找不到 Switch 系统档案 %1 </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2490"/>
+ <source>yuzu was unable to locate a Switch system archive: %1. %2</source>
+ <translation>Yuzu 找不到 Switch 系统档案: %1, %2 </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2494"/>
+ <source>System Archive Not Found</source>
+ <translation>未找到系统档案</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2496"/>
+ <source>System Archive Missing</source>
+ <translation>系统档案缺失</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2502"/>
+ <source>yuzu was unable to locate the Switch shared fonts. %1</source>
+ <translation>Yuzu 找不到 Swtich 共享字体 %1 </translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2503"/>
+ <source>Shared Fonts Not Found</source>
+ <translation>未找到共享字体</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2505"/>
+ <source>Shared Font Missing</source>
+ <translation>共享字体文件缺失</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2511"/>
+ <source>Fatal Error</source>
+ <translation>致命错误</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2512"/>
+ <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source>
+ <translation>yuzu 遇到了致命错误,请查看日志了解详情。有关查找日志的更多信息,请参阅以下页面:&lt;a href=&apos;https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;How to Upload the Log File&lt;/a&gt;。&lt;br/&gt;&lt;br/&gt;您要退出并返回至游戏列表吗?继续模拟可能会导致崩溃,存档损坏或其他错误。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2521"/>
+ <source>Fatal Error encountered</source>
+ <translation>发生致命错误</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2544"/>
+ <source>Confirm Key Rederivation</source>
+ <translation>确认重新生成密钥</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2545"/>
+ <source>You are about to force rederive all of your keys.
+If you do not know what this means or what you are doing,
+this is a potentially destructive action.
+Please make sure this is what you want
+and optionally make backups.
+
+This will delete your autogenerated key files and re-run the key derivation module.</source>
+ <translation>即将强制重新生成您的全部密钥。
+如果您不清楚这意味着什么,或您在做什么,
+这可能具有破坏性后果。
+请确保您希望这样做,并且做好备份。
+
+这将删除您自动生成的密钥文件并重新运行密钥生成模块。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2578"/>
+ <source>Missing fuses</source>
+ <translation>项目丢失</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2581"/>
+ <source> - Missing BOOT0</source>
+ <translation>- 丢失 BOOT0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2584"/>
+ <source> - Missing BCPKG2-1-Normal-Main</source>
+ <translation> - 丢失 BCPKG2-1-Normal-Main</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2587"/>
+ <source> - Missing PRODINFO</source>
+ <translation>- 丢失 PRODINFO</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2591"/>
+ <source>Derivation Components Missing</source>
+ <translation>组件丢失</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2592"/>
+ <source>Components are missing that may hinder key derivation from completing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
+ <translation>缺少组件可能会影响密钥的使用。&lt;br&gt;请查看&lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;yuzu 快速导航&lt;/a&gt;以获得你的密钥和游戏。&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2601"/>
+ <source>Deriving keys...
+This may take up to a minute depending
+on your system&apos;s performance.</source>
+ <translation>正在生成密钥...
+这可能需要最多一分钟,具体取决于
+您的系统性能。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2603"/>
+ <source>Deriving Keys</source>
+ <translation>生成密钥</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2648"/>
+ <source>Select RomFS Dump Target</source>
+ <translation>选择 RomFS 转储目标</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2649"/>
+ <source>Please select which RomFS you would like to dump.</source>
+ <translation>请选择希望转储的 RomFS。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <location filename="../../src/yuzu/main.cpp" line="2756"/>
+ <location filename="../../src/yuzu/main.cpp" line="2767"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2665"/>
+ <source>Are you sure you want to close yuzu?</source>
+ <translation>您确定要关闭 yuzu 吗?</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2757"/>
+ <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
+ <translation>您确定要停止模拟吗?未保存的进度将会丢失。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.cpp" line="2768"/>
+ <source>The currently running application has requested yuzu to not exit.
+
+Would you like to bypass this and exit anyway?</source>
+ <translation>当前运行的应用程序请求 yuzu 不要退出。
+
+您希望忽略并退出吗?</translation>
+ </message>
+</context>
+<context>
+ <name>GRenderWindow</name>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="600"/>
+ <source>OpenGL not available!</source>
+ <translation>OpenGL 模式不可用!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="601"/>
+ <source>yuzu has not been compiled with OpenGL support.</source>
+ <translation>yuzu 没有使用 OpenGL 进行编译。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="615"/>
+ <source>Vulkan not available!</source>
+ <translation>Vulkan 模式不可用!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="616"/>
+ <source>yuzu has not been compiled with Vulkan support.</source>
+ <translation>yuzu 没有使用 Vulkan 进行编译。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="625"/>
+ <source>Error while initializing OpenGL 4.3!</source>
+ <translation>初始化 OpenGL 4.3 时出错!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="626"/>
+ <source>Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.</source>
+ <translation>您的 GPU 可能不支持 OpenGL 4.3 ,或者您没有安装最新的显卡驱动。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="634"/>
+ <source>Error while initializing OpenGL!</source>
+ <translation>初始化 OpenGL 时出错!</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/bootmanager.cpp" line="635"/>
+ <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;</source>
+ <translation>您的 GPU 可能不支持某些必需的 OpenGL 扩展。请确保您已经安装最新的显卡驱动。&lt;br&gt;&lt;br&gt;不支持的扩展:&lt;br&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>GameList</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="307"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="651"/>
+ <source>Name</source>
+ <translation>名称</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="308"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="652"/>
+ <source>Compatibility</source>
+ <translation>兼容性</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="311"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="655"/>
+ <source>Add-ons</source>
+ <translation>附加项</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="312"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="315"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="656"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="659"/>
+ <source>File type</source>
+ <translation>文件类型</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="313"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="316"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="657"/>
+ <location filename="../../src/yuzu/game_list.cpp" line="660"/>
+ <source>Size</source>
+ <translation>大小</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="476"/>
+ <source>Open Save Data Location</source>
+ <translation>打开存档位置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="477"/>
+ <source>Open Mod Data Location</source>
+ <translation>打开 MOD 数据位置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="479"/>
+ <source>Open Transferable Shader Cache</source>
+ <translation>打开可转移着色器缓存</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="481"/>
+ <source>Remove</source>
+ <translation>删除</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="482"/>
+ <source>Remove Installed Update</source>
+ <translation>删除已安装的游戏更新</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="483"/>
+ <source>Remove All Installed DLC</source>
+ <translation>删除所有已安装 DLC</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="484"/>
+ <source>Remove Shader Cache</source>
+ <translation>删除着色器缓存</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="485"/>
+ <source>Remove Custom Configuration</source>
+ <translation>删除自定义设置</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="487"/>
+ <source>Remove All Installed Contents</source>
+ <translation>删除所有安装的项目</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="488"/>
+ <source>Dump RomFS</source>
+ <translation>转储 RomFS</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="489"/>
+ <source>Copy Title ID to Clipboard</source>
+ <translation>复制游戏 ID 到剪贴板</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="490"/>
+ <source>Navigate to GameDB entry</source>
+ <translation>查看兼容性报告</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="492"/>
+ <source>Properties</source>
+ <translation>属性</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="542"/>
+ <source>Scan Subfolders</source>
+ <translation>扫描子文件夹</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="543"/>
+ <source>Remove Game Directory</source>
+ <translation>移除游戏目录</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="562"/>
+ <source>▲ Move Up</source>
+ <translation>▲ 向上移动</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="563"/>
+ <source>▼ Move Down</source>
+ <translation>▼ 向下移动</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="564"/>
+ <source>Open Directory Location</source>
+ <translation>打开目录位置</translation>
+ </message>
+</context>
+<context>
+ <name>GameListItemCompat</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Perfect</source>
+ <translation>完美</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="146"/>
+ <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without
+any workarounds needed.</source>
+ <translation>游戏功能完美,没有音频或图形问题,所有测试功能按预期工作,无需需要任何解决办法。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Great</source>
+ <translation>良好</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="147"/>
+ <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some
+workarounds.</source>
+ <translation>游戏运行时会有非常轻微的图像或音频问题,但是能从头玩到尾。可能需要一些技巧才能完成游戏。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Okay</source>
+ <translation>一般</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="148"/>
+ <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with
+workarounds.</source>
+ <translation>游戏运行时会有很多图像或音频错误,但是在使用一些特殊技巧之后能完整地完成游戏。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Bad</source>
+ <translation>较差</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="149"/>
+ <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches
+even with workarounds.</source>
+ <translation>游戏能运行,但是会有大量图像或音频错误。即使使用一些技巧也无法通过游戏的某些区域。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Intro/Menu</source>
+ <translation>开场 / 菜单</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="150"/>
+ <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start
+Screen.</source>
+ <translation>游戏完全没法玩,图像或音频有重大错误。通过开场菜单后无法继续。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>Won&apos;t Boot</source>
+ <translation>无法打开</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="151"/>
+ <source>The game crashes when attempting to startup.</source>
+ <translation>在启动游戏时直接崩溃了。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>Not Tested</source>
+ <translation>未测试</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="152"/>
+ <source>The game has not yet been tested.</source>
+ <translation>游戏尚未经过测试。</translation>
+ </message>
+</context>
+<context>
+ <name>GameListPlaceholder</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="722"/>
+ <source>Double-click to add a new folder to the game list</source>
+ <translation>双击以添加新的游戏文件夹</translation>
+ </message>
+</context>
+<context>
+ <name>GameListSearchField</name>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="120"/>
+ <source>Filter:</source>
+ <translation>搜索:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list.cpp" line="123"/>
+ <source>Enter pattern to filter</source>
+ <translation>搜索游戏</translation>
+ </message>
+</context>
+<context>
+ <name>InstallDialog</name>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="31"/>
+ <source>Please confirm these are the files you wish to install.</source>
+ <translation>请确认这些您想要安装的文件。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="34"/>
+ <source>Installing an Update or DLC will overwrite the previously installed one.</source>
+ <translation>安装游戏更新或 DLC 时,会覆盖以前安装的内容。</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="38"/>
+ <source>Install</source>
+ <translation>安装</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/install_dialog.cpp" line="52"/>
+ <source>Install Files to NAND</source>
+ <translation>安装文件到 NAND</translation>
+ </message>
+</context>
+<context>
+ <name>LoadingScreen</name>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
+ <source>Loading Shaders 387 / 1628</source>
+ <translation>正在加载着色器: 387 / 1628</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
+ <source>Loading Shaders %v out of %m</source>
+ <translation>正在加载着色器: %v / %m</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
+ <source>Estimated Time 5m 4s</source>
+ <translation>所需时间: 5 分 4 秒</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="91"/>
+ <source>Loading...</source>
+ <translation>加载中...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="92"/>
+ <source>Loading Shaders %1 / %2</source>
+ <translation>正在加载着色器: %1 / %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="93"/>
+ <source>Launching...</source>
+ <translation>启动中...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/loading_screen.cpp" line="174"/>
+ <source>Estimated Time %1</source>
+ <translation>所需时间: %1</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="14"/>
+ <source>yuzu</source>
+ <translation>yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="53"/>
+ <source>&amp;File</source>
+ <translation>文件 (&amp;F)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="57"/>
+ <source>Recent Files</source>
+ <translation>最近文件</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="76"/>
+ <source>&amp;Emulation</source>
+ <translation>模拟 (&amp;E)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="88"/>
+ <source>&amp;View</source>
+ <translation>视图 (&amp;V)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="92"/>
+ <source>Debugging</source>
+ <translation>调试</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="106"/>
+ <source>Tools</source>
+ <translation>工具</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="114"/>
+ <source>&amp;Help</source>
+ <translation>帮助 (&amp;H)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="134"/>
+ <source>Install Files to NAND...</source>
+ <translation>安装文件到 NAND...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="139"/>
+ <source>Load File...</source>
+ <translation>加载文件...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="144"/>
+ <source>Load Folder...</source>
+ <translation>加载文件夹...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="149"/>
+ <source>E&amp;xit</source>
+ <translation>退出 (&amp;X)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="157"/>
+ <source>&amp;Start</source>
+ <translation>开始 (&amp;S)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="165"/>
+ <source>&amp;Pause</source>
+ <translation>暂停 (&amp;P)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="173"/>
+ <source>&amp;Stop</source>
+ <translation>停止 (&amp;S)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="178"/>
+ <source>Reinitialize keys...</source>
+ <translation>重新生成密钥...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="183"/>
+ <source>About yuzu</source>
+ <translation>关于 yuzu</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="191"/>
+ <source>Single Window Mode</source>
+ <translation>单窗口模式</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="196"/>
+ <source>Configure...</source>
+ <translation>设置...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="204"/>
+ <source>Display Dock Widget Headers</source>
+ <translation>显示停靠小部件的标题</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="212"/>
+ <source>Show Filter Bar</source>
+ <translation>显示搜索栏</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="220"/>
+ <source>Show Status Bar</source>
+ <translation>显示状态栏</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="225"/>
+ <source>Reset Window Size</source>
+ <translation>重置窗口大小</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="233"/>
+ <source>Fullscreen</source>
+ <translation>全屏</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="241"/>
+ <source>Restart</source>
+ <translation>重新启动</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="249"/>
+ <source>Load Amiibo...</source>
+ <translation>加载 Amiibo...</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="257"/>
+ <source>Report Compatibility</source>
+ <translation>报告兼容性</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="265"/>
+ <source>Open Mods Page</source>
+ <translation>打开 Mod 页面</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="270"/>
+ <source>Open Quickstart Guide</source>
+ <translation>查看快速导航</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="275"/>
+ <source>FAQ</source>
+ <translation>FAQ</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="280"/>
+ <source>Open yuzu Folder</source>
+ <translation>打开 yuzu 文件夹</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="288"/>
+ <source>Capture Screenshot</source>
+ <translation>捕获截图</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/main.ui" line="296"/>
+ <source>Configure Current Game..</source>
+ <translation>配置当前游戏...</translation>
+ </message>
+</context>
+<context>
+ <name>MicroProfileDialog</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/profiler.cpp" line="51"/>
+ <source>MicroProfile</source>
+ <translation>MicroProfile</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="238"/>
+ <source>Installed SD Titles</source>
+ <translation>SD 卡中安装的项目</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="246"/>
+ <source>Installed NAND Titles</source>
+ <translation>NAND 中安装的项目</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="254"/>
+ <source>System Titles</source>
+ <translation>系统项目</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/game_list_p.h" line="296"/>
+ <source>Add New Game Directory</source>
+ <translation>添加游戏目录</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="32"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
+ <source>Shift</source>
+ <translation>Shift</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="34"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
+ <source>Ctrl</source>
+ <translation>Ctrl</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="27"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="36"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
+ <source>Alt</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="37"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="46"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="131"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="181"/>
+ <source>[not set]</source>
+ <translation>[未设置]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="49"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="58"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="157"/>
+ <source>Hat %1 %2</source>
+ <translation>方向键 %1 %2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="56"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="65"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="164"/>
+ <source>Axis %1%2</source>
+ <translation>轴 %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="62"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="71"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/>
+ <source>Button %1</source>
+ <translation>按键 %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="68"/>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="76"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="176"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="227"/>
+ <source>[unknown]</source>
+ <translation>[未知]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="22"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/>
+ <source>Click 0</source>
+ <translation>点击 0</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="24"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
+ <source>Click 1</source>
+ <translation>点击 1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="26"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
+ <source>Click 2</source>
+ <translation>点击 2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="28"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
+ <source>Click 3</source>
+ <translation>点击 3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_mouse_advanced.cpp" line="30"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
+ <source>Click 4</source>
+ <translation>点击 4</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="143"/>
+ <source>GC Axis %1%2</source>
+ <translation>GC 轴 %1%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
+ <source>GC Button %1</source>
+ <translation>GC 按键 %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="190"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="210"/>
+ <source>[unused]</source>
+ <translation>[未使用]</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="196"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/>
+ <source>Axis %1</source>
+ <translation>轴 %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="216"/>
+ <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="222"/>
+ <source>GC Axis %1</source>
+ <translation>GC 轴 %1</translation>
+ </message>
+</context>
+<context>
+ <name>QtErrorDisplay</name>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="22"/>
+ <source>An error has occured.
+Please try again or contact the developer of the software.
+
+Error Code: %1-%2 (0x%3)</source>
+ <translation>发生了一个错误。
+请再试一次或联系开发者。
+
+错误代码: %1-%2 (0x%3)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="35"/>
+ <source>An error occured on %1 at %2.
+Please try again or contact the developer of the software.
+
+Error Code: %3-%4 (0x%5)</source>
+ <translation>在 %2 处的 %1 上发生了一个错误。
+请再试一次或联系开发者。
+
+错误代码: %3-%4 (0x%5)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/error.cpp" line="49"/>
+ <source>An error has occured.
+Error Code: %1-%2 (0x%3)
+
+%4
+
+%5</source>
+ <translation>发生了一个错误。
+错误代码: %1-%2 (0x%3)
+
+%4
+
+%5</translation>
+ </message>
+</context>
+<context>
+ <name>QtProfileSelectionDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="22"/>
+ <source>%1
+%2</source>
+ <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment>
+ <translation>%1
+%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="51"/>
+ <source>Select a user:</source>
+ <translation>选择一个用户:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="80"/>
+ <source>Users</source>
+ <translation>用户</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/profile_select.cpp" line="111"/>
+ <source>Profile Selector</source>
+ <translation>选择用户</translation>
+ </message>
+</context>
+<context>
+ <name>QtSoftwareKeyboardDialog</name>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="59"/>
+ <source>Enter text:</source>
+ <translation>输入文本:</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/applets/software_keyboard.cpp" line="101"/>
+ <source>Software Keyboard</source>
+ <translation>软件键盘</translation>
+ </message>
+</context>
+<context>
+ <name>SequenceDialog</name>
+ <message>
+ <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="11"/>
+ <source>Enter a hotkey</source>
+ <translation>键入热键</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeCallstack</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/>
+ <source>Call stack</source>
+ <translation>调用栈</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeMutexInfo</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="127"/>
+ <source>waiting for mutex 0x%1</source>
+ <translation>正在等待互斥锁 0x%1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="134"/>
+ <source>has waiters: %1</source>
+ <translation>等待中: %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="136"/>
+ <source>owner handle: 0x%1</source>
+ <translation>所有者句柄: 0x%1</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeObjectList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="223"/>
+ <source>waiting for all objects</source>
+ <translation>正在等待所有对象</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="224"/>
+ <source>waiting for one of the following objects</source>
+ <translation>正在等待下列对象中的一个</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeSynchronizationObject</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/>
+ <source>[%1]%2 %3</source>
+ <translation>[%1]%2 %3</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="208"/>
+ <source>waited by no thread</source>
+ <translation>没有等待的线程</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThread</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="243"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="248"/>
+ <source>running</source>
+ <translation>运行中</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/>
+ <source>ready</source>
+ <translation>就绪</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="253"/>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="257"/>
+ <source>paused</source>
+ <translation>暂停</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="260"/>
+ <source>waiting for HLE return</source>
+ <translation>等待 HLE 返回</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="263"/>
+ <source>sleeping</source>
+ <translation>睡眠</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="266"/>
+ <source>waiting for IPC reply</source>
+ <translation>等待 IPC 响应</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="269"/>
+ <source>waiting for objects</source>
+ <translation>等待对象</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="272"/>
+ <source>waiting for mutex</source>
+ <translation>等待互斥锁</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="275"/>
+ <source>waiting for condition variable</source>
+ <translation>等待条件变量</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="278"/>
+ <source>waiting for address arbiter</source>
+ <translation>等待 address arbiter</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/>
+ <source>dormant</source>
+ <translation>休眠</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/>
+ <source>dead</source>
+ <translation>死亡</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="289"/>
+ <source> PC = 0x%1 LR = 0x%2</source>
+ <translation>PC = 0x%1 LR = 0x%2</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/>
+ <source>ideal</source>
+ <translation>ideal</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="348"/>
+ <source>core %1</source>
+ <translation>核心 %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/>
+ <source>Unknown processor %1</source>
+ <translation>未知的处理器 %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/>
+ <source>processor = %1</source>
+ <translation>处理器 = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="357"/>
+ <source>ideal core = %1</source>
+ <translation>理想核心 = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/>
+ <source>affinity mask = %1</source>
+ <translation>关联掩码 = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="360"/>
+ <source>thread id = %1</source>
+ <translation>线程 ID = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="361"/>
+ <source>priority = %1(current) / %2(normal)</source>
+ <translation>优先级 = %1 (实时) / %2 (正常)</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="365"/>
+ <source>last running ticks = %1</source>
+ <translation>最后运行频率 = %1</translation>
+ </message>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="372"/>
+ <source>not waiting for mutex</source>
+ <translation>未等待互斥锁</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeThreadList</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="394"/>
+ <source>waited by thread</source>
+ <translation>等待中的线程</translation>
+ </message>
+</context>
+<context>
+ <name>WaitTreeWidget</name>
+ <message>
+ <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="466"/>
+ <source>Wait Tree</source>
+ <translation>等待树</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/dist/license.md b/dist/license.md
index f1ff35c95..e9bc87656 100644
--- a/dist/license.md
+++ b/dist/license.md
@@ -5,6 +5,7 @@ Icon Name | License | Origin/Author
qt_themes/default/icons/16x16/checked.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/default/icons/16x16/failed.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/default/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
+qt_themes/default/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io
qt_themes/default/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/default/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/default/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
@@ -12,6 +13,7 @@ qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/qdarkstyle/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
+qt_themes/qdarkstyle/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io
qt_themes/qdarkstyle/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/qdarkstyle/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/qdarkstyle/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
@@ -19,6 +21,7 @@ qt_themes/qdarkstyle/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/qdarkstyle/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
qt_themes/qdarkstyle/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/colorful/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
+qt_themes/colorful/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io
qt_themes/colorful/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/colorful/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/colorful/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
diff --git a/dist/qt_themes/colorful_dark/icons/16x16/refresh.png b/dist/qt_themes/colorful_dark/icons/16x16/refresh.png
new file mode 100644
index 000000000..d4afd76f9
--- /dev/null
+++ b/dist/qt_themes/colorful_dark/icons/16x16/refresh.png
Binary files differ
diff --git a/dist/qt_themes/colorful_dark/icons/16x16/view-refresh.png b/dist/qt_themes/colorful_dark/icons/16x16/view-refresh.png
new file mode 100644
index 000000000..d4afd76f9
--- /dev/null
+++ b/dist/qt_themes/colorful_dark/icons/16x16/view-refresh.png
Binary files differ
diff --git a/dist/qt_themes/colorful_dark/style.qrc b/dist/qt_themes/colorful_dark/style.qrc
index 27a6cc87d..0abcb4e83 100644
--- a/dist/qt_themes/colorful_dark/style.qrc
+++ b/dist/qt_themes/colorful_dark/style.qrc
@@ -2,6 +2,7 @@
<qresource prefix="icons/colorful_dark">
<file alias="index.theme">icons/index.theme</file>
<file alias="16x16/lock.png">icons/16x16/lock.png</file>
+ <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
diff --git a/dist/qt_themes/colorful_midnight_blue/icons/16x16/refresh.png b/dist/qt_themes/colorful_midnight_blue/icons/16x16/refresh.png
new file mode 100644
index 000000000..d4afd76f9
--- /dev/null
+++ b/dist/qt_themes/colorful_midnight_blue/icons/16x16/refresh.png
Binary files differ
diff --git a/dist/qt_themes/colorful_midnight_blue/icons/16x16/view-refresh.png b/dist/qt_themes/colorful_midnight_blue/icons/16x16/view-refresh.png
new file mode 100644
index 000000000..d4afd76f9
--- /dev/null
+++ b/dist/qt_themes/colorful_midnight_blue/icons/16x16/view-refresh.png
Binary files differ
diff --git a/dist/qt_themes/colorful_midnight_blue/style.qrc b/dist/qt_themes/colorful_midnight_blue/style.qrc
index fd33bc850..bf367099a 100644
--- a/dist/qt_themes/colorful_midnight_blue/style.qrc
+++ b/dist/qt_themes/colorful_midnight_blue/style.qrc
@@ -2,6 +2,7 @@
<qresource prefix="icons/colorful_midnight_blue">
<file alias="index.theme">icons/index.theme</file>
<file alias="16x16/lock.png">icons/16x16/lock.png</file>
+ <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
diff --git a/dist/qt_themes/default/default.qrc b/dist/qt_themes/default/default.qrc
index c51fdb26c..2182f33f3 100644
--- a/dist/qt_themes/default/default.qrc
+++ b/dist/qt_themes/default/default.qrc
@@ -4,6 +4,7 @@
<file alias="16x16/checked.png">icons/16x16/checked.png</file>
<file alias="16x16/failed.png">icons/16x16/failed.png</file>
<file alias="16x16/lock.png">icons/16x16/lock.png</file>
+ <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
diff --git a/dist/qt_themes/default/icons/16x16/refresh.png b/dist/qt_themes/default/icons/16x16/refresh.png
new file mode 100644
index 000000000..69f9474ac
--- /dev/null
+++ b/dist/qt_themes/default/icons/16x16/refresh.png
Binary files differ
diff --git a/dist/qt_themes/default/icons/16x16/view-refresh.png b/dist/qt_themes/default/icons/16x16/view-refresh.png
new file mode 100644
index 000000000..69f9474ac
--- /dev/null
+++ b/dist/qt_themes/default/icons/16x16/view-refresh.png
Binary files differ
diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss
index 6b5953e38..b6dd2063d 100644
--- a/dist/qt_themes/default/style.qss
+++ b/dist/qt_themes/default/style.qss
@@ -30,6 +30,250 @@ QPushButton#RendererStatusBarButton:checked {
color: #e85c00;
}
-QPushButton#RendererStatusBarButton:!checked{
+QPushButton#RendererStatusBarButton:!checked {
color: #0066ff;
}
+
+QPushButton#buttonRefreshDevices {
+ min-width: 20px;
+ min-height: 20px;
+ max-width: 20px;
+ max-height: 20px;
+}
+
+QWidget#bottomPerGameInput,
+QWidget#topControllerApplet,
+QWidget#bottomControllerApplet,
+QGroupBox#groupPlayer1Connected:checked,
+QGroupBox#groupPlayer2Connected:checked,
+QGroupBox#groupPlayer3Connected:checked,
+QGroupBox#groupPlayer4Connected:checked,
+QGroupBox#groupPlayer5Connected:checked,
+QGroupBox#groupPlayer6Connected:checked,
+QGroupBox#groupPlayer7Connected:checked,
+QGroupBox#groupPlayer8Connected:checked {
+ background-color: #f5f5f5;
+}
+
+QWidget#topControllerApplet {
+ border-bottom: 1px solid #828790
+}
+
+QWidget#bottomPerGameInput,
+QWidget#bottomControllerApplet {
+ border-top: 1px solid #828790
+}
+
+QWidget#topPerGameInput,
+QWidget#middleControllerApplet {
+ background-color: #fff;
+}
+
+QWidget#topPerGameInput QComboBox,
+QWidget#middleControllerApplet QComboBox {
+ width: 123px;
+}
+
+QWidget#connectedControllers {
+ background: transparent;
+}
+
+QWidget#playersSupported,
+QWidget#controllersSupported,
+QWidget#controllerSupported1,
+QWidget#controllerSupported2,
+QWidget#controllerSupported3,
+QWidget#controllerSupported4,
+QWidget#controllerSupported5,
+QWidget#controllerSupported6 {
+ border: none;
+ background: transparent;
+}
+
+QGroupBox#groupPlayer1Connected,
+QGroupBox#groupPlayer2Connected,
+QGroupBox#groupPlayer3Connected,
+QGroupBox#groupPlayer4Connected,
+QGroupBox#groupPlayer5Connected,
+QGroupBox#groupPlayer6Connected,
+QGroupBox#groupPlayer7Connected,
+QGroupBox#groupPlayer8Connected {
+ border: 1px solid #828790;
+ border-radius: 3px;
+ padding: 0px;
+ min-height: 98px;
+ max-height: 98px;
+}
+
+QGroupBox#groupPlayer1Connected:unchecked,
+QGroupBox#groupPlayer2Connected:unchecked,
+QGroupBox#groupPlayer3Connected:unchecked,
+QGroupBox#groupPlayer4Connected:unchecked,
+QGroupBox#groupPlayer5Connected:unchecked,
+QGroupBox#groupPlayer6Connected:unchecked,
+QGroupBox#groupPlayer7Connected:unchecked,
+QGroupBox#groupPlayer8Connected:unchecked {
+ border: 1px solid #d9d9d9;
+}
+
+QGroupBox#groupPlayer1Connected::title,
+QGroupBox#groupPlayer2Connected::title,
+QGroupBox#groupPlayer3Connected::title,
+QGroupBox#groupPlayer4Connected::title,
+QGroupBox#groupPlayer5Connected::title,
+QGroupBox#groupPlayer6Connected::title,
+QGroupBox#groupPlayer7Connected::title,
+QGroupBox#groupPlayer8Connected::title {
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-top: 1px;
+ margin-left: 0px;
+ margin-right: -4px;
+ margin-bottom: 4px;
+}
+
+QCheckBox#checkboxPlayer1Connected,
+QCheckBox#checkboxPlayer2Connected,
+QCheckBox#checkboxPlayer3Connected,
+QCheckBox#checkboxPlayer4Connected,
+QCheckBox#checkboxPlayer5Connected,
+QCheckBox#checkboxPlayer6Connected,
+QCheckBox#checkboxPlayer7Connected,
+QCheckBox#checkboxPlayer8Connected {
+ spacing: 0px;
+}
+
+QWidget#Player1LEDs QCheckBox,
+QWidget#Player2LEDs QCheckBox,
+QWidget#Player3LEDs QCheckBox,
+QWidget#Player4LEDs QCheckBox,
+QWidget#Player5LEDs QCheckBox,
+QWidget#Player6LEDs QCheckBox,
+QWidget#Player7LEDs QCheckBox,
+QWidget#Player8LEDs QCheckBox {
+ spacing: 0px;
+}
+
+QWidget#Player1LEDs QCheckBox::indicator,
+QWidget#Player2LEDs QCheckBox::indicator,
+QWidget#Player3LEDs QCheckBox::indicator,
+QWidget#Player4LEDs QCheckBox::indicator,
+QWidget#Player5LEDs QCheckBox::indicator,
+QWidget#Player6LEDs QCheckBox::indicator,
+QWidget#Player7LEDs QCheckBox::indicator,
+QWidget#Player8LEDs QCheckBox::indicator {
+ width: 6px;
+ height: 6px;
+ margin-left: 0px;
+}
+
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
+ width: 12px;
+ height: 12px;
+}
+
+QCheckBox#checkboxPlayer1Connected::indicator,
+QCheckBox#checkboxPlayer2Connected::indicator,
+QCheckBox#checkboxPlayer3Connected::indicator,
+QCheckBox#checkboxPlayer4Connected::indicator,
+QCheckBox#checkboxPlayer5Connected::indicator,
+QCheckBox#checkboxPlayer6Connected::indicator,
+QCheckBox#checkboxPlayer7Connected::indicator,
+QCheckBox#checkboxPlayer8Connected::indicator {
+ width: 14px;
+ height: 14px;
+}
+
+QGroupBox#groupPlayer1Connected::indicator,
+QGroupBox#groupPlayer2Connected::indicator,
+QGroupBox#groupPlayer3Connected::indicator,
+QGroupBox#groupPlayer4Connected::indicator,
+QGroupBox#groupPlayer5Connected::indicator,
+QGroupBox#groupPlayer6Connected::indicator,
+QGroupBox#groupPlayer7Connected::indicator,
+QGroupBox#groupPlayer8Connected::indicator {
+ width: 16px;
+ height: 16px;
+}
+
+QWidget#Player1LEDs QCheckBox::indicator:checked,
+QWidget#Player2LEDs QCheckBox::indicator:checked,
+QWidget#Player3LEDs QCheckBox::indicator:checked,
+QWidget#Player4LEDs QCheckBox::indicator:checked,
+QWidget#Player5LEDs QCheckBox::indicator:checked,
+QWidget#Player6LEDs QCheckBox::indicator:checked,
+QWidget#Player7LEDs QCheckBox::indicator:checked,
+QWidget#Player8LEDs QCheckBox::indicator:checked,
+QGroupBox#groupPlayer1Connected::indicator:checked,
+QGroupBox#groupPlayer2Connected::indicator:checked,
+QGroupBox#groupPlayer3Connected::indicator:checked,
+QGroupBox#groupPlayer4Connected::indicator:checked,
+QGroupBox#groupPlayer5Connected::indicator:checked,
+QGroupBox#groupPlayer6Connected::indicator:checked,
+QGroupBox#groupPlayer7Connected::indicator:checked,
+QGroupBox#groupPlayer8Connected::indicator:checked,
+QCheckBox#checkboxPlayer1Connected::indicator:checked,
+QCheckBox#checkboxPlayer2Connected::indicator:checked,
+QCheckBox#checkboxPlayer3Connected::indicator:checked,
+QCheckBox#checkboxPlayer4Connected::indicator:checked,
+QCheckBox#checkboxPlayer5Connected::indicator:checked,
+QCheckBox#checkboxPlayer6Connected::indicator:checked,
+QCheckBox#checkboxPlayer7Connected::indicator:checked,
+QCheckBox#checkboxPlayer8Connected::indicator:checked,
+QGroupBox#groupConnectedController::indicator:checked {
+ border-radius: 2px;
+ border: 1px solid #929192;
+ background: #39ff14;
+ image: none;
+}
+
+QWidget#Player1LEDs QCheckBox::indicator:unchecked,
+QWidget#Player2LEDs QCheckBox::indicator:unchecked,
+QWidget#Player3LEDs QCheckBox::indicator:unchecked,
+QWidget#Player4LEDs QCheckBox::indicator:unchecked,
+QWidget#Player5LEDs QCheckBox::indicator:unchecked,
+QWidget#Player6LEDs QCheckBox::indicator:unchecked,
+QWidget#Player7LEDs QCheckBox::indicator:unchecked,
+QWidget#Player8LEDs QCheckBox::indicator:unchecked,
+QGroupBox#groupPlayer1Connected::indicator:unchecked,
+QGroupBox#groupPlayer2Connected::indicator:unchecked,
+QGroupBox#groupPlayer3Connected::indicator:unchecked,
+QGroupBox#groupPlayer4Connected::indicator:unchecked,
+QGroupBox#groupPlayer5Connected::indicator:unchecked,
+QGroupBox#groupPlayer6Connected::indicator:unchecked,
+QGroupBox#groupPlayer7Connected::indicator:unchecked,
+QGroupBox#groupPlayer8Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer4Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer5Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
+QGroupBox#groupConnectedController::indicator:unchecked {
+ border-radius: 2px;
+ border: 1px solid #929192;
+ background: transparent;
+ image: none;
+}
+
+QWidget#controllerPlayer1,
+QWidget#controllerPlayer2,
+QWidget#controllerPlayer3,
+QWidget#controllerPlayer4,
+QWidget#controllerPlayer5,
+QWidget#controllerPlayer6,
+QWidget#controllerPlayer7,
+QWidget#controllerPlayer8 {
+ background: transparent;
+}
diff --git a/dist/qt_themes/qdarkstyle/icons/16x16/refresh.png b/dist/qt_themes/qdarkstyle/icons/16x16/refresh.png
new file mode 100644
index 000000000..d4afd76f9
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle/icons/16x16/refresh.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/icons/16x16/view-refresh.png b/dist/qt_themes/qdarkstyle/icons/16x16/view-refresh.png
new file mode 100644
index 000000000..d4afd76f9
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle/icons/16x16/view-refresh.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/style.qrc b/dist/qt_themes/qdarkstyle/style.qrc
index c2c14c28a..2b91204f3 100644
--- a/dist/qt_themes/qdarkstyle/style.qrc
+++ b/dist/qt_themes/qdarkstyle/style.qrc
@@ -2,6 +2,7 @@
<qresource prefix="icons/qdarkstyle">
<file alias="index.theme">icons/index.theme</file>
<file alias="16x16/lock.png">icons/16x16/lock.png</file>
+ <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
@@ -51,6 +52,6 @@
<file>rc/radio_unchecked.png</file>
</qresource>
<qresource prefix="qdarkstyle">
- <file>style.qss</file>
+ <file>style.qss</file>
</qresource>
</RCC>
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 2926a05fa..66026e8be 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -40,8 +40,8 @@ QCheckBox:disabled {
QCheckBox::indicator,
QGroupBox::indicator {
- width: 18px;
- height: 18px;
+ width: 16px;
+ height: 16px;
}
QGroupBox::indicator {
@@ -1237,6 +1237,7 @@ QPlainTextEdit:disabled {
background-color: #2b2e31;
}
+
QPushButton#TogglableStatusBarButton {
min-width: 0px;
color: #656565;
@@ -1271,6 +1272,305 @@ QPushButton#RendererStatusBarButton:checked {
color: #e85c00;
}
-QPushButton#RendererStatusBarButton:!checked{
- color: #00ccdd;
+QPushButton#RendererStatusBarButton:!checked {
+ color: #00ccdd;
+}
+
+QPushButton#buttonRefreshDevices {
+ min-width: 24px;
+ min-height: 24px;
+ max-width: 24px;
+ max-height: 24px;
+ padding: 0px 0px;
+}
+
+QSpinBox#spinboxLStickRange,
+QSpinBox#spinboxRStickRange {
+ padding: 4px 0px 5px 0px;
+ min-width: 63px;
+}
+
+QSpinBox#vibrationSpin {
+ padding: 4px 0px 5px 0px;
+ min-width: 63px;
+}
+
+QSpinBox#spinboxLStickRange:up-button,
+QSpinBox#spinboxRStickRange:up-button,
+QSpinBox#vibrationSpin:up-button {
+ left: -2px;
+}
+
+QSpinBox#spinboxLStickRange:down-button,
+QSpinBox#spinboxRStickRange:down-button,
+QSpinBox#vibrationSpin:down-button {
+ right: -1px;
+}
+
+QGroupBox#motionGroup::indicator,
+QGroupBox#vibrationGroup::indicator {
+ margin-left: 0px;
+}
+
+QGroupBox#motionGroup::title,
+QGroupBox#vibrationGroup::title {
+ spacing: 2px;
+ padding-left: 1px;
+ padding-right: 1px;
+}
+
+QWidget#bottomPerGameInput,
+QWidget#topControllerApplet,
+QWidget#bottomControllerApplet,
+QGroupBox#groupPlayer1Connected:checked,
+QGroupBox#groupPlayer2Connected:checked,
+QGroupBox#groupPlayer3Connected:checked,
+QGroupBox#groupPlayer4Connected:checked,
+QGroupBox#groupPlayer5Connected:checked,
+QGroupBox#groupPlayer6Connected:checked,
+QGroupBox#groupPlayer7Connected:checked,
+QGroupBox#groupPlayer8Connected:checked {
+ background-color: #232629;
+}
+
+QWidget#topPerGameInput,
+QWidget#middleControllerApplet {
+ background-color: #31363b;
+}
+
+QWidget#topPerGameInput QComboBox,
+QWidget#middleControllerApplet QComboBox {
+ width: 119px;
+}
+
+QRadioButton#radioDocked {
+ margin-left: -3px;
+}
+
+
+QRadioButton#radioUndocked {
+ margin-right: 5px;
+}
+
+QWidget#connectedControllers {
+ background: transparent;
+}
+
+QWidget#playersSupported,
+QWidget#controllersSupported,
+QWidget#controllerSupported1,
+QWidget#controllerSupported2,
+QWidget#controllerSupported3,
+QWidget#controllerSupported4,
+QWidget#controllerSupported5,
+QWidget#controllerSupported6 {
+ border: none;
+ background: transparent;
+}
+
+QGroupBox#groupPlayer1Connected,
+QGroupBox#groupPlayer2Connected,
+QGroupBox#groupPlayer3Connected,
+QGroupBox#groupPlayer4Connected,
+QGroupBox#groupPlayer5Connected,
+QGroupBox#groupPlayer6Connected,
+QGroupBox#groupPlayer7Connected,
+QGroupBox#groupPlayer8Connected {
+ border: 1px solid #76797c;
+ border-radius: 3px;
+ padding: 0px;
+ min-height: 98px;
+ max-height: 98px;
+ margin-top: 0px;
+}
+
+QGroupBox#groupPlayer1Connected:unchecked,
+QGroupBox#groupPlayer2Connected:unchecked,
+QGroupBox#groupPlayer3Connected:unchecked,
+QGroupBox#groupPlayer4Connected:unchecked,
+QGroupBox#groupPlayer5Connected:unchecked,
+QGroupBox#groupPlayer6Connected:unchecked,
+QGroupBox#groupPlayer7Connected:unchecked,
+QGroupBox#groupPlayer8Connected:unchecked {
+ border: 1px solid #54575b;
+}
+
+QGroupBox#groupPlayer1Connected::title,
+QGroupBox#groupPlayer2Connected::title,
+QGroupBox#groupPlayer3Connected::title,
+QGroupBox#groupPlayer4Connected::title,
+QGroupBox#groupPlayer5Connected::title,
+QGroupBox#groupPlayer6Connected::title,
+QGroupBox#groupPlayer7Connected::title,
+QGroupBox#groupPlayer8Connected::title {
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-top: 1px;
+ margin-left: -2px;
+ margin-right: -4px;
+ margin-bottom: 6px;
+}
+
+QCheckBox#checkboxPlayer1Connected,
+QCheckBox#checkboxPlayer2Connected,
+QCheckBox#checkboxPlayer3Connected,
+QCheckBox#checkboxPlayer4Connected,
+QCheckBox#checkboxPlayer5Connected,
+QCheckBox#checkboxPlayer6Connected,
+QCheckBox#checkboxPlayer7Connected,
+QCheckBox#checkboxPlayer8Connected {
+ spacing: 0px;
+}
+
+QWidget#Player1LEDs,
+QWidget#Player2LEDs,
+QWidget#Player3LEDs,
+QWidget#Player4LEDs,
+QWidget#Player5LEDs,
+QWidget#Player6LEDs,
+QWidget#Player7LEDs,
+QWidget#Player8LEDs {
+ background: transparent;
+}
+
+QWidget#Player1LEDs QCheckBox,
+QWidget#Player2LEDs QCheckBox,
+QWidget#Player3LEDs QCheckBox,
+QWidget#Player4LEDs QCheckBox,
+QWidget#Player5LEDs QCheckBox,
+QWidget#Player6LEDs QCheckBox,
+QWidget#Player7LEDs QCheckBox,
+QWidget#Player8LEDs QCheckBox {
+ spacing: 0px;
+ margin-bottom: 0px;
+ margin-right: 0px;
+}
+
+QWidget#Player1LEDs QCheckBox::indicator,
+QWidget#Player2LEDs QCheckBox::indicator,
+QWidget#Player3LEDs QCheckBox::indicator,
+QWidget#Player4LEDs QCheckBox::indicator,
+QWidget#Player5LEDs QCheckBox::indicator,
+QWidget#Player6LEDs QCheckBox::indicator,
+QWidget#Player7LEDs QCheckBox::indicator,
+QWidget#Player8LEDs QCheckBox::indicator {
+ width: 6px;
+ height: 6px;
+ margin-left: 0px;
+}
+
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
+ width: 12px;
+ height: 12px;
+}
+
+QCheckBox#checkboxPlayer1Connected::indicator,
+QCheckBox#checkboxPlayer2Connected::indicator,
+QCheckBox#checkboxPlayer3Connected::indicator,
+QCheckBox#checkboxPlayer4Connected::indicator,
+QCheckBox#checkboxPlayer5Connected::indicator,
+QCheckBox#checkboxPlayer6Connected::indicator,
+QCheckBox#checkboxPlayer7Connected::indicator,
+QCheckBox#checkboxPlayer8Connected::indicator {
+ width: 14px;
+ height: 14px;
+}
+
+QGroupBox#groupPlayer1Connected::indicator,
+QGroupBox#groupPlayer2Connected::indicator,
+QGroupBox#groupPlayer3Connected::indicator,
+QGroupBox#groupPlayer4Connected::indicator,
+QGroupBox#groupPlayer5Connected::indicator,
+QGroupBox#groupPlayer6Connected::indicator,
+QGroupBox#groupPlayer7Connected::indicator,
+QGroupBox#groupPlayer8Connected::indicator {
+ width: 16px;
+ height: 16px;
+}
+
+QWidget#Player1LEDs QCheckBox::indicator:checked,
+QWidget#Player2LEDs QCheckBox::indicator:checked,
+QWidget#Player3LEDs QCheckBox::indicator:checked,
+QWidget#Player4LEDs QCheckBox::indicator:checked,
+QWidget#Player5LEDs QCheckBox::indicator:checked,
+QWidget#Player6LEDs QCheckBox::indicator:checked,
+QWidget#Player7LEDs QCheckBox::indicator:checked,
+QWidget#Player8LEDs QCheckBox::indicator:checked,
+QGroupBox#groupPlayer1Connected::indicator:checked,
+QGroupBox#groupPlayer2Connected::indicator:checked,
+QGroupBox#groupPlayer3Connected::indicator:checked,
+QGroupBox#groupPlayer4Connected::indicator:checked,
+QGroupBox#groupPlayer5Connected::indicator:checked,
+QGroupBox#groupPlayer6Connected::indicator:checked,
+QGroupBox#groupPlayer7Connected::indicator:checked,
+QGroupBox#groupPlayer8Connected::indicator:checked,
+QCheckBox#checkboxPlayer1Connected::indicator:checked,
+QCheckBox#checkboxPlayer2Connected::indicator:checked,
+QCheckBox#checkboxPlayer3Connected::indicator:checked,
+QCheckBox#checkboxPlayer4Connected::indicator:checked,
+QCheckBox#checkboxPlayer5Connected::indicator:checked,
+QCheckBox#checkboxPlayer6Connected::indicator:checked,
+QCheckBox#checkboxPlayer7Connected::indicator:checked,
+QCheckBox#checkboxPlayer8Connected::indicator:checked,
+QGroupBox#groupConnectedController::indicator:checked {
+ border-radius: 2px;
+ border: 1px solid #929192;
+ background: #39ff14;
+ image: none;
+}
+
+QWidget#Player1LEDs QCheckBox::indicator:unchecked,
+QWidget#Player2LEDs QCheckBox::indicator:unchecked,
+QWidget#Player3LEDs QCheckBox::indicator:unchecked,
+QWidget#Player4LEDs QCheckBox::indicator:unchecked,
+QWidget#Player5LEDs QCheckBox::indicator:unchecked,
+QWidget#Player6LEDs QCheckBox::indicator:unchecked,
+QWidget#Player7LEDs QCheckBox::indicator:unchecked,
+QWidget#Player8LEDs QCheckBox::indicator:unchecked,
+QGroupBox#groupPlayer1Connected::indicator:unchecked,
+QGroupBox#groupPlayer2Connected::indicator:unchecked,
+QGroupBox#groupPlayer3Connected::indicator:unchecked,
+QGroupBox#groupPlayer4Connected::indicator:unchecked,
+QGroupBox#groupPlayer5Connected::indicator:unchecked,
+QGroupBox#groupPlayer6Connected::indicator:unchecked,
+QGroupBox#groupPlayer7Connected::indicator:unchecked,
+QGroupBox#groupPlayer8Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer4Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer5Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
+QGroupBox#groupConnectedController::indicator:unchecked {
+ border-radius: 2px;
+ border: 1px solid #929192;
+ background: transparent;
+ image: none;
+}
+
+QWidget#controllerPlayer1,
+QWidget#controllerPlayer2,
+QWidget#controllerPlayer3,
+QWidget#controllerPlayer4,
+QWidget#controllerPlayer5,
+QWidget#controllerPlayer6,
+QWidget#controllerPlayer7,
+QWidget#controllerPlayer8 {
+ background: transparent;
+}
+
+/* touchscreen mapping widget */
+TouchScreenPreview {
+ qproperty-dotHighlightColor: #3daee9;
}
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/refresh.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/refresh.png
new file mode 100644
index 000000000..d4afd76f9
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/refresh.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/view-refresh.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/view-refresh.png
new file mode 100644
index 000000000..d4afd76f9
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/view-refresh.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc
index 1b7686f15..579e73ece 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc
@@ -2,6 +2,7 @@
<qresource prefix="icons/qdarkstyle_midnight_blue">
<file alias="index.theme">icons/index.theme</file>
<file alias="16x16/lock.png">icons/16x16/lock.png</file>
+ <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
@@ -220,6 +221,6 @@
<file>rc/window_undock_pressed@2x.png</file>
</qresource>
<qresource prefix="qdarkstyle_midnight_blue">
- <file>style.qss</file>
+ <file>style.qss</file>
</qresource>
</RCC>
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
index 9c24b0d07..c6318ba4e 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -138,8 +138,6 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar
--------------------------------------------------------------------------- */
QStatusBar {
- border: 1px solid #32414B;
- /* Fixes Spyder #9120, #9121 */
background: #32414B;
/* Fixes #205, white vertical borders separating items */
}
@@ -161,6 +159,7 @@ QStatusBar QToolTip {
QStatusBar QLabel {
/* Fixes Spyder #9120, #9121 */
background: transparent;
+ padding: 0px;
}
/* QCheckBox --------------------------------------------------------------
@@ -239,18 +238,16 @@ QGroupBox {
font-weight: bold;
border: 1px solid #32414B;
border-radius: 4px;
+ margin-top: 12px;
padding: 4px;
- margin-top: 16px;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top left;
- left: 3px;
padding-left: 3px;
padding-right: 5px;
- padding-top: 8px;
- padding-bottom: 16px;
+ padding-top: 4px;
}
QGroupBox::indicator {
@@ -367,28 +364,19 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar
--------------------------------------------------------------------------- */
QMenuBar {
background-color: #32414B;
- padding: 2px;
- border: 1px solid #19232D;
color: #F0F0F0;
}
-QMenuBar:focus {
- border: 1px solid #148CD2;
-}
-
QMenuBar::item {
background: transparent;
- padding: 4px;
}
QMenuBar::item:selected {
- padding: 4px;
background: transparent;
border: 0px solid #32414B;
}
QMenuBar::item:pressed {
- padding: 4px;
border: 0px solid #32414B;
background-color: #148CD2;
color: #F0F0F0;
@@ -396,6 +384,7 @@ QMenuBar::item:pressed {
padding-bottom: 0px;
}
+
/* QMenu ------------------------------------------------------------------
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu
@@ -482,7 +471,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox
--------------------------------------------------------------------------- */
QAbstractItemView {
- alternate-background-color: #19232D;
+ alternate-background-color: #1f2933;
color: #F0F0F0;
border: 1px solid #32414B;
border-radius: 4px;
@@ -501,13 +490,13 @@ QAbstractScrollArea {
background-color: #19232D;
border: 1px solid #32414B;
border-radius: 4px;
- padding: 2px;
/* fix #159 */
min-height: 1.25em;
/* fix #159 */
color: #F0F0F0;
}
+
QAbstractScrollArea:disabled {
color: #787878;
}
@@ -807,20 +796,22 @@ QAbstractSpinBox {
}
QAbstractSpinBox:up-button {
- background-color: transparent #19232D;
+ background-color: #505F69;
subcontrol-origin: border;
subcontrol-position: top right;
border-left: 1px solid #32414B;
- border-bottom: 1px solid #32414B;
+ border-top: 1px solid #32414B;
+ border-right: 1px solid #32414B;
+ border-top-right-radius: 4px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
- margin: 1px;
+ margin: 0px;
width: 12px;
- margin-bottom: -1px;
+ margin-bottom: 0px;
}
QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off {
- image: url(":/qss_icons/rc/arrow_up_disabled.png");
+ image: url(":/qss_icons/rc/up_arrow.png");
height: 8px;
width: 8px;
}
@@ -830,20 +821,23 @@ QAbstractSpinBox::up-arrow:hover {
}
QAbstractSpinBox:down-button {
- background-color: transparent #19232D;
+ background-color: #505F69;
subcontrol-origin: border;
subcontrol-position: bottom right;
border-left: 1px solid #32414B;
+ border-right: 1px solid #32414B;
+ border-bottom: 1px solid #32414B;
border-top: 1px solid #32414B;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
- margin: 1px;
+ border-bottom-right-radius: 4px;
+ margin: 0px;
width: 12px;
- margin-top: -1px;
+ margin-top: 0px;
}
QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off {
- image: url(":/qss_icons/rc/arrow_down_disabled.png");
+ image: url(":/qss_icons/rc/down_arrow.png");
height: 8px;
width: 8px;
}
@@ -1199,6 +1193,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox
--------------------------------------------------------------------------- */
QComboBox {
+ background-color: #0f1922;
border: 1px solid #32414B;
border-radius: 4px;
selection-background-color: #1464A0;
@@ -1216,7 +1211,7 @@ QComboBox {
QComboBox QAbstractItemView {
border: 1px solid #32414B;
border-radius: 0;
- background-color: #19232D;
+ background-color: #0f1922;
selection-background-color: #1464A0;
}
@@ -1285,7 +1280,12 @@ QComboBox::drop-down {
}
QComboBox::down-arrow {
- image: url(":/qss_icons/rc/arrow_down_disabled.png");
+ image: url(":/qss_icons/rc/down_arrow.png");
+ background-color: #505F69;
+ padding: 6px 2px;
+ border: 1px solid #32414B;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
height: 8px;
width: 8px;
}
@@ -1559,12 +1559,12 @@ QTabBar::tab:right:!selected {
QTabBar::tab:top {
background-color: #32414B;
color: #F0F0F0;
+ min-width: 36px;
margin-left: 2px;
- padding-left: 4px;
- padding-right: 4px;
+ padding-left: 8px;
+ padding-right: 8px;
padding-top: 2px;
padding-bottom: 2px;
- min-width: 5px;
border-bottom: 3px solid #32414B;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
@@ -1588,16 +1588,16 @@ QTabBar::tab:top:!selected:hover {
QTabBar::tab:bottom {
color: #F0F0F0;
+ min-width: 36px;
border-top: 3px solid #32414B;
background-color: #32414B;
margin-left: 2px;
- padding-left: 4px;
- padding-right: 4px;
+ padding-left: 8px;
+ padding-right: 8px;
padding-top: 2px;
padding-bottom: 2px;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
- min-width: 5px;
}
QTabBar::tab:bottom:selected {
@@ -1752,21 +1752,6 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview
--------------------------------------------------------------------------- */
-QTreeView:branch:selected, QTreeView:branch:hover {
- background: url(":/qss_icons/rc/transparent.png");
-}
-
-QTreeView:branch:has-siblings:!adjoins-item {
- border-image: url(":/qss_icons/rc/branch_line.png") 0;
-}
-
-QTreeView:branch:has-siblings:adjoins-item {
- border-image: url(":/qss_icons/rc/branch_more.png") 0;
-}
-
-QTreeView:branch:!has-children:!has-siblings:adjoins-item {
- border-image: url(":/qss_icons/rc/branch_end.png") 0;
-}
QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings {
border-image: none;
@@ -1900,21 +1885,21 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview
--------------------------------------------------------------------------- */
QHeaderView {
- background-color: #32414B;
- border: 0px transparent #32414B;
+ background-color: #19232D;
+ border: 0px transparent #19232D;
padding: 0px;
margin: 0px;
border-radius: 0px;
}
QHeaderView:disabled {
- background-color: #32414B;
- border: 1px transparent #32414B;
+ background-color: #19232D;
+ border: 1px transparent #19232D;
padding: 2px;
}
QHeaderView::section {
- background-color: #32414B;
+ background-color: #19232D;
color: #F0F0F0;
padding: 2px;
border-radius: 0px;
@@ -1934,11 +1919,11 @@ QHeaderView::section:checked:disabled {
QHeaderView::section::horizontal {
padding-left: 4px;
padding-right: 4px;
- border-left: 1px solid #19232D;
+ border-left: 1px solid #32414B;
}
QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one {
- border-left: 1px solid #32414B;
+ border-left: 1px solid #19232D;
}
QHeaderView::section::horizontal:disabled {
@@ -1948,7 +1933,7 @@ QHeaderView::section::horizontal:disabled {
QHeaderView::section::vertical {
padding-left: 4px;
padding-right: 4px;
- border-top: 1px solid #19232D;
+ border-top: 1px solid #32414B;
}
QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one {
@@ -1962,7 +1947,7 @@ QHeaderView::section::vertical:disabled {
QHeaderView::down-arrow {
/* Those settings (border/width/height/background-color) solve bug */
/* transparent arrow background and size */
- background-color: #32414B;
+ background-color: #19232D;
border: none;
height: 12px;
width: 12px;
@@ -1972,7 +1957,7 @@ QHeaderView::down-arrow {
}
QHeaderView::up-arrow {
- background-color: #32414B;
+ background-color: #19232D;
border: none;
height: 12px;
width: 12px;
@@ -2172,3 +2157,348 @@ PlotWidget {
/* Fix cut labels in plots #134 */
padding: 0px;
}
+
+
+QPushButton#TogglableStatusBarButton {
+ min-width: 0px;
+ color: #656565;
+ border: 1px solid transparent;
+ background-color: transparent;
+ padding: 0px 3px 0px 3px;
+ text-align: center;
+}
+
+QPushButton#TogglableStatusBarButton:checked {
+ color: #ffffff;
+}
+
+QPushButton#TogglableStatusBarButton:hover {
+ border: 1px solid #76797C;
+}
+
+QPushButton#RendererStatusBarButton {
+ min-width: 0px;
+ color: #656565;
+ border: 1px solid transparent;
+ background-color: transparent;
+ padding: 0px 3px 0px 3px;
+ text-align: center;
+}
+
+QPushButton#RendererStatusBarButton:hover {
+ border: 1px solid #76797C;
+}
+
+QPushButton#RendererStatusBarButton:checked {
+ color: #e85c00;
+}
+
+QPushButton#RendererStatusBarButton:!checked {
+ color: #00ccdd;
+}
+
+QPushButton#buttonRefreshDevices {
+ min-width: 20px;
+ min-height: 20px;
+ max-width: 20px;
+ max-height: 20px;
+ padding: 0px 0px;
+}
+
+QSpinBox#spinboxLStickRange,
+QSpinBox#spinboxRStickRange {
+ min-width: 38px;
+}
+
+QGroupBox#motionGroup::indicator,
+QGroupBox#vibrationGroup::indicator {
+ margin-left: 0px;
+}
+
+QWidget#bottomPerGameInput QGroupBox#motionGroup,
+QWidget#bottomPerGameInput QGroupBox#vibrationGroup,
+QWidget#bottomPerGameInput QGroupBox#inputConfigGroup {
+ padding: 0px;
+}
+
+QGroupBox#motionGroup::title,
+QGroupBox#vibrationGroup::title {
+ spacing: 2px;
+ padding-left: 1px;
+ padding-right: 1px;
+}
+
+QListWidget#selectorList {
+ background-color: #0f1922;
+}
+
+QSpinBox,
+QLineEdit,
+QTreeView#hotkey_list,
+QScrollArea#scrollArea QTreeView {
+ background-color: #0f1922;
+}
+
+QWidget#bottomPerGameInput,
+QWidget#topControllerApplet,
+QWidget#bottomControllerApplet,
+QGroupBox#groupPlayer1Connected:checked,
+QGroupBox#groupPlayer2Connected:checked,
+QGroupBox#groupPlayer3Connected:checked,
+QGroupBox#groupPlayer4Connected:checked,
+QGroupBox#groupPlayer5Connected:checked,
+QGroupBox#groupPlayer6Connected:checked,
+QGroupBox#groupPlayer7Connected:checked,
+QGroupBox#groupPlayer8Connected:checked {
+ background-color: #0f1922;
+}
+
+QWidget#topPerGameInput,
+QWidget#middleControllerApplet {
+ background-color: #19232d;
+}
+
+QWidget#topPerGameInput QComboBox,
+QWidget#middleControllerApplet QComboBox {
+ padding-right: 2px;
+ width: 127px;
+}
+
+QGroupBox#handheldGroup {
+ padding-left: 0px;
+}
+
+QRadioButton#radioDocked {
+ margin-left: -1px;
+ padding-left: 0px;
+}
+
+QRadioButton#radioDocked::indicator {
+ margin-left: 0px;
+}
+
+
+QRadioButton#radioUndocked {
+ margin-right: 2px;
+}
+
+QWidget#connectedControllers {
+ background: transparent;
+}
+
+QWidget#playersSupported,
+QWidget#controllersSupported,
+QWidget#controllerSupported1,
+QWidget#controllerSupported2,
+QWidget#controllerSupported3,
+QWidget#controllerSupported4,
+QWidget#controllerSupported5,
+QWidget#controllerSupported6 {
+ border: none;
+ background: transparent;
+}
+
+QGroupBox#groupPlayer1Connected,
+QGroupBox#groupPlayer2Connected,
+QGroupBox#groupPlayer3Connected,
+QGroupBox#groupPlayer4Connected,
+QGroupBox#groupPlayer5Connected,
+QGroupBox#groupPlayer6Connected,
+QGroupBox#groupPlayer7Connected,
+QGroupBox#groupPlayer8Connected {
+ border: 1px solid #76797c;
+ border-radius: 3px;
+ padding: 0px;
+ min-height: 98px;
+ max-height: 98px;
+ margin-top: 0px;
+}
+
+
+QGroupBox#groupPlayer1Connected:unchecked,
+QGroupBox#groupPlayer2Connected:unchecked,
+QGroupBox#groupPlayer3Connected:unchecked,
+QGroupBox#groupPlayer4Connected:unchecked,
+QGroupBox#groupPlayer5Connected:unchecked,
+QGroupBox#groupPlayer6Connected:unchecked,
+QGroupBox#groupPlayer7Connected:unchecked,
+QGroupBox#groupPlayer8Connected:unchecked {
+ border: 1px solid #32414b;
+}
+
+QGroupBox#groupPlayer1Connected::title,
+QGroupBox#groupPlayer2Connected::title,
+QGroupBox#groupPlayer3Connected::title,
+QGroupBox#groupPlayer4Connected::title,
+QGroupBox#groupPlayer5Connected::title,
+QGroupBox#groupPlayer6Connected::title,
+QGroupBox#groupPlayer7Connected::title,
+QGroupBox#groupPlayer8Connected::title {
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-top: 1px;
+ margin-left: -2px;
+ margin-right: -4px;
+ margin-bottom: 6px;
+}
+
+QCheckBox#checkboxPlayer1Connected,
+QCheckBox#checkboxPlayer2Connected,
+QCheckBox#checkboxPlayer3Connected,
+QCheckBox#checkboxPlayer4Connected,
+QCheckBox#checkboxPlayer5Connected,
+QCheckBox#checkboxPlayer6Connected,
+QCheckBox#checkboxPlayer7Connected,
+QCheckBox#checkboxPlayer8Connected {
+ spacing: 0px;
+}
+
+QWidget#connectedControllers QLabel {
+ padding: 0px;
+}
+
+QWidget#Player1LEDs,
+QWidget#Player2LEDs,
+QWidget#Player3LEDs,
+QWidget#Player4LEDs,
+QWidget#Player5LEDs,
+QWidget#Player6LEDs,
+QWidget#Player7LEDs,
+QWidget#Player8LEDs {
+ background: transparent;
+}
+
+QWidget#Player1LEDs QCheckBox,
+QWidget#Player2LEDs QCheckBox,
+QWidget#Player3LEDs QCheckBox,
+QWidget#Player4LEDs QCheckBox,
+QWidget#Player5LEDs QCheckBox,
+QWidget#Player6LEDs QCheckBox,
+QWidget#Player7LEDs QCheckBox,
+QWidget#Player8LEDs QCheckBox,
+QCheckBox#checkboxPlayer1Connected,
+QCheckBox#checkboxPlayer2Connected,
+QCheckBox#checkboxPlayer3Connected,
+QCheckBox#checkboxPlayer4Connected,
+QCheckBox#checkboxPlayer5Connected,
+QCheckBox#checkboxPlayer6Connected,
+QCheckBox#checkboxPlayer7Connected,
+QCheckBox#checkboxPlayer8Connected {
+ spacing: 0px;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ background: transparent;
+}
+
+QWidget#Player1LEDs QCheckBox::indicator,
+QWidget#Player2LEDs QCheckBox::indicator,
+QWidget#Player3LEDs QCheckBox::indicator,
+QWidget#Player4LEDs QCheckBox::indicator,
+QWidget#Player5LEDs QCheckBox::indicator,
+QWidget#Player6LEDs QCheckBox::indicator,
+QWidget#Player7LEDs QCheckBox::indicator,
+QWidget#Player8LEDs QCheckBox::indicator {
+ width: 6px;
+ height: 6px;
+ margin-left: 0px;
+}
+
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
+QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
+ width: 12px;
+ height: 12px;
+}
+
+QCheckBox#checkboxPlayer1Connected::indicator,
+QCheckBox#checkboxPlayer2Connected::indicator,
+QCheckBox#checkboxPlayer3Connected::indicator,
+QCheckBox#checkboxPlayer4Connected::indicator,
+QCheckBox#checkboxPlayer5Connected::indicator,
+QCheckBox#checkboxPlayer6Connected::indicator,
+QCheckBox#checkboxPlayer7Connected::indicator,
+QCheckBox#checkboxPlayer8Connected::indicator {
+ width: 14px;
+ height: 14px;
+ margin-left: 2px;
+}
+
+QWidget#Player1LEDs QCheckBox::indicator:checked,
+QWidget#Player2LEDs QCheckBox::indicator:checked,
+QWidget#Player3LEDs QCheckBox::indicator:checked,
+QWidget#Player4LEDs QCheckBox::indicator:checked,
+QWidget#Player5LEDs QCheckBox::indicator:checked,
+QWidget#Player6LEDs QCheckBox::indicator:checked,
+QWidget#Player7LEDs QCheckBox::indicator:checked,
+QWidget#Player8LEDs QCheckBox::indicator:checked,
+QGroupBox#groupPlayer1Connected::indicator:checked,
+QGroupBox#groupPlayer2Connected::indicator:checked,
+QGroupBox#groupPlayer3Connected::indicator:checked,
+QGroupBox#groupPlayer4Connected::indicator:checked,
+QGroupBox#groupPlayer5Connected::indicator:checked,
+QGroupBox#groupPlayer6Connected::indicator:checked,
+QGroupBox#groupPlayer7Connected::indicator:checked,
+QGroupBox#groupPlayer8Connected::indicator:checked,
+QCheckBox#checkboxPlayer1Connected::indicator:checked,
+QCheckBox#checkboxPlayer2Connected::indicator:checked,
+QCheckBox#checkboxPlayer3Connected::indicator:checked,
+QCheckBox#checkboxPlayer4Connected::indicator:checked,
+QCheckBox#checkboxPlayer5Connected::indicator:checked,
+QCheckBox#checkboxPlayer6Connected::indicator:checked,
+QCheckBox#checkboxPlayer7Connected::indicator:checked,
+QCheckBox#checkboxPlayer8Connected::indicator:checked,
+QGroupBox#groupConnectedController::indicator:checked {
+ border-radius: 2px;
+ border: 1px solid #929192;
+ background: #39ff14;
+ image: none;
+}
+
+QWidget#Player1LEDs QCheckBox::indicator:unchecked,
+QWidget#Player2LEDs QCheckBox::indicator:unchecked,
+QWidget#Player3LEDs QCheckBox::indicator:unchecked,
+QWidget#Player4LEDs QCheckBox::indicator:unchecked,
+QWidget#Player5LEDs QCheckBox::indicator:unchecked,
+QWidget#Player6LEDs QCheckBox::indicator:unchecked,
+QWidget#Player7LEDs QCheckBox::indicator:unchecked,
+QWidget#Player8LEDs QCheckBox::indicator:unchecked,
+QGroupBox#groupPlayer1Connected::indicator:unchecked,
+QGroupBox#groupPlayer2Connected::indicator:unchecked,
+QGroupBox#groupPlayer3Connected::indicator:unchecked,
+QGroupBox#groupPlayer4Connected::indicator:unchecked,
+QGroupBox#groupPlayer5Connected::indicator:unchecked,
+QGroupBox#groupPlayer6Connected::indicator:unchecked,
+QGroupBox#groupPlayer7Connected::indicator:unchecked,
+QGroupBox#groupPlayer8Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer4Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer5Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
+QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
+QGroupBox#groupConnectedController::indicator:unchecked {
+ border-radius: 2px;
+ border: 1px solid #929192;
+ background: #19232d;
+ image: none;
+}
+
+QWidget#controllerPlayer1,
+QWidget#controllerPlayer2,
+QWidget#controllerPlayer3,
+QWidget#controllerPlayer4,
+QWidget#controllerPlayer5,
+QWidget#controllerPlayer6,
+QWidget#controllerPlayer7,
+QWidget#controllerPlayer8 {
+ background: transparent;
+}
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index d1dcc403b..e01ff6930 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -90,6 +90,9 @@ if (ENABLE_WEB_SERVICE)
target_include_directories(httplib INTERFACE ./httplib)
target_compile_definitions(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
+ if (WIN32)
+ target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32)
+ endif()
endif()
# Opus
diff --git a/externals/dynarmic b/externals/dynarmic
-Subproject 82417da7803e2cf18efc28a1cd3f3d0a4b6045a
+Subproject 0e1112b7df77ae55a62a51622940d5c8f9e8c84
diff --git a/externals/httplib/httplib.h b/externals/httplib/httplib.h
index e03842e6d..5139b7f05 100644
--- a/externals/httplib/httplib.h
+++ b/externals/httplib/httplib.h
@@ -16,14 +16,18 @@
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
#endif
-#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND
-#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND 0
-#endif
-
#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5
#endif
+#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
+#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 300
+#endif
+
+#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND
+#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0
+#endif
+
#ifndef CPPHTTPLIB_READ_TIMEOUT_SECOND
#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5
#endif
@@ -32,6 +36,26 @@
#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0
#endif
+#ifndef CPPHTTPLIB_WRITE_TIMEOUT_SECOND
+#define CPPHTTPLIB_WRITE_TIMEOUT_SECOND 5
+#endif
+
+#ifndef CPPHTTPLIB_WRITE_TIMEOUT_USECOND
+#define CPPHTTPLIB_WRITE_TIMEOUT_USECOND 0
+#endif
+
+#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND
+#define CPPHTTPLIB_IDLE_INTERVAL_SECOND 0
+#endif
+
+#ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND
+#ifdef _WIN32
+#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 10000
+#else
+#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0
+#endif
+#endif
+
#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
#endif
@@ -41,16 +65,26 @@
#endif
#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH
-#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH (std::numeric_limits<size_t>::max())
+#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH ((std::numeric_limits<size_t>::max)())
+#endif
+
+#ifndef CPPHTTPLIB_TCP_NODELAY
+#define CPPHTTPLIB_TCP_NODELAY false
#endif
#ifndef CPPHTTPLIB_RECV_BUFSIZ
#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u)
#endif
+#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
+#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)
+#endif
+
#ifndef CPPHTTPLIB_THREAD_POOL_COUNT
#define CPPHTTPLIB_THREAD_POOL_COUNT \
- (std::max(1u, std::thread::hardware_concurrency() - 1))
+ ((std::max)(8u, std::thread::hardware_concurrency() > 0 \
+ ? std::thread::hardware_concurrency() - 1 \
+ : 0))
#endif
/*
@@ -92,6 +126,8 @@ using ssize_t = int;
#include <io.h>
#include <winsock2.h>
+
+#include <wincrypt.h>
#include <ws2tcpip.h>
#ifndef WSA_FLAG_NO_HANDLE_INHERIT
@@ -100,6 +136,8 @@ using ssize_t = int;
#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib")
+#pragma comment(lib, "crypt32.lib")
+#pragma comment(lib, "cryptui.lib")
#endif
#ifndef strcasecmp
@@ -118,6 +156,10 @@ using socket_t = SOCKET;
#include <ifaddrs.h>
#include <netdb.h>
#include <netinet/in.h>
+#ifdef __linux__
+#include <resolv.h>
+#endif
+#include <netinet/tcp.h>
#ifdef CPPHTTPLIB_USE_POLL
#include <poll.h>
#endif
@@ -134,17 +176,21 @@ using socket_t = int;
#include <array>
#include <atomic>
#include <cassert>
+#include <cctype>
+#include <climits>
#include <condition_variable>
#include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <functional>
+#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <random>
#include <regex>
+#include <sstream>
#include <string>
#include <sys/stat.h>
#include <thread>
@@ -155,12 +201,17 @@ using socket_t = int;
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
+#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK)
+#include <openssl/applink.c>
+#endif
+
#include <iomanip>
+#include <iostream>
#include <sstream>
-// #if OPENSSL_VERSION_NUMBER < 0x1010100fL
-// #error Sorry, OpenSSL versions prior to 1.1.1 are not supported
-// #endif
+#if OPENSSL_VERSION_NUMBER < 0x1010100fL
+#error Sorry, OpenSSL versions prior to 1.1.1 are not supported
+#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#include <openssl/crypto.h>
@@ -174,6 +225,11 @@ inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) {
#include <zlib.h>
#endif
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+#include <brotli/decode.h>
+#include <brotli/encode.h>
+#endif
+
/*
* Declaration
*/
@@ -212,7 +268,8 @@ using MultipartFormDataMap = std::multimap<std::string, MultipartFormData>;
class DataSink {
public:
- DataSink() = default;
+ DataSink() : os(&sb_), sb_(*this) {}
+
DataSink(const DataSink &) = delete;
DataSink &operator=(const DataSink &) = delete;
DataSink(DataSink &&) = delete;
@@ -221,10 +278,31 @@ public:
std::function<void(const char *data, size_t data_len)> write;
std::function<void()> done;
std::function<bool()> is_writable;
+ std::ostream os;
+
+private:
+ class data_sink_streambuf : public std::streambuf {
+ public:
+ explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {}
+
+ protected:
+ std::streamsize xsputn(const char *s, std::streamsize n) {
+ sink_.write(s, static_cast<size_t>(n));
+ return n;
+ }
+
+ private:
+ DataSink &sink_;
+ };
+
+ data_sink_streambuf sb_;
};
using ContentProvider =
- std::function<void(size_t offset, size_t length, DataSink &sink)>;
+ std::function<bool(size_t offset, size_t length, DataSink &sink)>;
+
+using ContentProviderWithoutLength =
+ std::function<bool(size_t offset, DataSink &sink)>;
using ContentReceiver =
std::function<bool(const char *data, size_t data_length)>;
@@ -238,18 +316,18 @@ public:
using MultipartReader = std::function<bool(MultipartContentHeader header,
ContentReceiver receiver)>;
- ContentReader(Reader reader, MultipartReader muitlpart_reader)
- : reader_(reader), muitlpart_reader_(muitlpart_reader) {}
+ ContentReader(Reader reader, MultipartReader multipart_reader)
+ : reader_(reader), multipart_reader_(multipart_reader) {}
bool operator()(MultipartContentHeader header,
ContentReceiver receiver) const {
- return muitlpart_reader_(header, receiver);
+ return multipart_reader_(header, receiver);
}
bool operator()(ContentReceiver receiver) const { return reader_(receiver); }
Reader reader_;
- MultipartReader muitlpart_reader_;
+ MultipartReader multipart_reader_;
};
using Range = std::pair<ssize_t, ssize_t>;
@@ -261,6 +339,9 @@ struct Request {
Headers headers;
std::string body;
+ std::string remote_addr;
+ int remote_port = -1;
+
// for server
std::string version;
std::string target;
@@ -273,6 +354,8 @@ struct Request {
size_t redirect_count = CPPHTTPLIB_REDIRECT_MAX_COUNT;
ResponseHandler response_handler;
ContentReceiver content_receiver;
+ size_t content_length = 0;
+ ContentProvider content_provider;
Progress progress;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
@@ -281,6 +364,8 @@ struct Request {
bool has_header(const char *key) const;
std::string get_header_value(const char *key, size_t id = 0) const;
+ template <typename T>
+ T get_header_value(const char *key, size_t id = 0) const;
size_t get_header_value_count(const char *key) const;
void set_header(const char *key, const char *val);
void set_header(const char *key, const std::string &val);
@@ -295,35 +380,40 @@ struct Request {
MultipartFormData get_file_value(const char *key) const;
// private members...
- size_t content_length;
- ContentProvider content_provider;
+ size_t authorization_count_ = 0;
};
struct Response {
std::string version;
int status = -1;
+ std::string reason;
Headers headers;
std::string body;
bool has_header(const char *key) const;
std::string get_header_value(const char *key, size_t id = 0) const;
+ template <typename T>
+ T get_header_value(const char *key, size_t id = 0) const;
size_t get_header_value_count(const char *key) const;
void set_header(const char *key, const char *val);
void set_header(const char *key, const std::string &val);
- void set_redirect(const char *url);
+ void set_redirect(const char *url, int status = 302);
+ void set_redirect(const std::string &url, int status = 302);
void set_content(const char *s, size_t n, const char *content_type);
- void set_content(const std::string &s, const char *content_type);
+ void set_content(std::string s, const char *content_type);
+
+ void set_content_provider(
+ size_t length, const char *content_type, ContentProvider provider,
+ const std::function<void()> &resource_releaser = nullptr);
void set_content_provider(
- size_t length,
- std::function<void(size_t offset, size_t length, DataSink &sink)>
- provider,
- std::function<void()> resource_releaser = [] {});
+ const char *content_type, ContentProviderWithoutLength provider,
+ const std::function<void()> &resource_releaser = nullptr);
void set_chunked_content_provider(
- std::function<void(size_t offset, DataSink &sink)> provider,
- std::function<void()> resource_releaser = [] {});
+ const char *content_type, ContentProviderWithoutLength provider,
+ const std::function<void()> &resource_releaser = nullptr);
Response() = default;
Response(const Response &) = default;
@@ -331,15 +421,16 @@ struct Response {
Response(Response &&) = default;
Response &operator=(Response &&) = default;
~Response() {
- if (content_provider_resource_releaser) {
- content_provider_resource_releaser();
+ if (content_provider_resource_releaser_) {
+ content_provider_resource_releaser_();
}
}
// private members...
- size_t content_length = 0;
- ContentProvider content_provider;
- std::function<void()> content_provider_resource_releaser;
+ size_t content_length_ = 0;
+ ContentProvider content_provider_;
+ std::function<void()> content_provider_resource_releaser_;
+ bool is_chunked_content_provider = false;
};
class Stream {
@@ -349,22 +440,25 @@ public:
virtual bool is_readable() const = 0;
virtual bool is_writable() const = 0;
- virtual int read(char *ptr, size_t size) = 0;
- virtual int write(const char *ptr, size_t size) = 0;
- virtual std::string get_remote_addr() const = 0;
+ virtual ssize_t read(char *ptr, size_t size) = 0;
+ virtual ssize_t write(const char *ptr, size_t size) = 0;
+ virtual void get_remote_ip_and_port(std::string &ip, int &port) const = 0;
template <typename... Args>
- int write_format(const char *fmt, const Args &... args);
- int write(const char *ptr);
- int write(const std::string &s);
+ ssize_t write_format(const char *fmt, const Args &... args);
+ ssize_t write(const char *ptr);
+ ssize_t write(const std::string &s);
};
class TaskQueue {
public:
TaskQueue() = default;
virtual ~TaskQueue() = default;
+
virtual void enqueue(std::function<void()> fn) = 0;
virtual void shutdown() = 0;
+
+ virtual void on_idle(){};
};
class ThreadPool : public TaskQueue {
@@ -439,6 +533,26 @@ private:
using Logger = std::function<void(const Request &, const Response &)>;
+using SocketOptions = std::function<void(socket_t sock)>;
+
+inline void default_socket_options(socket_t sock) {
+ int yes = 1;
+#ifdef _WIN32
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&yes),
+ sizeof(yes));
+ setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
+ reinterpret_cast<char *>(&yes), sizeof(yes));
+#else
+#ifdef SO_REUSEPORT
+ setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, reinterpret_cast<void *>(&yes),
+ sizeof(yes));
+#else
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<void *>(&yes),
+ sizeof(yes));
+#endif
+#endif
+}
+
class Server {
public:
using Handler = std::function<void(const Request &, Response &)>;
@@ -461,23 +575,30 @@ public:
Server &Patch(const char *pattern, Handler handler);
Server &Patch(const char *pattern, HandlerWithContentReader handler);
Server &Delete(const char *pattern, Handler handler);
+ Server &Delete(const char *pattern, HandlerWithContentReader handler);
Server &Options(const char *pattern, Handler handler);
- [[deprecated]] bool set_base_dir(const char *dir,
- const char *mount_point = nullptr);
- bool set_mount_point(const char *mount_point, const char *dir);
+ bool set_base_dir(const char *dir, const char *mount_point = nullptr);
+ bool set_mount_point(const char *mount_point, const char *dir,
+ Headers headers = Headers());
bool remove_mount_point(const char *mount_point);
void set_file_extension_and_mimetype_mapping(const char *ext,
const char *mime);
void set_file_request_handler(Handler handler);
void set_error_handler(Handler handler);
+ void set_expect_100_continue_handler(Expect100ContinueHandler handler);
void set_logger(Logger logger);
- void set_expect_100_continue_handler(Expect100ContinueHandler handler);
+ void set_tcp_nodelay(bool on);
+ void set_socket_options(SocketOptions socket_options);
void set_keep_alive_max_count(size_t count);
- void set_read_timeout(time_t sec, time_t usec);
+ void set_keep_alive_timeout(time_t sec);
+ void set_read_timeout(time_t sec, time_t usec = 0);
+ void set_write_timeout(time_t sec, time_t usec = 0);
+ void set_idle_interval(time_t sec, time_t usec = 0);
+
void set_payload_max_length(size_t length);
bool bind_to_port(const char *host, int port, int socket_flags = 0);
@@ -492,54 +613,66 @@ public:
std::function<TaskQueue *(void)> new_task_queue;
protected:
- bool process_request(Stream &strm, bool last_connection,
- bool &connection_close,
+ bool process_request(Stream &strm, bool close_connection,
+ bool &connection_closed,
const std::function<void(Request &)> &setup_request);
- size_t keep_alive_max_count_;
- time_t read_timeout_sec_;
- time_t read_timeout_usec_;
- size_t payload_max_length_;
+ std::atomic<socket_t> svr_sock_;
+ size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT;
+ time_t keep_alive_timeout_sec_ = CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND;
+ time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND;
+ time_t read_timeout_usec_ = CPPHTTPLIB_READ_TIMEOUT_USECOND;
+ time_t write_timeout_sec_ = CPPHTTPLIB_WRITE_TIMEOUT_SECOND;
+ time_t write_timeout_usec_ = CPPHTTPLIB_WRITE_TIMEOUT_USECOND;
+ time_t idle_interval_sec_ = CPPHTTPLIB_IDLE_INTERVAL_SECOND;
+ time_t idle_interval_usec_ = CPPHTTPLIB_IDLE_INTERVAL_USECOND;
+ size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;
private:
using Handlers = std::vector<std::pair<std::regex, Handler>>;
using HandlersForContentReader =
std::vector<std::pair<std::regex, HandlerWithContentReader>>;
- socket_t create_server_socket(const char *host, int port,
- int socket_flags) const;
+ socket_t create_server_socket(const char *host, int port, int socket_flags,
+ SocketOptions socket_options) const;
int bind_internal(const char *host, int port, int socket_flags);
bool listen_internal();
- bool routing(Request &req, Response &res, Stream &strm, bool last_connection);
+ bool routing(Request &req, Response &res, Stream &strm);
bool handle_file_request(Request &req, Response &res, bool head = false);
- bool dispatch_request(Request &req, Response &res, Handlers &handlers);
- bool dispatch_request_for_content_reader(Request &req, Response &res,
- ContentReader content_reader,
- HandlersForContentReader &handlers);
+ bool dispatch_request(Request &req, Response &res, const Handlers &handlers);
+ bool
+ dispatch_request_for_content_reader(Request &req, Response &res,
+ ContentReader content_reader,
+ const HandlersForContentReader &handlers);
bool parse_request_line(const char *s, Request &req);
- bool write_response(Stream &strm, bool last_connection, const Request &req,
+ bool write_response(Stream &strm, bool close_connection, const Request &req,
Response &res);
bool write_content_with_provider(Stream &strm, const Request &req,
Response &res, const std::string &boundary,
const std::string &content_type);
- bool read_content(Stream &strm, bool last_connection, Request &req,
- Response &res);
- bool read_content_with_content_receiver(
- Stream &strm, bool last_connection, Request &req, Response &res,
- ContentReceiver receiver, MultipartContentHeader multipart_header,
- ContentReceiver multipart_receiver);
- bool read_content_core(Stream &strm, bool last_connection, Request &req,
- Response &res, ContentReceiver receiver,
+ bool read_content(Stream &strm, Request &req, Response &res);
+ bool
+ read_content_with_content_receiver(Stream &strm, Request &req, Response &res,
+ ContentReceiver receiver,
+ MultipartContentHeader multipart_header,
+ ContentReceiver multipart_receiver);
+ bool read_content_core(Stream &strm, Request &req, Response &res,
+ ContentReceiver receiver,
MultipartContentHeader mulitpart_header,
ContentReceiver multipart_receiver);
virtual bool process_and_close_socket(socket_t sock);
+
+ struct MountPointEntry {
+ std::string mount_point;
+ std::string base_dir;
+ Headers headers;
+ };
+ std::vector<MountPointEntry> base_dirs_;
std::atomic<bool> is_running_;
- std::atomic<socket_t> svr_sock_;
- std::vector<std::pair<std::string, std::string>> base_dirs_;
std::map<std::string, std::string> file_extension_and_mimetype_map_;
Handler file_request_handler_;
Handlers get_handlers_;
@@ -550,293 +683,427 @@ private:
Handlers patch_handlers_;
HandlersForContentReader patch_handlers_for_content_reader_;
Handlers delete_handlers_;
+ HandlersForContentReader delete_handlers_for_content_reader_;
Handlers options_handlers_;
Handler error_handler_;
Logger logger_;
Expect100ContinueHandler expect_100_continue_handler_;
-};
-
-class Client {
-public:
- explicit Client(const std::string &host, int port = 80,
- const std::string &client_cert_path = std::string(),
- const std::string &client_key_path = std::string());
-
- virtual ~Client();
-
- virtual bool is_valid() const;
-
- std::shared_ptr<Response> Get(const char *path);
-
- std::shared_ptr<Response> Get(const char *path, const Headers &headers);
-
- std::shared_ptr<Response> Get(const char *path, Progress progress);
-
- std::shared_ptr<Response> Get(const char *path, const Headers &headers,
- Progress progress);
-
- std::shared_ptr<Response> Get(const char *path,
- ContentReceiver content_receiver);
-
- std::shared_ptr<Response> Get(const char *path, const Headers &headers,
- ContentReceiver content_receiver);
-
- std::shared_ptr<Response>
- Get(const char *path, ContentReceiver content_receiver, Progress progress);
-
- std::shared_ptr<Response> Get(const char *path, const Headers &headers,
- ContentReceiver content_receiver,
- Progress progress);
- std::shared_ptr<Response> Get(const char *path, const Headers &headers,
- ResponseHandler response_handler,
- ContentReceiver content_receiver);
-
- std::shared_ptr<Response> Get(const char *path, const Headers &headers,
- ResponseHandler response_handler,
- ContentReceiver content_receiver,
- Progress progress);
-
- std::shared_ptr<Response> Head(const char *path);
-
- std::shared_ptr<Response> Head(const char *path, const Headers &headers);
-
- std::shared_ptr<Response> Post(const char *path, const std::string &body,
- const char *content_type);
-
- std::shared_ptr<Response> Post(const char *path, const Headers &headers,
- const std::string &body,
- const char *content_type);
-
- std::shared_ptr<Response> Post(const char *path, size_t content_length,
- ContentProvider content_provider,
- const char *content_type);
-
- std::shared_ptr<Response> Post(const char *path, const Headers &headers,
- size_t content_length,
- ContentProvider content_provider,
- const char *content_type);
-
- std::shared_ptr<Response> Post(const char *path, const Params &params);
-
- std::shared_ptr<Response> Post(const char *path, const Headers &headers,
- const Params &params);
-
- std::shared_ptr<Response> Post(const char *path,
- const MultipartFormDataItems &items);
-
- std::shared_ptr<Response> Post(const char *path, const Headers &headers,
- const MultipartFormDataItems &items);
-
- std::shared_ptr<Response> Put(const char *path, const std::string &body,
- const char *content_type);
-
- std::shared_ptr<Response> Put(const char *path, const Headers &headers,
- const std::string &body,
- const char *content_type);
-
- std::shared_ptr<Response> Put(const char *path, size_t content_length,
- ContentProvider content_provider,
- const char *content_type);
-
- std::shared_ptr<Response> Put(const char *path, const Headers &headers,
- size_t content_length,
- ContentProvider content_provider,
- const char *content_type);
-
- std::shared_ptr<Response> Put(const char *path, const Params &params);
-
- std::shared_ptr<Response> Put(const char *path, const Headers &headers,
- const Params &params);
-
- std::shared_ptr<Response> Patch(const char *path, const std::string &body,
- const char *content_type);
+ bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
+ SocketOptions socket_options_ = default_socket_options;
+};
- std::shared_ptr<Response> Patch(const char *path, const Headers &headers,
- const std::string &body,
- const char *content_type);
+enum Error {
+ Success = 0,
+ Unknown,
+ Connection,
+ BindIPAddress,
+ Read,
+ Write,
+ ExceedRedirectCount,
+ Canceled,
+ SSLConnection,
+ SSLLoadingCerts,
+ SSLServerVerification
+};
- std::shared_ptr<Response> Patch(const char *path, size_t content_length,
- ContentProvider content_provider,
- const char *content_type);
+class Result {
+public:
+ Result(const std::shared_ptr<Response> &res, Error err)
+ : res_(res), err_(err) {}
+ operator bool() const { return res_ != nullptr; }
+ bool operator==(std::nullptr_t) const { return res_ == nullptr; }
+ bool operator!=(std::nullptr_t) const { return res_ != nullptr; }
+ const Response &value() const { return *res_; }
+ const Response &operator*() const { return *res_; }
+ const Response *operator->() const { return res_.get(); }
+ Error error() const { return err_; }
- std::shared_ptr<Response> Patch(const char *path, const Headers &headers,
- size_t content_length,
- ContentProvider content_provider,
- const char *content_type);
+private:
+ std::shared_ptr<Response> res_;
+ Error err_;
+};
- std::shared_ptr<Response> Delete(const char *path);
+class ClientImpl {
+public:
+ explicit ClientImpl(const std::string &host);
- std::shared_ptr<Response> Delete(const char *path, const std::string &body,
- const char *content_type);
+ explicit ClientImpl(const std::string &host, int port);
- std::shared_ptr<Response> Delete(const char *path, const Headers &headers);
+ explicit ClientImpl(const std::string &host, int port,
+ const std::string &client_cert_path,
+ const std::string &client_key_path);
- std::shared_ptr<Response> Delete(const char *path, const Headers &headers,
- const std::string &body,
- const char *content_type);
+ virtual ~ClientImpl();
- std::shared_ptr<Response> Options(const char *path);
+ virtual bool is_valid() const;
- std::shared_ptr<Response> Options(const char *path, const Headers &headers);
+ Result Get(const char *path);
+ Result Get(const char *path, const Headers &headers);
+ Result Get(const char *path, Progress progress);
+ Result Get(const char *path, const Headers &headers, Progress progress);
+ Result Get(const char *path, ContentReceiver content_receiver);
+ Result Get(const char *path, const Headers &headers,
+ ContentReceiver content_receiver);
+ Result Get(const char *path, ContentReceiver content_receiver,
+ Progress progress);
+ Result Get(const char *path, const Headers &headers,
+ ContentReceiver content_receiver, Progress progress);
+ Result Get(const char *path, ResponseHandler response_handler,
+ ContentReceiver content_receiver);
+ Result Get(const char *path, const Headers &headers,
+ ResponseHandler response_handler,
+ ContentReceiver content_receiver);
+ Result Get(const char *path, ResponseHandler response_handler,
+ ContentReceiver content_receiver, Progress progress);
+ Result Get(const char *path, const Headers &headers,
+ ResponseHandler response_handler, ContentReceiver content_receiver,
+ Progress progress);
+
+ Result Head(const char *path);
+ Result Head(const char *path, const Headers &headers);
+
+ Result Post(const char *path);
+ Result Post(const char *path, const std::string &body,
+ const char *content_type);
+ Result Post(const char *path, const Headers &headers, const std::string &body,
+ const char *content_type);
+ Result Post(const char *path, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Post(const char *path, const Headers &headers, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Post(const char *path, const Params &params);
+ Result Post(const char *path, const Headers &headers, const Params &params);
+ Result Post(const char *path, const MultipartFormDataItems &items);
+ Result Post(const char *path, const Headers &headers,
+ const MultipartFormDataItems &items);
+
+ Result Put(const char *path);
+ Result Put(const char *path, const std::string &body,
+ const char *content_type);
+ Result Put(const char *path, const Headers &headers, const std::string &body,
+ const char *content_type);
+ Result Put(const char *path, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Put(const char *path, const Headers &headers, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Put(const char *path, const Params &params);
+ Result Put(const char *path, const Headers &headers, const Params &params);
+
+ Result Patch(const char *path, const std::string &body,
+ const char *content_type);
+ Result Patch(const char *path, const Headers &headers,
+ const std::string &body, const char *content_type);
+ Result Patch(const char *path, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Patch(const char *path, const Headers &headers, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+
+ Result Delete(const char *path);
+ Result Delete(const char *path, const std::string &body,
+ const char *content_type);
+ Result Delete(const char *path, const Headers &headers);
+ Result Delete(const char *path, const Headers &headers,
+ const std::string &body, const char *content_type);
+
+ Result Options(const char *path);
+ Result Options(const char *path, const Headers &headers);
bool send(const Request &req, Response &res);
- bool send(const std::vector<Request> &requests,
- std::vector<Response> &responses);
+ size_t is_socket_open() const;
- void set_timeout_sec(time_t timeout_sec);
+ void stop();
- void set_read_timeout(time_t sec, time_t usec);
+ void set_default_headers(Headers headers);
- void set_keep_alive_max_count(size_t count);
+ void set_tcp_nodelay(bool on);
+ void set_socket_options(SocketOptions socket_options);
- void set_basic_auth(const char *username, const char *password);
+ void set_connection_timeout(time_t sec, time_t usec = 0);
+ void set_read_timeout(time_t sec, time_t usec = 0);
+ void set_write_timeout(time_t sec, time_t usec = 0);
+ void set_basic_auth(const char *username, const char *password);
+ void set_bearer_token_auth(const char *token);
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
void set_digest_auth(const char *username, const char *password);
#endif
+ void set_keep_alive(bool on);
void set_follow_location(bool on);
void set_compress(bool on);
+ void set_decompress(bool on);
+
void set_interface(const char *intf);
void set_proxy(const char *host, int port);
-
void set_proxy_basic_auth(const char *username, const char *password);
-
+ void set_proxy_bearer_token_auth(const char *token);
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
void set_proxy_digest_auth(const char *username, const char *password);
#endif
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ void enable_server_certificate_verification(bool enabled);
+#endif
+
void set_logger(Logger logger);
protected:
+ struct Socket {
+ socket_t sock = INVALID_SOCKET;
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ SSL *ssl = nullptr;
+#endif
+
+ bool is_open() const { return sock != INVALID_SOCKET; }
+ };
+
+ virtual bool create_and_connect_socket(Socket &socket);
+ virtual void close_socket(Socket &socket, bool process_socket_ret);
+
bool process_request(Stream &strm, const Request &req, Response &res,
- bool last_connection, bool &connection_close);
+ bool close_connection);
+ Error get_last_error() const;
+
+ void copy_settings(const ClientImpl &rhs);
+
+ // Error state
+ mutable Error error_ = Error::Success;
+
+ // Socket endoint information
const std::string host_;
const int port_;
const std::string host_and_port_;
+ // Current open socket
+ Socket socket_;
+ mutable std::mutex socket_mutex_;
+ std::recursive_mutex request_mutex_;
+
+ // Default headers
+ Headers default_headers_;
+
// Settings
std::string client_cert_path_;
std::string client_key_path_;
- time_t timeout_sec_ = 300;
+ time_t connection_timeout_sec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND;
+ time_t connection_timeout_usec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND;
time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND;
time_t read_timeout_usec_ = CPPHTTPLIB_READ_TIMEOUT_USECOND;
-
- size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT;
+ time_t write_timeout_sec_ = CPPHTTPLIB_WRITE_TIMEOUT_SECOND;
+ time_t write_timeout_usec_ = CPPHTTPLIB_WRITE_TIMEOUT_USECOND;
std::string basic_auth_username_;
std::string basic_auth_password_;
+ std::string bearer_token_auth_token_;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
std::string digest_auth_username_;
std::string digest_auth_password_;
#endif
+ bool keep_alive_ = false;
bool follow_location_ = false;
+ bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
+ SocketOptions socket_options_ = nullptr;
+
bool compress_ = false;
+ bool decompress_ = true;
std::string interface_;
std::string proxy_host_;
- int proxy_port_;
+ int proxy_port_ = -1;
std::string proxy_basic_auth_username_;
std::string proxy_basic_auth_password_;
+ std::string proxy_bearer_token_auth_token_;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
std::string proxy_digest_auth_username_;
std::string proxy_digest_auth_password_;
#endif
- Logger logger_;
-
- void copy_settings(const Client &rhs) {
- client_cert_path_ = rhs.client_cert_path_;
- client_key_path_ = rhs.client_key_path_;
- timeout_sec_ = rhs.timeout_sec_;
- read_timeout_sec_ = rhs.read_timeout_sec_;
- read_timeout_usec_ = rhs.read_timeout_usec_;
- keep_alive_max_count_ = rhs.keep_alive_max_count_;
- basic_auth_username_ = rhs.basic_auth_username_;
- basic_auth_password_ = rhs.basic_auth_password_;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
- digest_auth_username_ = rhs.digest_auth_username_;
- digest_auth_password_ = rhs.digest_auth_password_;
+ bool server_certificate_verification_ = true;
#endif
- follow_location_ = rhs.follow_location_;
- compress_ = rhs.compress_;
- interface_ = rhs.interface_;
- proxy_host_ = rhs.proxy_host_;
- proxy_port_ = rhs.proxy_port_;
- proxy_basic_auth_username_ = rhs.proxy_basic_auth_username_;
- proxy_basic_auth_password_ = rhs.proxy_basic_auth_password_;
-#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
- proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
- proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
-#endif
- logger_ = rhs.logger_;
- }
+
+ Logger logger_;
private:
socket_t create_client_socket() const;
bool read_response_line(Stream &strm, Response &res);
- bool write_request(Stream &strm, const Request &req, bool last_connection);
+ bool write_request(Stream &strm, const Request &req, bool close_connection);
bool redirect(const Request &req, Response &res);
bool handle_request(Stream &strm, const Request &req, Response &res,
- bool last_connection, bool &connection_close);
-#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
- bool connect(socket_t sock, Response &res, bool &error);
-#endif
-
+ bool close_connection);
+ void stop_core();
std::shared_ptr<Response> send_with_content_provider(
const char *method, const char *path, const Headers &headers,
const std::string &body, size_t content_length,
ContentProvider content_provider, const char *content_type);
- virtual bool process_and_close_socket(
- socket_t sock, size_t request_count,
- std::function<bool(Stream &strm, bool last_connection,
- bool &connection_close)>
- callback);
-
+ virtual bool process_socket(Socket &socket,
+ std::function<bool(Stream &strm)> callback);
virtual bool is_ssl() const;
};
-inline void Get(std::vector<Request> &requests, const char *path,
- const Headers &headers) {
- Request req;
- req.method = "GET";
- req.path = path;
- req.headers = headers;
- requests.emplace_back(std::move(req));
-}
+class Client {
+public:
+ // Universal interface
+ explicit Client(const char *scheme_host_port);
+
+ explicit Client(const char *scheme_host_port,
+ const std::string &client_cert_path,
+ const std::string &client_key_path);
+
+ // HTTP only interface
+ explicit Client(const std::string &host, int port);
+
+ explicit Client(const std::string &host, int port,
+ const std::string &client_cert_path,
+ const std::string &client_key_path);
+
+ ~Client();
+
+ bool is_valid() const;
+
+ Result Get(const char *path);
+ Result Get(const char *path, const Headers &headers);
+ Result Get(const char *path, Progress progress);
+ Result Get(const char *path, const Headers &headers, Progress progress);
+ Result Get(const char *path, ContentReceiver content_receiver);
+ Result Get(const char *path, const Headers &headers,
+ ContentReceiver content_receiver);
+ Result Get(const char *path, ContentReceiver content_receiver,
+ Progress progress);
+ Result Get(const char *path, const Headers &headers,
+ ContentReceiver content_receiver, Progress progress);
+ Result Get(const char *path, ResponseHandler response_handler,
+ ContentReceiver content_receiver);
+ Result Get(const char *path, const Headers &headers,
+ ResponseHandler response_handler,
+ ContentReceiver content_receiver);
+ Result Get(const char *path, const Headers &headers,
+ ResponseHandler response_handler, ContentReceiver content_receiver,
+ Progress progress);
+ Result Get(const char *path, ResponseHandler response_handler,
+ ContentReceiver content_receiver, Progress progress);
+
+ Result Head(const char *path);
+ Result Head(const char *path, const Headers &headers);
+
+ Result Post(const char *path);
+ Result Post(const char *path, const std::string &body,
+ const char *content_type);
+ Result Post(const char *path, const Headers &headers, const std::string &body,
+ const char *content_type);
+ Result Post(const char *path, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Post(const char *path, const Headers &headers, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Post(const char *path, const Params &params);
+ Result Post(const char *path, const Headers &headers, const Params &params);
+ Result Post(const char *path, const MultipartFormDataItems &items);
+ Result Post(const char *path, const Headers &headers,
+ const MultipartFormDataItems &items);
+ Result Put(const char *path);
+ Result Put(const char *path, const std::string &body,
+ const char *content_type);
+ Result Put(const char *path, const Headers &headers, const std::string &body,
+ const char *content_type);
+ Result Put(const char *path, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Put(const char *path, const Headers &headers, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Put(const char *path, const Params &params);
+ Result Put(const char *path, const Headers &headers, const Params &params);
+ Result Patch(const char *path, const std::string &body,
+ const char *content_type);
+ Result Patch(const char *path, const Headers &headers,
+ const std::string &body, const char *content_type);
+ Result Patch(const char *path, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+ Result Patch(const char *path, const Headers &headers, size_t content_length,
+ ContentProvider content_provider, const char *content_type);
+
+ Result Delete(const char *path);
+ Result Delete(const char *path, const std::string &body,
+ const char *content_type);
+ Result Delete(const char *path, const Headers &headers);
+ Result Delete(const char *path, const Headers &headers,
+ const std::string &body, const char *content_type);
+
+ Result Options(const char *path);
+ Result Options(const char *path, const Headers &headers);
-inline void Get(std::vector<Request> &requests, const char *path) {
- Get(requests, path, Headers());
-}
+ bool send(const Request &req, Response &res);
-inline void Post(std::vector<Request> &requests, const char *path,
- const Headers &headers, const std::string &body,
- const char *content_type) {
- Request req;
- req.method = "POST";
- req.path = path;
- req.headers = headers;
- req.headers.emplace("Content-Type", content_type);
- req.body = body;
- requests.emplace_back(std::move(req));
-}
+ size_t is_socket_open() const;
-inline void Post(std::vector<Request> &requests, const char *path,
- const std::string &body, const char *content_type) {
- Post(requests, path, Headers(), body, content_type);
-}
+ void stop();
+
+ void set_default_headers(Headers headers);
+
+ void set_tcp_nodelay(bool on);
+ void set_socket_options(SocketOptions socket_options);
+
+ void set_connection_timeout(time_t sec, time_t usec = 0);
+ void set_read_timeout(time_t sec, time_t usec = 0);
+ void set_write_timeout(time_t sec, time_t usec = 0);
+
+ void set_basic_auth(const char *username, const char *password);
+ void set_bearer_token_auth(const char *token);
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ void set_digest_auth(const char *username, const char *password);
+#endif
+
+ void set_keep_alive(bool on);
+ void set_follow_location(bool on);
+
+ void set_compress(bool on);
+
+ void set_decompress(bool on);
+
+ void set_interface(const char *intf);
+
+ void set_proxy(const char *host, int port);
+ void set_proxy_basic_auth(const char *username, const char *password);
+ void set_proxy_bearer_token_auth(const char *token);
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ void set_proxy_digest_auth(const char *username, const char *password);
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ void enable_server_certificate_verification(bool enabled);
+#endif
+
+ void set_logger(Logger logger);
+
+ // SSL
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ void set_ca_cert_path(const char *ca_cert_file_path,
+ const char *ca_cert_dir_path = nullptr);
+
+ void set_ca_cert_store(X509_STORE *ca_cert_store);
+
+ long get_openssl_verify_result() const;
+
+ SSL_CTX *ssl_context() const;
+#endif
+
+private:
+ std::shared_ptr<ClientImpl> cli_;
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ bool is_ssl_ = false;
+#endif
+}; // namespace httplib
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
class SSLServer : public Server {
@@ -845,43 +1112,58 @@ public:
const char *client_ca_cert_file_path = nullptr,
const char *client_ca_cert_dir_path = nullptr);
- virtual ~SSLServer();
+ SSLServer(X509 *cert, EVP_PKEY *private_key,
+ X509_STORE *client_ca_cert_store = nullptr);
- virtual bool is_valid() const;
+ ~SSLServer() override;
+
+ bool is_valid() const override;
private:
- virtual bool process_and_close_socket(socket_t sock);
+ bool process_and_close_socket(socket_t sock) override;
SSL_CTX *ctx_;
std::mutex ctx_mutex_;
};
-class SSLClient : public Client {
+class SSLClient : public ClientImpl {
public:
- SSLClient(const std::string &host, int port = 443,
- const std::string &client_cert_path = std::string(),
- const std::string &client_key_path = std::string());
+ explicit SSLClient(const std::string &host);
- virtual ~SSLClient();
+ explicit SSLClient(const std::string &host, int port);
- virtual bool is_valid() const;
+ explicit SSLClient(const std::string &host, int port,
+ const std::string &client_cert_path,
+ const std::string &client_key_path);
+
+ explicit SSLClient(const std::string &host, int port, X509 *client_cert,
+ EVP_PKEY *client_key);
- void set_ca_cert_path(const char *ca_ceert_file_path,
+ ~SSLClient() override;
+
+ bool is_valid() const override;
+
+ void set_ca_cert_path(const char *ca_cert_file_path,
const char *ca_cert_dir_path = nullptr);
- void enable_server_certificate_verification(bool enabled);
+ void set_ca_cert_store(X509_STORE *ca_cert_store);
long get_openssl_verify_result() const;
- SSL_CTX *ssl_context() const noexcept;
+ SSL_CTX *ssl_context() const;
private:
- virtual bool process_and_close_socket(
- socket_t sock, size_t request_count,
- std::function<bool(Stream &strm, bool last_connection,
- bool &connection_close)>
- callback);
- virtual bool is_ssl() const;
+ bool create_and_connect_socket(Socket &socket) override;
+ void close_socket(Socket &socket, bool process_socket_ret) override;
+
+ bool process_socket(Socket &socket,
+ std::function<bool(Stream &strm)> callback) override;
+ bool is_ssl() const override;
+
+ bool connect_with_proxy(Socket &sock, Response &res, bool &success);
+ bool initialize_ssl(Socket &socket);
+
+ bool load_certs();
bool verify_host(X509 *server_cert) const;
bool verify_host_with_subject_alt_name(X509 *server_cert) const;
@@ -890,12 +1172,15 @@ private:
SSL_CTX *ctx_;
std::mutex ctx_mutex_;
+ std::once_flag initialize_cert_;
+
std::vector<std::string> host_components_;
std::string ca_cert_file_path_;
std::string ca_cert_dir_path_;
- bool server_certificate_verification_ = false;
long verify_result_ = 0;
+
+ friend class ClientImpl;
};
#endif
@@ -948,31 +1233,39 @@ inline std::string from_i_to_hex(size_t n) {
return ret;
}
+inline bool start_with(const std::string &a, const std::string &b) {
+ if (a.size() < b.size()) { return false; }
+ for (size_t i = 0; i < b.size(); i++) {
+ if (::tolower(a[i]) != ::tolower(b[i])) { return false; }
+ }
+ return true;
+}
+
inline size_t to_utf8(int code, char *buff) {
if (code < 0x0080) {
buff[0] = (code & 0x7F);
return 1;
} else if (code < 0x0800) {
- buff[0] = (0xC0 | ((code >> 6) & 0x1F));
- buff[1] = (0x80 | (code & 0x3F));
+ buff[0] = static_cast<char>(0xC0 | ((code >> 6) & 0x1F));
+ buff[1] = static_cast<char>(0x80 | (code & 0x3F));
return 2;
} else if (code < 0xD800) {
- buff[0] = (0xE0 | ((code >> 12) & 0xF));
- buff[1] = (0x80 | ((code >> 6) & 0x3F));
- buff[2] = (0x80 | (code & 0x3F));
+ buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
+ buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
+ buff[2] = static_cast<char>(0x80 | (code & 0x3F));
return 3;
} else if (code < 0xE000) { // D800 - DFFF is invalid...
return 0;
} else if (code < 0x10000) {
- buff[0] = (0xE0 | ((code >> 12) & 0xF));
- buff[1] = (0x80 | ((code >> 6) & 0x3F));
- buff[2] = (0x80 | (code & 0x3F));
+ buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
+ buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
+ buff[2] = static_cast<char>(0x80 | (code & 0x3F));
return 3;
} else if (code < 0x110000) {
- buff[0] = (0xF0 | ((code >> 18) & 0x7));
- buff[1] = (0x80 | ((code >> 12) & 0x3F));
- buff[2] = (0x80 | ((code >> 6) & 0x3F));
- buff[3] = (0x80 | (code & 0x3F));
+ buff[0] = static_cast<char>(0xF0 | ((code >> 18) & 0x7));
+ buff[1] = static_cast<char>(0x80 | ((code >> 12) & 0x3F));
+ buff[2] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
+ buff[3] = static_cast<char>(0x80 | (code & 0x3F));
return 4;
}
@@ -992,8 +1285,8 @@ inline std::string base64_encode(const std::string &in) {
int val = 0;
int valb = -6;
- for (uint8_t c : in) {
- val = (val << 8) + c;
+ for (auto c : in) {
+ val = (val << 8) + static_cast<uint8_t>(c);
valb += 8;
while (valb >= 0) {
out.push_back(lookup[(val >> valb) & 0x3F]);
@@ -1057,13 +1350,81 @@ inline bool is_valid_path(const std::string &path) {
return true;
}
+inline std::string encode_url(const std::string &s) {
+ std::string result;
+
+ for (size_t i = 0; s[i]; i++) {
+ switch (s[i]) {
+ case ' ': result += "%20"; break;
+ case '+': result += "%2B"; break;
+ case '\r': result += "%0D"; break;
+ case '\n': result += "%0A"; break;
+ case '\'': result += "%27"; break;
+ case ',': result += "%2C"; break;
+ // case ':': result += "%3A"; break; // ok? probably...
+ case ';': result += "%3B"; break;
+ default:
+ auto c = static_cast<uint8_t>(s[i]);
+ if (c >= 0x80) {
+ result += '%';
+ char hex[4];
+ auto len = snprintf(hex, sizeof(hex) - 1, "%02X", c);
+ assert(len == 2);
+ result.append(hex, static_cast<size_t>(len));
+ } else {
+ result += s[i];
+ }
+ break;
+ }
+ }
+
+ return result;
+}
+
+inline std::string decode_url(const std::string &s,
+ bool convert_plus_to_space) {
+ std::string result;
+
+ for (size_t i = 0; i < s.size(); i++) {
+ if (s[i] == '%' && i + 1 < s.size()) {
+ if (s[i + 1] == 'u') {
+ int val = 0;
+ if (from_hex_to_i(s, i + 2, 4, val)) {
+ // 4 digits Unicode codes
+ char buff[4];
+ size_t len = to_utf8(val, buff);
+ if (len > 0) { result.append(buff, len); }
+ i += 5; // 'u0000'
+ } else {
+ result += s[i];
+ }
+ } else {
+ int val = 0;
+ if (from_hex_to_i(s, i + 1, 2, val)) {
+ // 2 digits hex codes
+ result += static_cast<char>(val);
+ i += 2; // '00'
+ } else {
+ result += s[i];
+ }
+ }
+ } else if (convert_plus_to_space && s[i] == '+') {
+ result += ' ';
+ } else {
+ result += s[i];
+ }
+ }
+
+ return result;
+}
+
inline void read_file(const std::string &path, std::string &out) {
std::ifstream fs(path, std::ios_base::binary);
fs.seekg(0, std::ios_base::end);
auto size = fs.tellg();
fs.seekg(0);
out.resize(static_cast<size_t>(size));
- fs.read(&out[0], size);
+ fs.read(&out[0], static_cast<std::streamsize>(size));
}
inline std::string file_extension(const std::string &path) {
@@ -1073,19 +1434,41 @@ inline std::string file_extension(const std::string &path) {
return std::string();
}
+inline bool is_space_or_tab(char c) { return c == ' ' || c == '\t'; }
+
+inline std::pair<size_t, size_t> trim(const char *b, const char *e, size_t left,
+ size_t right) {
+ while (b + left < e && is_space_or_tab(b[left])) {
+ left++;
+ }
+ while (right > 0 && is_space_or_tab(b[right - 1])) {
+ right--;
+ }
+ return std::make_pair(left, right);
+}
+
+inline std::string trim_copy(const std::string &s) {
+ auto r = trim(s.data(), s.data() + s.size(), 0, s.size());
+ return s.substr(r.first, r.second - r.first);
+}
+
template <class Fn> void split(const char *b, const char *e, char d, Fn fn) {
- int i = 0;
- int beg = 0;
+ size_t i = 0;
+ size_t beg = 0;
- while (e ? (b + i != e) : (b[i] != '\0')) {
+ while (e ? (b + i < e) : (b[i] != '\0')) {
if (b[i] == d) {
- fn(&b[beg], &b[i]);
+ auto r = trim(b, e, beg, i);
+ if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
beg = i + 1;
}
i++;
}
- if (i) { fn(&b[beg], &b[i]); }
+ if (i) {
+ auto r = trim(b, e, beg, i);
+ if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
+ }
}
// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer`
@@ -1172,7 +1555,17 @@ inline int close_socket(socket_t sock) {
#endif
}
-inline int select_read(socket_t sock, time_t sec, time_t usec) {
+template <typename T> inline ssize_t handle_EINTR(T fn) {
+ ssize_t res = false;
+ while (true) {
+ res = fn();
+ if (res < 0 && errno == EINTR) { continue; }
+ break;
+ }
+ return res;
+}
+
+inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) {
#ifdef CPPHTTPLIB_USE_POLL
struct pollfd pfd_read;
pfd_read.fd = sock;
@@ -1180,7 +1573,7 @@ inline int select_read(socket_t sock, time_t sec, time_t usec) {
auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
- return poll(&pfd_read, 1, timeout);
+ return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
#else
fd_set fds;
FD_ZERO(&fds);
@@ -1188,13 +1581,15 @@ inline int select_read(socket_t sock, time_t sec, time_t usec) {
timeval tv;
tv.tv_sec = static_cast<long>(sec);
- tv.tv_usec = static_cast<long>(usec);
+ tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
- return select(static_cast<int>(sock + 1), &fds, nullptr, nullptr, &tv);
+ return handle_EINTR([&]() {
+ return select(static_cast<int>(sock + 1), &fds, nullptr, nullptr, &tv);
+ });
#endif
}
-inline int select_write(socket_t sock, time_t sec, time_t usec) {
+inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) {
#ifdef CPPHTTPLIB_USE_POLL
struct pollfd pfd_read;
pfd_read.fd = sock;
@@ -1202,7 +1597,7 @@ inline int select_write(socket_t sock, time_t sec, time_t usec) {
auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
- return poll(&pfd_read, 1, timeout);
+ return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
#else
fd_set fds;
FD_ZERO(&fds);
@@ -1210,9 +1605,11 @@ inline int select_write(socket_t sock, time_t sec, time_t usec) {
timeval tv;
tv.tv_sec = static_cast<long>(sec);
- tv.tv_usec = static_cast<long>(usec);
+ tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
- return select(static_cast<int>(sock + 1), nullptr, &fds, nullptr, &tv);
+ return handle_EINTR([&]() {
+ return select(static_cast<int>(sock + 1), nullptr, &fds, nullptr, &tv);
+ });
#endif
}
@@ -1224,13 +1621,14 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
- if (poll(&pfd_read, 1, timeout) > 0 &&
- pfd_read.revents & (POLLIN | POLLOUT)) {
+ auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
+
+ if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) {
int error = 0;
socklen_t len = sizeof(error);
- return getsockopt(sock, SOL_SOCKET, SO_ERROR,
- reinterpret_cast<char *>(&error), &len) >= 0 &&
- !error;
+ auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
+ reinterpret_cast<char *>(&error), &len);
+ return res >= 0 && !error;
}
return false;
#else
@@ -1243,10 +1641,13 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
timeval tv;
tv.tv_sec = static_cast<long>(sec);
- tv.tv_usec = static_cast<long>(usec);
+ tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
+
+ auto ret = handle_EINTR([&]() {
+ return select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv);
+ });
- if (select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv) > 0 &&
- (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
+ if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
int error = 0;
socklen_t len = sizeof(error);
return getsockopt(sock, SOL_SOCKET, SO_ERROR,
@@ -1259,40 +1660,45 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
class SocketStream : public Stream {
public:
- SocketStream(socket_t sock, time_t read_timeout_sec,
- time_t read_timeout_usec);
+ SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
+ time_t write_timeout_sec, time_t write_timeout_usec);
~SocketStream() override;
bool is_readable() const override;
bool is_writable() const override;
- int read(char *ptr, size_t size) override;
- int write(const char *ptr, size_t size) override;
- std::string get_remote_addr() const override;
+ ssize_t read(char *ptr, size_t size) override;
+ ssize_t write(const char *ptr, size_t size) override;
+ void get_remote_ip_and_port(std::string &ip, int &port) const override;
private:
socket_t sock_;
time_t read_timeout_sec_;
time_t read_timeout_usec_;
+ time_t write_timeout_sec_;
+ time_t write_timeout_usec_;
};
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
class SSLSocketStream : public Stream {
public:
SSLSocketStream(socket_t sock, SSL *ssl, time_t read_timeout_sec,
- time_t read_timeout_usec);
- virtual ~SSLSocketStream();
+ time_t read_timeout_usec, time_t write_timeout_sec,
+ time_t write_timeout_usec);
+ ~SSLSocketStream() override;
bool is_readable() const override;
bool is_writable() const override;
- int read(char *ptr, size_t size) override;
- int write(const char *ptr, size_t size) override;
- std::string get_remote_addr() const override;
+ ssize_t read(char *ptr, size_t size) override;
+ ssize_t write(const char *ptr, size_t size) override;
+ void get_remote_ip_and_port(std::string &ip, int &port) const override;
private:
socket_t sock_;
SSL *ssl_;
time_t read_timeout_sec_;
time_t read_timeout_usec_;
+ time_t write_timeout_sec_;
+ time_t write_timeout_usec_;
};
#endif
@@ -1303,58 +1709,76 @@ public:
bool is_readable() const override;
bool is_writable() const override;
- int read(char *ptr, size_t size) override;
- int write(const char *ptr, size_t size) override;
- std::string get_remote_addr() const override;
+ ssize_t read(char *ptr, size_t size) override;
+ ssize_t write(const char *ptr, size_t size) override;
+ void get_remote_ip_and_port(std::string &ip, int &port) const override;
const std::string &get_buffer() const;
private:
std::string buffer;
- int position = 0;
+ size_t position = 0;
};
+inline bool keep_alive(socket_t sock, time_t keep_alive_timeout_sec) {
+ using namespace std::chrono;
+ auto start = steady_clock::now();
+ while (true) {
+ auto val = select_read(sock, 0, 10000);
+ if (val < 0) {
+ return false;
+ } else if (val == 0) {
+ auto current = steady_clock::now();
+ auto duration = duration_cast<milliseconds>(current - start);
+ auto timeout = keep_alive_timeout_sec * 1000;
+ if (duration.count() > timeout) { return false; }
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ } else {
+ return true;
+ }
+ }
+}
+
template <typename T>
-inline bool process_socket(bool is_client_request, socket_t sock,
- size_t keep_alive_max_count, time_t read_timeout_sec,
- time_t read_timeout_usec, T callback) {
+inline bool
+process_server_socket_core(socket_t sock, size_t keep_alive_max_count,
+ time_t keep_alive_timeout_sec, T callback) {
assert(keep_alive_max_count > 0);
-
auto ret = false;
-
- if (keep_alive_max_count > 1) {
- auto count = keep_alive_max_count;
- while (count > 0 &&
- (is_client_request ||
- select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND,
- CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND) > 0)) {
- SocketStream strm(sock, read_timeout_sec, read_timeout_usec);
- auto last_connection = count == 1;
- auto connection_close = false;
-
- ret = callback(strm, last_connection, connection_close);
- if (!ret || connection_close) { break; }
-
- count--;
- }
- } else { // keep_alive_max_count is 0 or 1
- SocketStream strm(sock, read_timeout_sec, read_timeout_usec);
- auto dummy_connection_close = false;
- ret = callback(strm, true, dummy_connection_close);
+ auto count = keep_alive_max_count;
+ while (count > 0 && keep_alive(sock, keep_alive_timeout_sec)) {
+ auto close_connection = count == 1;
+ auto connection_closed = false;
+ ret = callback(close_connection, connection_closed);
+ if (!ret || connection_closed) { break; }
+ count--;
}
-
return ret;
}
template <typename T>
-inline bool process_and_close_socket(bool is_client_request, socket_t sock,
- size_t keep_alive_max_count,
- time_t read_timeout_sec,
- time_t read_timeout_usec, T callback) {
- auto ret = process_socket(is_client_request, sock, keep_alive_max_count,
- read_timeout_sec, read_timeout_usec, callback);
- close_socket(sock);
- return ret;
+inline bool
+process_server_socket(socket_t sock, size_t keep_alive_max_count,
+ time_t keep_alive_timeout_sec, time_t read_timeout_sec,
+ time_t read_timeout_usec, time_t write_timeout_sec,
+ time_t write_timeout_usec, T callback) {
+ return process_server_socket_core(
+ sock, keep_alive_max_count, keep_alive_timeout_sec,
+ [&](bool close_connection, bool &connection_closed) {
+ SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
+ write_timeout_sec, write_timeout_usec);
+ return callback(strm, close_connection, connection_closed);
+ });
+}
+
+template <typename T>
+inline bool process_client_socket(socket_t sock, time_t read_timeout_sec,
+ time_t read_timeout_usec,
+ time_t write_timeout_sec,
+ time_t write_timeout_usec, T callback) {
+ SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
+ write_timeout_sec, write_timeout_usec);
+ return callback(strm);
}
inline int shutdown_socket(socket_t sock) {
@@ -1365,18 +1789,10 @@ inline int shutdown_socket(socket_t sock) {
#endif
}
-template <typename Fn>
-socket_t create_socket(const char *host, int port, Fn fn,
- int socket_flags = 0) {
-#ifdef _WIN32
-#define SO_SYNCHRONOUS_NONALERT 0x20
-#define SO_OPENTYPE 0x7008
-
- int opt = SO_SYNCHRONOUS_NONALERT;
- setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt,
- sizeof(opt));
-#endif
-
+template <typename BindOrConnect>
+socket_t create_socket(const char *host, int port, int socket_flags,
+ bool tcp_nodelay, SocketOptions socket_options,
+ BindOrConnect bind_or_connect) {
// Get address info
struct addrinfo hints;
struct addrinfo *result;
@@ -1390,6 +1806,9 @@ socket_t create_socket(const char *host, int port, Fn fn,
auto service = std::to_string(port);
if (getaddrinfo(host, service.c_str(), &hints, &result)) {
+#ifdef __linux__
+ res_init();
+#endif
return INVALID_SOCKET;
}
@@ -1424,17 +1843,22 @@ socket_t create_socket(const char *host, int port, Fn fn,
if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { continue; }
#endif
- // Make 'reuse address' option available
- int yes = 1;
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&yes),
- sizeof(yes));
-#ifdef SO_REUSEPORT
- setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, reinterpret_cast<char *>(&yes),
- sizeof(yes));
-#endif
+ if (tcp_nodelay) {
+ int yes = 1;
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&yes),
+ sizeof(yes));
+ }
+
+ if (socket_options) { socket_options(sock); }
+
+ if (rp->ai_family == AF_INET6) {
+ int no = 0;
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&no),
+ sizeof(no));
+ }
// bind or connect
- if (fn(sock, *rp)) {
+ if (bind_or_connect(sock, *rp)) {
freeaddrinfo(result);
return sock;
}
@@ -1479,7 +1903,7 @@ inline bool bind_ip_address(socket_t sock, const char *host) {
auto ret = false;
for (auto rp = result; rp; rp = rp->ai_next) {
const auto &ai = *rp;
- if (!::bind(sock, ai.ai_addr, static_cast<int>(ai.ai_addrlen))) {
+ if (!::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
ret = true;
break;
}
@@ -1489,8 +1913,12 @@ inline bool bind_ip_address(socket_t sock, const char *host) {
return ret;
}
+#if !defined _WIN32 && !defined ANDROID
+#define USE_IF2IP
+#endif
+
+#ifdef USE_IF2IP
inline std::string if2ip(const std::string &ifn) {
-#ifndef _WIN32
struct ifaddrs *ifap;
getifaddrs(&ifap);
for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) {
@@ -1506,51 +1934,83 @@ inline std::string if2ip(const std::string &ifn) {
}
}
freeifaddrs(ifap);
-#endif
return std::string();
}
+#endif
inline socket_t create_client_socket(const char *host, int port,
- time_t timeout_sec,
- const std::string &intf) {
- return create_socket(
- host, port, [&](socket_t sock, struct addrinfo &ai) -> bool {
+ bool tcp_nodelay,
+ SocketOptions socket_options,
+ time_t timeout_sec, time_t timeout_usec,
+ const std::string &intf, Error &error) {
+ auto sock = create_socket(
+ host, port, 0, tcp_nodelay, socket_options,
+ [&](socket_t sock, struct addrinfo &ai) -> bool {
if (!intf.empty()) {
+#ifdef USE_IF2IP
auto ip = if2ip(intf);
if (ip.empty()) { ip = intf; }
- if (!bind_ip_address(sock, ip.c_str())) { return false; }
+ if (!bind_ip_address(sock, ip.c_str())) {
+ error = Error::BindIPAddress;
+ return false;
+ }
+#endif
}
set_nonblocking(sock, true);
- auto ret = ::connect(sock, ai.ai_addr, static_cast<int>(ai.ai_addrlen));
+ auto ret =
+ ::connect(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen));
+
if (ret < 0) {
if (is_connection_error() ||
- !wait_until_socket_is_ready(sock, timeout_sec, 0)) {
+ !wait_until_socket_is_ready(sock, timeout_sec, timeout_usec)) {
close_socket(sock);
+ error = Error::Connection;
return false;
}
}
set_nonblocking(sock, false);
+ error = Error::Success;
return true;
});
-}
-inline std::string get_remote_addr(socket_t sock) {
- struct sockaddr_storage addr;
- socklen_t len = sizeof(addr);
+ if (sock != INVALID_SOCKET) {
+ error = Error::Success;
+ } else {
+ if (error == Error::Success) { error = Error::Connection; }
+ }
- if (!getpeername(sock, reinterpret_cast<struct sockaddr *>(&addr), &len)) {
- std::array<char, NI_MAXHOST> ipstr{};
+ return sock;
+}
- if (!getnameinfo(reinterpret_cast<struct sockaddr *>(&addr), len,
- ipstr.data(), static_cast<unsigned int>(ipstr.size()), nullptr, 0, NI_NUMERICHOST)) {
- return ipstr.data();
- }
+inline void get_remote_ip_and_port(const struct sockaddr_storage &addr,
+ socklen_t addr_len, std::string &ip,
+ int &port) {
+ if (addr.ss_family == AF_INET) {
+ port = ntohs(reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_port);
+ } else if (addr.ss_family == AF_INET6) {
+ port =
+ ntohs(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_port);
}
- return std::string();
+ std::array<char, NI_MAXHOST> ipstr{};
+ if (!getnameinfo(reinterpret_cast<const struct sockaddr *>(&addr), addr_len,
+ ipstr.data(), static_cast<socklen_t>(ipstr.size()), nullptr,
+ 0, NI_NUMERICHOST)) {
+ ip = ipstr.data();
+ }
+}
+
+inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) {
+ struct sockaddr_storage addr;
+ socklen_t addr_len = sizeof(addr);
+
+ if (!getpeername(sock, reinterpret_cast<struct sockaddr *>(&addr),
+ &addr_len)) {
+ get_remote_ip_and_port(addr, addr_len, ip, port);
+ }
}
inline const char *
@@ -1596,121 +2056,336 @@ find_content_type(const std::string &path,
inline const char *status_message(int status) {
switch (status) {
case 100: return "Continue";
+ case 101: return "Switching Protocol";
+ case 102: return "Processing";
+ case 103: return "Early Hints";
case 200: return "OK";
+ case 201: return "Created";
case 202: return "Accepted";
+ case 203: return "Non-Authoritative Information";
case 204: return "No Content";
+ case 205: return "Reset Content";
case 206: return "Partial Content";
+ case 207: return "Multi-Status";
+ case 208: return "Already Reported";
+ case 226: return "IM Used";
+ case 300: return "Multiple Choice";
case 301: return "Moved Permanently";
case 302: return "Found";
case 303: return "See Other";
case 304: return "Not Modified";
+ case 305: return "Use Proxy";
+ case 306: return "unused";
+ case 307: return "Temporary Redirect";
+ case 308: return "Permanent Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
+ case 402: return "Payment Required";
case 403: return "Forbidden";
case 404: return "Not Found";
+ case 405: return "Method Not Allowed";
+ case 406: return "Not Acceptable";
+ case 407: return "Proxy Authentication Required";
+ case 408: return "Request Timeout";
+ case 409: return "Conflict";
+ case 410: return "Gone";
+ case 411: return "Length Required";
+ case 412: return "Precondition Failed";
case 413: return "Payload Too Large";
- case 414: return "Request-URI Too Long";
+ case 414: return "URI Too Long";
case 415: return "Unsupported Media Type";
case 416: return "Range Not Satisfiable";
case 417: return "Expectation Failed";
+ case 418: return "I'm a teapot";
+ case 421: return "Misdirected Request";
+ case 422: return "Unprocessable Entity";
+ case 423: return "Locked";
+ case 424: return "Failed Dependency";
+ case 425: return "Too Early";
+ case 426: return "Upgrade Required";
+ case 428: return "Precondition Required";
+ case 429: return "Too Many Requests";
+ case 431: return "Request Header Fields Too Large";
+ case 451: return "Unavailable For Legal Reasons";
+ case 501: return "Not Implemented";
+ case 502: return "Bad Gateway";
case 503: return "Service Unavailable";
+ case 504: return "Gateway Timeout";
+ case 505: return "HTTP Version Not Supported";
+ case 506: return "Variant Also Negotiates";
+ case 507: return "Insufficient Storage";
+ case 508: return "Loop Detected";
+ case 510: return "Not Extended";
+ case 511: return "Network Authentication Required";
default:
case 500: return "Internal Server Error";
}
}
-#ifdef CPPHTTPLIB_ZLIB_SUPPORT
-inline bool can_compress(const std::string &content_type) {
- return !content_type.find("text/") || content_type == "image/svg+xml" ||
+inline bool can_compress_content_type(const std::string &content_type) {
+ return (!content_type.find("text/") && content_type != "text/event-stream") ||
+ content_type == "image/svg+xml" ||
content_type == "application/javascript" ||
content_type == "application/json" ||
content_type == "application/xml" ||
content_type == "application/xhtml+xml";
}
-inline bool compress(std::string &content) {
- z_stream strm;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
+enum class EncodingType { None = 0, Gzip, Brotli };
- auto ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
- Z_DEFAULT_STRATEGY);
- if (ret != Z_OK) { return false; }
+inline EncodingType encoding_type(const Request &req, const Response &res) {
+ auto ret =
+ detail::can_compress_content_type(res.get_header_value("Content-Type"));
+ if (!ret) { return EncodingType::None; }
- strm.avail_in = content.size();
- strm.next_in =
- const_cast<Bytef *>(reinterpret_cast<const Bytef *>(content.data()));
+ const auto &s = req.get_header_value("Accept-Encoding");
+ (void)(s);
- std::string compressed;
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+ // TODO: 'Accept-Encoding' has br, not br;q=0
+ ret = s.find("br") != std::string::npos;
+ if (ret) { return EncodingType::Brotli; }
+#endif
- std::array<char, 16384> buff{};
- do {
- strm.avail_out = buff.size();
- strm.next_out = reinterpret_cast<Bytef *>(buff.data());
- ret = deflate(&strm, Z_FINISH);
- assert(ret != Z_STREAM_ERROR);
- compressed.append(buff.data(), buff.size() - strm.avail_out);
- } while (strm.avail_out == 0);
+#ifdef CPPHTTPLIB_ZLIB_SUPPORT
+ // TODO: 'Accept-Encoding' has gzip, not gzip;q=0
+ ret = s.find("gzip") != std::string::npos;
+ if (ret) { return EncodingType::Gzip; }
+#endif
- assert(ret == Z_STREAM_END);
- assert(strm.avail_in == 0);
+ return EncodingType::None;
+}
- content.swap(compressed);
+class compressor {
+public:
+ virtual ~compressor(){};
- deflateEnd(&strm);
- return true;
-}
+ typedef std::function<bool(const char *data, size_t data_len)> Callback;
+ virtual bool compress(const char *data, size_t data_length, bool last,
+ Callback callback) = 0;
+};
class decompressor {
public:
- decompressor() {
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
+ virtual ~decompressor() {}
+
+ virtual bool is_valid() const = 0;
+
+ typedef std::function<bool(const char *data, size_t data_len)> Callback;
+ virtual bool decompress(const char *data, size_t data_length,
+ Callback callback) = 0;
+};
+
+class nocompressor : public compressor {
+public:
+ ~nocompressor(){};
+
+ bool compress(const char *data, size_t data_length, bool /*last*/,
+ Callback callback) override {
+ if (!data_length) { return true; }
+ return callback(data, data_length);
+ }
+};
+
+#ifdef CPPHTTPLIB_ZLIB_SUPPORT
+class gzip_compressor : public compressor {
+public:
+ gzip_compressor() {
+ std::memset(&strm_, 0, sizeof(strm_));
+ strm_.zalloc = Z_NULL;
+ strm_.zfree = Z_NULL;
+ strm_.opaque = Z_NULL;
+
+ is_valid_ = deflateInit2(&strm_, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
+ Z_DEFAULT_STRATEGY) == Z_OK;
+ }
+
+ ~gzip_compressor() { deflateEnd(&strm_); }
+
+ bool compress(const char *data, size_t data_length, bool last,
+ Callback callback) override {
+ assert(is_valid_);
+
+ auto flush = last ? Z_FINISH : Z_NO_FLUSH;
+
+ strm_.avail_in = static_cast<decltype(strm_.avail_in)>(data_length);
+ strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
+
+ int ret = Z_OK;
+
+ std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
+ do {
+ strm_.avail_out = buff.size();
+ strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
+
+ ret = deflate(&strm_, flush);
+ assert(ret != Z_STREAM_ERROR);
+
+ if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
+ return false;
+ }
+ } while (strm_.avail_out == 0);
+
+ assert((last && ret == Z_STREAM_END) || (!last && ret == Z_OK));
+ assert(strm_.avail_in == 0);
+ return true;
+ }
+
+private:
+ bool is_valid_ = false;
+ z_stream strm_;
+};
+
+class gzip_decompressor : public decompressor {
+public:
+ gzip_decompressor() {
+ std::memset(&strm_, 0, sizeof(strm_));
+ strm_.zalloc = Z_NULL;
+ strm_.zfree = Z_NULL;
+ strm_.opaque = Z_NULL;
// 15 is the value of wbits, which should be at the maximum possible value
- // to ensure that any gzip stream can be decoded. The offset of 16 specifies
- // that the stream to decompress will be formatted with a gzip wrapper.
- is_valid_ = inflateInit2(&strm, 16 + 15) == Z_OK;
+ // to ensure that any gzip stream can be decoded. The offset of 32 specifies
+ // that the stream type should be automatically detected either gzip or
+ // deflate.
+ is_valid_ = inflateInit2(&strm_, 32 + 15) == Z_OK;
}
- ~decompressor() { inflateEnd(&strm); }
+ ~gzip_decompressor() { inflateEnd(&strm_); }
- bool is_valid() const { return is_valid_; }
+ bool is_valid() const override { return is_valid_; }
+
+ bool decompress(const char *data, size_t data_length,
+ Callback callback) override {
+ assert(is_valid_);
- template <typename T>
- bool decompress(const char *data, size_t data_length, T callback) {
int ret = Z_OK;
- strm.avail_in = data_length;
- strm.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
+ strm_.avail_in = static_cast<decltype(strm_.avail_in)>(data_length);
+ strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
- std::array<char, 16384> buff{};
- do {
- strm.avail_out = buff.size();
- strm.next_out = reinterpret_cast<Bytef *>(buff.data());
+ std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
+ while (strm_.avail_in > 0) {
+ strm_.avail_out = buff.size();
+ strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
- ret = inflate(&strm, Z_NO_FLUSH);
+ ret = inflate(&strm_, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR);
switch (ret) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
- case Z_MEM_ERROR: inflateEnd(&strm); return false;
+ case Z_MEM_ERROR: inflateEnd(&strm_); return false;
}
- if (!callback(buff.data(), buff.size() - strm.avail_out)) {
+ if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
return false;
}
- } while (strm.avail_out == 0);
+ }
return ret == Z_OK || ret == Z_STREAM_END;
}
private:
- bool is_valid_;
- z_stream strm;
+ bool is_valid_ = false;
+ z_stream strm_;
+};
+#endif
+
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+class brotli_compressor : public compressor {
+public:
+ brotli_compressor() {
+ state_ = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
+ }
+
+ ~brotli_compressor() { BrotliEncoderDestroyInstance(state_); }
+
+ bool compress(const char *data, size_t data_length, bool last,
+ Callback callback) override {
+ std::array<uint8_t, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
+
+ auto operation = last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
+ auto available_in = data_length;
+ auto next_in = reinterpret_cast<const uint8_t *>(data);
+
+ for (;;) {
+ if (last) {
+ if (BrotliEncoderIsFinished(state_)) { break; }
+ } else {
+ if (!available_in) { break; }
+ }
+
+ auto available_out = buff.size();
+ auto next_out = buff.data();
+
+ if (!BrotliEncoderCompressStream(state_, operation, &available_in,
+ &next_in, &available_out, &next_out,
+ nullptr)) {
+ return false;
+ }
+
+ auto output_bytes = buff.size() - available_out;
+ if (output_bytes) {
+ callback(reinterpret_cast<const char *>(buff.data()), output_bytes);
+ }
+ }
+
+ return true;
+ }
+
+private:
+ BrotliEncoderState *state_ = nullptr;
+};
+
+class brotli_decompressor : public decompressor {
+public:
+ brotli_decompressor() {
+ decoder_s = BrotliDecoderCreateInstance(0, 0, 0);
+ decoder_r = decoder_s ? BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT
+ : BROTLI_DECODER_RESULT_ERROR;
+ }
+
+ ~brotli_decompressor() {
+ if (decoder_s) { BrotliDecoderDestroyInstance(decoder_s); }
+ }
+
+ bool is_valid() const override { return decoder_s; }
+
+ bool decompress(const char *data, size_t data_length,
+ Callback callback) override {
+ if (decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
+ decoder_r == BROTLI_DECODER_RESULT_ERROR) {
+ return 0;
+ }
+
+ const uint8_t *next_in = (const uint8_t *)data;
+ size_t avail_in = data_length;
+ size_t total_out;
+
+ decoder_r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
+
+ std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
+ while (decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+ char *next_out = buff.data();
+ size_t avail_out = buff.size();
+
+ decoder_r = BrotliDecoderDecompressStream(
+ decoder_s, &avail_in, &next_in, &avail_out,
+ reinterpret_cast<uint8_t **>(&next_out), &total_out);
+
+ if (decoder_r == BROTLI_DECODER_RESULT_ERROR) { return false; }
+
+ if (!callback(buff.data(), buff.size() - avail_out)) { return false; }
+ }
+
+ return decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
+ decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
+ }
+
+private:
+ BrotliDecoderResult decoder_r;
+ BrotliDecoderState *decoder_s = nullptr;
};
#endif
@@ -1720,21 +2395,60 @@ inline bool has_header(const Headers &headers, const char *key) {
inline const char *get_header_value(const Headers &headers, const char *key,
size_t id = 0, const char *def = nullptr) {
- auto it = headers.find(key);
- std::advance(it, id);
- if (it != headers.end()) { return it->second.c_str(); }
+ auto rng = headers.equal_range(key);
+ auto it = rng.first;
+ std::advance(it, static_cast<ssize_t>(id));
+ if (it != rng.second) { return it->second.c_str(); }
return def;
}
-inline uint64_t get_header_value_uint64(const Headers &headers, const char *key,
- int def = 0) {
- auto it = headers.find(key);
- if (it != headers.end()) {
+template <typename T>
+inline T get_header_value(const Headers & /*headers*/, const char * /*key*/,
+ size_t /*id*/ = 0, uint64_t /*def*/ = 0) {}
+
+template <>
+inline uint64_t get_header_value<uint64_t>(const Headers &headers,
+ const char *key, size_t id,
+ uint64_t def) {
+ auto rng = headers.equal_range(key);
+ auto it = rng.first;
+ std::advance(it, static_cast<ssize_t>(id));
+ if (it != rng.second) {
return std::strtoull(it->second.data(), nullptr, 10);
}
return def;
}
+template <typename T>
+inline bool parse_header(const char *beg, const char *end, T fn) {
+ // Skip trailing spaces and tabs.
+ while (beg < end && is_space_or_tab(end[-1])) {
+ end--;
+ }
+
+ auto p = beg;
+ while (p < end && *p != ':') {
+ p++;
+ }
+
+ if (p == end) { return false; }
+
+ auto key_end = p;
+
+ if (*p++ != ':') { return false; }
+
+ while (p < end && is_space_or_tab(*p)) {
+ p++;
+ }
+
+ if (p < end) {
+ fn(std::string(beg, key_end), decode_url(std::string(p, end), false));
+ return true;
+ }
+
+ return false;
+}
+
inline bool read_headers(Stream &strm, Headers &headers) {
const auto bufsiz = 2048;
char buf[bufsiz];
@@ -1751,24 +2465,13 @@ inline bool read_headers(Stream &strm, Headers &headers) {
continue; // Skip invalid line.
}
- // Skip trailing spaces and tabs.
+ // Exclude CRLF
auto end = line_reader.ptr() + line_reader.size() - 2;
- while (line_reader.ptr() < end && (end[-1] == ' ' || end[-1] == '\t')) {
- end--;
- }
- // Horizontal tab and ' ' are considered whitespace and are ignored when on
- // the left or right side of the header value:
- // - https://stackoverflow.com/questions/50179659/
- // - https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
- static const std::regex re(R"((.+?):[\t ]*(.+))");
-
- std::cmatch m;
- if (std::regex_match(line_reader.ptr(), end, m, re)) {
- auto key = std::string(m[1]);
- auto val = std::string(m[2]);
- headers.emplace(key, val);
- }
+ parse_header(line_reader.ptr(), end,
+ [&](std::string &&key, std::string &&val) {
+ headers.emplace(std::move(key), std::move(val));
+ });
}
return true;
@@ -1781,12 +2484,12 @@ inline bool read_content_with_length(Stream &strm, uint64_t len,
uint64_t r = 0;
while (r < len) {
auto read_len = static_cast<size_t>(len - r);
- auto n = strm.read(buf, std::min(read_len, CPPHTTPLIB_RECV_BUFSIZ));
+ auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
if (n <= 0) { return false; }
- if (!out(buf, n)) { return false; }
+ if (!out(buf, static_cast<size_t>(n))) { return false; }
- r += n;
+ r += static_cast<uint64_t>(n);
if (progress) {
if (!progress(r, len)) { return false; }
@@ -1801,9 +2504,9 @@ inline void skip_content_with_length(Stream &strm, uint64_t len) {
uint64_t r = 0;
while (r < len) {
auto read_len = static_cast<size_t>(len - r);
- auto n = strm.read(buf, std::min(read_len, CPPHTTPLIB_RECV_BUFSIZ));
+ auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
if (n <= 0) { return; }
- r += n;
+ r += static_cast<uint64_t>(n);
}
}
@@ -1816,7 +2519,7 @@ inline bool read_content_without_length(Stream &strm, ContentReceiver out) {
} else if (n == 0) {
return true;
}
- if (!out(buf, n)) { return false; }
+ if (!out(buf, static_cast<size_t>(n))) { return false; }
}
return true;
@@ -1830,9 +2533,17 @@ inline bool read_content_chunked(Stream &strm, ContentReceiver out) {
if (!line_reader.getline()) { return false; }
- auto chunk_len = std::stoi(line_reader.ptr(), 0, 16);
+ unsigned long chunk_len;
+ while (true) {
+ char *end_ptr;
+
+ chunk_len = std::strtoul(line_reader.ptr(), &end_ptr, 16);
+
+ if (end_ptr == line_reader.ptr()) { return false; }
+ if (chunk_len == ULONG_MAX) { return false; }
+
+ if (chunk_len == 0) { break; }
- while (chunk_len > 0) {
if (!read_content_with_length(strm, chunk_len, nullptr, out)) {
return false;
}
@@ -1842,8 +2553,6 @@ inline bool read_content_chunked(Stream &strm, ContentReceiver out) {
if (strcmp(line_reader.ptr(), "\r\n")) { break; }
if (!line_reader.getline()) { return false; }
-
- chunk_len = std::stoi(line_reader.ptr(), 0, 16);
}
if (chunk_len == 0) {
@@ -1860,62 +2569,86 @@ inline bool is_chunked_transfer_encoding(const Headers &headers) {
"chunked");
}
-template <typename T>
-bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
- Progress progress, ContentReceiver receiver) {
-
- ContentReceiver out = [&](const char *buf, size_t n) {
- return receiver(buf, n);
- };
+template <typename T, typename U>
+bool prepare_content_receiver(T &x, int &status, ContentReceiver receiver,
+ bool decompress, U callback) {
+ if (decompress) {
+ std::string encoding = x.get_header_value("Content-Encoding");
+ std::shared_ptr<decompressor> decompressor;
+ if (encoding.find("gzip") != std::string::npos ||
+ encoding.find("deflate") != std::string::npos) {
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
- decompressor decompressor;
-
- if (!decompressor.is_valid()) {
- status = 500;
- return false;
- }
-
- if (x.get_header_value("Content-Encoding") == "gzip") {
- out = [&](const char *buf, size_t n) {
- return decompressor.decompress(
- buf, n, [&](const char *buf, size_t n) { return receiver(buf, n); });
- };
- }
+ decompressor = std::make_shared<gzip_decompressor>();
#else
- if (x.get_header_value("Content-Encoding") == "gzip") {
- status = 415;
- return false;
- }
+ status = 415;
+ return false;
#endif
+ } else if (encoding.find("br") != std::string::npos) {
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+ decompressor = std::make_shared<brotli_decompressor>();
+#else
+ status = 415;
+ return false;
+#endif
+ }
- auto ret = true;
- auto exceed_payload_max_length = false;
-
- if (is_chunked_transfer_encoding(x.headers)) {
- ret = read_content_chunked(strm, out);
- } else if (!has_header(x.headers, "Content-Length")) {
- ret = read_content_without_length(strm, out);
- } else {
- auto len = get_header_value_uint64(x.headers, "Content-Length", 0);
- if (len > payload_max_length) {
- exceed_payload_max_length = true;
- skip_content_with_length(strm, len);
- ret = false;
- } else if (len > 0) {
- ret = read_content_with_length(strm, len, progress, out);
+ if (decompressor) {
+ if (decompressor->is_valid()) {
+ ContentReceiver out = [&](const char *buf, size_t n) {
+ return decompressor->decompress(
+ buf, n,
+ [&](const char *buf, size_t n) { return receiver(buf, n); });
+ };
+ return callback(out);
+ } else {
+ status = 500;
+ return false;
+ }
}
}
- if (!ret) { status = exceed_payload_max_length ? 413 : 400; }
+ ContentReceiver out = [&](const char *buf, size_t n) {
+ return receiver(buf, n);
+ };
+ return callback(out);
+}
+
+template <typename T>
+bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
+ Progress progress, ContentReceiver receiver,
+ bool decompress) {
+ return prepare_content_receiver(
+ x, status, receiver, decompress, [&](const ContentReceiver &out) {
+ auto ret = true;
+ auto exceed_payload_max_length = false;
+
+ if (is_chunked_transfer_encoding(x.headers)) {
+ ret = read_content_chunked(strm, out);
+ } else if (!has_header(x.headers, "Content-Length")) {
+ ret = read_content_without_length(strm, out);
+ } else {
+ auto len = get_header_value<uint64_t>(x.headers, "Content-Length");
+ if (len > payload_max_length) {
+ exceed_payload_max_length = true;
+ skip_content_with_length(strm, len);
+ ret = false;
+ } else if (len > 0) {
+ ret = read_content_with_length(strm, len, progress, out);
+ }
+ }
- return ret;
+ if (!ret) { status = exceed_payload_max_length ? 413 : 400; }
+ return ret;
+ });
}
template <typename T>
-inline int write_headers(Stream &strm, const T &info, const Headers &headers) {
- auto write_len = 0;
+inline ssize_t write_headers(Stream &strm, const T &info,
+ const Headers &headers) {
+ ssize_t write_len = 0;
for (const auto &x : info.headers) {
+ if (x.first == "EXCEPTION_WHAT") { continue; }
auto len =
strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str());
if (len < 0) { return len; }
@@ -1933,57 +2666,150 @@ inline int write_headers(Stream &strm, const T &info, const Headers &headers) {
return write_len;
}
+inline bool write_data(Stream &strm, const char *d, size_t l) {
+ size_t offset = 0;
+ while (offset < l) {
+ auto length = strm.write(d + offset, l - offset);
+ if (length < 0) { return false; }
+ offset += static_cast<size_t>(length);
+ }
+ return true;
+}
+
+template <typename T>
inline ssize_t write_content(Stream &strm, ContentProvider content_provider,
- size_t offset, size_t length) {
+ size_t offset, size_t length, T is_shutting_down) {
size_t begin_offset = offset;
size_t end_offset = offset + length;
- while (offset < end_offset) {
- ssize_t written_length = 0;
+ auto ok = true;
+ DataSink data_sink;
- DataSink data_sink;
- data_sink.write = [&](const char *d, size_t l) {
+ data_sink.write = [&](const char *d, size_t l) {
+ if (ok) {
offset += l;
- written_length = strm.write(d, l);
- };
- data_sink.done = [&](void) { written_length = -1; };
- data_sink.is_writable = [&](void) { return strm.is_writable(); };
+ if (!write_data(strm, d, l)) { ok = false; }
+ }
+ };
- content_provider(offset, end_offset - offset, data_sink);
- if (written_length < 0) { return written_length; }
+ data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };
+
+ while (offset < end_offset && !is_shutting_down()) {
+ if (!content_provider(offset, end_offset - offset, data_sink)) {
+ return -1;
+ }
+ if (!ok) { return -1; }
}
+
return static_cast<ssize_t>(offset - begin_offset);
}
template <typename T>
+inline ssize_t write_content_without_length(Stream &strm,
+ ContentProvider content_provider,
+ T is_shutting_down) {
+ size_t offset = 0;
+ auto data_available = true;
+ auto ok = true;
+ DataSink data_sink;
+
+ data_sink.write = [&](const char *d, size_t l) {
+ if (ok) {
+ offset += l;
+ if (!write_data(strm, d, l)) { ok = false; }
+ }
+ };
+
+ data_sink.done = [&](void) { data_available = false; };
+
+ data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };
+
+ while (data_available && !is_shutting_down()) {
+ if (!content_provider(offset, 0, data_sink)) { return -1; }
+ if (!ok) { return -1; }
+ }
+
+ return static_cast<ssize_t>(offset);
+}
+
+template <typename T, typename U>
inline ssize_t write_content_chunked(Stream &strm,
ContentProvider content_provider,
- T is_shutting_down) {
+ T is_shutting_down, U &compressor) {
size_t offset = 0;
auto data_available = true;
ssize_t total_written_length = 0;
- while (data_available && !is_shutting_down()) {
- ssize_t written_length = 0;
+ auto ok = true;
+ DataSink data_sink;
+
+ data_sink.write = [&](const char *d, size_t l) {
+ if (!ok) { return; }
+
+ data_available = l > 0;
+ offset += l;
+
+ std::string payload;
+ if (!compressor.compress(d, l, false,
+ [&](const char *data, size_t data_len) {
+ payload.append(data, data_len);
+ return true;
+ })) {
+ ok = false;
+ return;
+ }
- DataSink data_sink;
- data_sink.write = [&](const char *d, size_t l) {
- data_available = l > 0;
- offset += l;
+ if (!payload.empty()) {
+ // Emit chunked response header and footer for each chunk
+ auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
+ if (write_data(strm, chunk.data(), chunk.size())) {
+ total_written_length += chunk.size();
+ } else {
+ ok = false;
+ return;
+ }
+ }
+ };
+ data_sink.done = [&](void) {
+ if (!ok) { return; }
+
+ data_available = false;
+
+ std::string payload;
+ if (!compressor.compress(nullptr, 0, true,
+ [&](const char *data, size_t data_len) {
+ payload.append(data, data_len);
+ return true;
+ })) {
+ ok = false;
+ return;
+ }
+
+ if (!payload.empty()) {
// Emit chunked response header and footer for each chunk
- auto chunk = from_i_to_hex(l) + "\r\n" + std::string(d, l) + "\r\n";
- written_length = strm.write(chunk);
- };
- data_sink.done = [&](void) {
- data_available = false;
- written_length = strm.write("0\r\n\r\n");
- };
- data_sink.is_writable = [&](void) { return strm.is_writable(); };
+ auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
+ if (write_data(strm, chunk.data(), chunk.size())) {
+ total_written_length += chunk.size();
+ } else {
+ ok = false;
+ return;
+ }
+ }
+
+ static const std::string done_marker("0\r\n\r\n");
+ if (write_data(strm, done_marker.data(), done_marker.size())) {
+ total_written_length += done_marker.size();
+ } else {
+ ok = false;
+ }
+ };
- content_provider(offset, 0, data_sink);
+ data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };
- if (written_length < 0) { return written_length; }
- total_written_length += written_length;
+ while (data_available && !is_shutting_down()) {
+ if (!content_provider(offset, 0, data_sink)) { return -1; }
+ if (!ok) { return -1; }
}
+
return total_written_length;
}
@@ -1994,6 +2820,12 @@ inline bool redirect(T &cli, const Request &req, Response &res,
new_req.path = path;
new_req.redirect_count -= 1;
+ if (res.status == 303 && (req.method != "GET" && req.method != "HEAD")) {
+ new_req.method = "GET";
+ new_req.body.clear();
+ new_req.headers.clear();
+ }
+
Response new_res;
auto ret = cli.send(new_req, new_res);
@@ -2001,75 +2833,20 @@ inline bool redirect(T &cli, const Request &req, Response &res,
return ret;
}
-inline std::string encode_url(const std::string &s) {
- std::string result;
-
- for (auto i = 0; s[i]; i++) {
- switch (s[i]) {
- case ' ': result += "%20"; break;
- case '+': result += "%2B"; break;
- case '\r': result += "%0D"; break;
- case '\n': result += "%0A"; break;
- case '\'': result += "%27"; break;
- case ',': result += "%2C"; break;
- // case ':': result += "%3A"; break; // ok? probably...
- case ';': result += "%3B"; break;
- default:
- auto c = static_cast<uint8_t>(s[i]);
- if (c >= 0x80) {
- result += '%';
- char hex[4];
- size_t len = snprintf(hex, sizeof(hex) - 1, "%02X", c);
- assert(len == 2);
- result.append(hex, len);
- } else {
- result += s[i];
- }
- break;
- }
- }
-
- return result;
-}
-
-inline std::string decode_url(const std::string &s) {
- std::string result;
+inline std::string params_to_query_str(const Params &params) {
+ std::string query;
- for (size_t i = 0; i < s.size(); i++) {
- if (s[i] == '%' && i + 1 < s.size()) {
- if (s[i + 1] == 'u') {
- int val = 0;
- if (from_hex_to_i(s, i + 2, 4, val)) {
- // 4 digits Unicode codes
- char buff[4];
- size_t len = to_utf8(val, buff);
- if (len > 0) { result.append(buff, len); }
- i += 5; // 'u0000'
- } else {
- result += s[i];
- }
- } else {
- int val = 0;
- if (from_hex_to_i(s, i + 1, 2, val)) {
- // 2 digits hex codes
- result += static_cast<char>(val);
- i += 2; // '00'
- } else {
- result += s[i];
- }
- }
- } else if (s[i] == '+') {
- result += ' ';
- } else {
- result += s[i];
- }
+ for (auto it = params.begin(); it != params.end(); ++it) {
+ if (it != params.begin()) { query += "&"; }
+ query += it->first;
+ query += "=";
+ query += encode_url(it->second);
}
-
- return result;
+ return query;
}
inline void parse_query_text(const std::string &s, Params &params) {
- split(&s[0], &s[s.size()], '&', [&](const char *b, const char *e) {
+ split(s.data(), s.data() + s.size(), '&', [&](const char *b, const char *e) {
std::string key;
std::string val;
split(b, e, '=', [&](const char *b2, const char *e2) {
@@ -2079,7 +2856,10 @@ inline void parse_query_text(const std::string &s, Params &params) {
val.assign(b2, e2);
}
});
- params.emplace(key, decode_url(val));
+
+ if (!key.empty()) {
+ params.emplace(decode_url(key, true), decode_url(val, true));
+ }
});
}
@@ -2087,17 +2867,20 @@ inline bool parse_multipart_boundary(const std::string &content_type,
std::string &boundary) {
auto pos = content_type.find("boundary=");
if (pos == std::string::npos) { return false; }
-
boundary = content_type.substr(pos + 9);
- return true;
+ if (boundary.length() >= 2 && boundary.front() == '"' &&
+ boundary.back() == '"') {
+ boundary = boundary.substr(1, boundary.size() - 2);
+ }
+ return !boundary.empty();
}
inline bool parse_range_header(const std::string &s, Ranges &ranges) {
static auto re_first_range = std::regex(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))");
std::smatch m;
if (std::regex_match(s, m, re_first_range)) {
- auto pos = m.position(1);
- auto len = m.length(1);
+ auto pos = static_cast<size_t>(m.position(1));
+ auto len = static_cast<size_t>(m.length(1));
bool all_valid_ranges = true;
split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) {
if (!all_valid_ranges) return;
@@ -2128,21 +2911,21 @@ inline bool parse_range_header(const std::string &s, Ranges &ranges) {
class MultipartFormDataParser {
public:
- MultipartFormDataParser() {}
+ MultipartFormDataParser() = default;
- void set_boundary(const std::string &boundary) { boundary_ = boundary; }
+ void set_boundary(std::string &&boundary) { boundary_ = boundary; }
bool is_valid() const { return is_valid_; }
template <typename T, typename U>
bool parse(const char *buf, size_t n, T content_callback, U header_callback) {
- static const std::regex re_content_type(R"(^Content-Type:\s*(.*?)\s*$)",
- std::regex_constants::icase);
static const std::regex re_content_disposition(
"^Content-Disposition:\\s*form-data;\\s*name=\"(.*?)\"(?:;\\s*filename="
"\"(.*?)\")?\\s*$",
std::regex_constants::icase);
+ static const std::string dash_ = "--";
+ static const std::string crlf_ = "\r\n";
buf_.append(buf, n); // TODO: performance improvement
@@ -2152,10 +2935,7 @@ public:
auto pattern = dash_ + boundary_ + crlf_;
if (pattern.size() > buf_.size()) { return true; }
auto pos = buf_.find(pattern);
- if (pos != 0) {
- is_done_ = true;
- return false;
- }
+ if (pos != 0) { return false; }
buf_.erase(0, pattern.size());
off_ += pattern.size();
state_ = 1;
@@ -2173,7 +2953,6 @@ public:
if (pos == 0) {
if (!header_callback(file_)) {
is_valid_ = false;
- is_done_ = false;
return false;
}
buf_.erase(0, crlf_.size());
@@ -2182,12 +2961,13 @@ public:
break;
}
- auto header = buf_.substr(0, pos);
- {
+ static const std::string header_name = "content-type:";
+ const auto header = buf_.substr(0, pos);
+ if (start_with(header, header_name)) {
+ file_.content_type = trim_copy(header.substr(header_name.size()));
+ } else {
std::smatch m;
- if (std::regex_match(header, m, re_content_type)) {
- file_.content_type = m[1];
- } else if (std::regex_match(header, m, re_content_disposition)) {
+ if (std::regex_match(header, m, re_content_disposition)) {
file_.name = m[1];
file_.filename = m[2];
}
@@ -2197,6 +2977,7 @@ public:
off_ += pos + crlf_.size();
pos = buf_.find(crlf_);
}
+ if (state_ != 3) { return true; }
break;
}
case 3: { // Body
@@ -2205,10 +2986,17 @@ public:
if (pattern.size() > buf_.size()) { return true; }
auto pos = buf_.find(pattern);
- if (pos == std::string::npos) { pos = buf_.size(); }
+ if (pos == std::string::npos) {
+ pos = buf_.size();
+ while (pos > 0) {
+ auto c = buf_[pos - 1];
+ if (c != '\r' && c != '\n' && c != '-') { break; }
+ pos--;
+ }
+ }
+
if (!content_callback(buf_.data(), pos)) {
is_valid_ = false;
- is_done_ = false;
return false;
}
@@ -2224,7 +3012,6 @@ public:
if (pos != std::string::npos) {
if (!content_callback(buf_.data(), pos)) {
is_valid_ = false;
- is_done_ = false;
return false;
}
@@ -2234,7 +3021,6 @@ public:
} else {
if (!content_callback(buf_.data(), pattern.size())) {
is_valid_ = false;
- is_done_ = false;
return false;
}
@@ -2246,20 +3032,19 @@ public:
}
case 4: { // Boundary
if (crlf_.size() > buf_.size()) { return true; }
- if (buf_.find(crlf_) == 0) {
+ if (buf_.compare(0, crlf_.size(), crlf_) == 0) {
buf_.erase(0, crlf_.size());
off_ += crlf_.size();
state_ = 1;
} else {
auto pattern = dash_ + crlf_;
if (pattern.size() > buf_.size()) { return true; }
- if (buf_.find(pattern) == 0) {
+ if (buf_.compare(0, pattern.size(), pattern) == 0) {
buf_.erase(0, pattern.size());
off_ += pattern.size();
is_valid_ = true;
state_ = 5;
} else {
- is_done_ = true;
return true;
}
}
@@ -2282,14 +3067,11 @@ private:
file_.content_type.clear();
}
- const std::string dash_ = "--";
- const std::string crlf_ = "\r\n";
std::string boundary_;
std::string buf_;
size_t state_ = 0;
- size_t is_valid_ = false;
- size_t is_done_ = false;
+ bool is_valid_ = false;
size_t off_ = 0;
MultipartFormData file_;
};
@@ -2329,12 +3111,14 @@ get_range_offset_and_length(const Request &req, size_t content_length,
return std::make_pair(0, content_length);
}
+ auto slen = static_cast<ssize_t>(content_length);
+
if (r.first == -1) {
- r.first = content_length - r.second;
- r.second = content_length - 1;
+ r.first = slen - r.second;
+ r.second = slen - 1;
}
- if (r.second == -1) { r.second = content_length - 1; }
+ if (r.second == -1) { r.second = slen - 1; }
return std::make_pair(r.first, r.second - r.first + 1);
}
@@ -2420,16 +3204,19 @@ get_multipart_ranges_data_length(const Request &req, Response &res,
return data_length;
}
+template <typename T>
inline bool write_multipart_ranges_data(Stream &strm, const Request &req,
Response &res,
const std::string &boundary,
- const std::string &content_type) {
+ const std::string &content_type,
+ T is_shutting_down) {
return process_multipart_ranges_data(
req, res, boundary, content_type,
[&](const std::string &token) { strm.write(token); },
[&](const char *token) { strm.write(token); },
[&](size_t offset, size_t length) {
- return write_content(strm, res.content_provider, offset, length) >= 0;
+ return write_content(strm, res.content_provider_, offset, length,
+ is_shutting_down) >= 0;
});
}
@@ -2438,20 +3225,31 @@ get_range_offset_and_length(const Request &req, const Response &res,
size_t index) {
auto r = req.ranges[index];
- if (r.second == -1) { r.second = res.content_length - 1; }
+ if (r.second == -1) {
+ r.second = static_cast<ssize_t>(res.content_length_) - 1;
+ }
return std::make_pair(r.first, r.second - r.first + 1);
}
inline bool expect_content(const Request &req) {
if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" ||
- req.method == "PRI") {
+ req.method == "PRI" || req.method == "DELETE") {
return true;
}
// TODO: check if Content-Length is set
return false;
}
+inline bool has_crlf(const char *s) {
+ auto p = s;
+ while (*p) {
+ if (*p == '\r' || *p == '\n') { return true; }
+ p++;
+ }
+ return false;
+}
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
template <typename CTX, typename Init, typename Update, typename Final>
inline std::string message_digest(const std::string &s, Init init,
@@ -2489,6 +3287,33 @@ inline std::string SHA_512(const std::string &s) {
#endif
#ifdef _WIN32
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+// NOTE: This code came up with the following stackoverflow post:
+// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
+inline bool load_system_certs_on_windows(X509_STORE *store) {
+ auto hStore = CertOpenSystemStoreW((HCRYPTPROV_LEGACY)NULL, L"ROOT");
+
+ if (!hStore) { return false; }
+
+ PCCERT_CONTEXT pContext = NULL;
+ while (pContext = CertEnumCertificatesInStore(hStore, pContext)) {
+ auto encoded_cert =
+ static_cast<const unsigned char *>(pContext->pbCertEncoded);
+
+ auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
+ if (x509) {
+ X509_STORE_add_cert(store, x509);
+ X509_free(x509);
+ }
+ }
+
+ CertFreeCertificateContext(pContext);
+ CertCloseStore(hStore, 0);
+
+ return true;
+}
+#endif
+
class WSInit {
public:
WSInit() {
@@ -2502,31 +3327,6 @@ public:
static WSInit wsinit_;
#endif
-} // namespace detail
-
-// Header utilities
-inline std::pair<std::string, std::string> make_range_header(Ranges ranges) {
- std::string field = "bytes=";
- auto i = 0;
- for (auto r : ranges) {
- if (i != 0) { field += ", "; }
- if (r.first != -1) { field += std::to_string(r.first); }
- field += '-';
- if (r.second != -1) { field += std::to_string(r.second); }
- i++;
- }
- return std::make_pair("Range", field);
-}
-
-inline std::pair<std::string, std::string>
-make_basic_authentication_header(const std::string &username,
- const std::string &password,
- bool is_proxy = false) {
- auto field = "Basic " + detail::base64_encode(username + ":" + password);
- auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
- return std::make_pair(key, field);
-}
-
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline std::pair<std::string, std::string> make_digest_authentication_header(
const Request &req, const std::map<std::string, std::string> &auth,
@@ -2566,17 +3366,18 @@ inline std::pair<std::string, std::string> make_digest_authentication_header(
":" + qop + ":" + H(A2));
}
- auto field = "Digest username=\"hello\", realm=\"" + auth.at("realm") +
- "\", nonce=\"" + auth.at("nonce") + "\", uri=\"" + req.path +
- "\", algorithm=" + algo + ", qop=" + qop + ", nc=\"" + nc +
- "\", cnonce=\"" + cnonce + "\", response=\"" + response + "\"";
+ auto field = "Digest username=\"" + username + "\", realm=\"" +
+ auth.at("realm") + "\", nonce=\"" + auth.at("nonce") +
+ "\", uri=\"" + req.path + "\", algorithm=" + algo +
+ ", qop=" + qop + ", nc=\"" + nc + "\", cnonce=\"" + cnonce +
+ "\", response=\"" + response + "\"";
auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
return std::make_pair(key, field);
}
#endif
-inline bool parse_www_authenticate(const httplib::Response &res,
+inline bool parse_www_authenticate(const Response &res,
std::map<std::string, std::string> &auth,
bool is_proxy) {
auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
@@ -2593,9 +3394,13 @@ inline bool parse_www_authenticate(const httplib::Response &res,
auto beg = std::sregex_iterator(s.begin(), s.end(), re);
for (auto i = beg; i != std::sregex_iterator(); ++i) {
auto m = *i;
- auto key = s.substr(m.position(1), m.length(1));
- auto val = m.length(2) > 0 ? s.substr(m.position(2), m.length(2))
- : s.substr(m.position(3), m.length(3));
+ auto key = s.substr(static_cast<size_t>(m.position(1)),
+ static_cast<size_t>(m.length(1)));
+ auto val = m.length(2) > 0
+ ? s.substr(static_cast<size_t>(m.position(2)),
+ static_cast<size_t>(m.length(2)))
+ : s.substr(static_cast<size_t>(m.position(3)),
+ static_cast<size_t>(m.length(3)));
auth[key] = val;
}
return true;
@@ -2612,13 +3417,60 @@ inline std::string random_string(size_t length) {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
- return charset[rand() % max_index];
+ return charset[static_cast<size_t>(rand()) % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
}
+class ContentProviderAdapter {
+public:
+ explicit ContentProviderAdapter(
+ ContentProviderWithoutLength &&content_provider)
+ : content_provider_(content_provider) {}
+
+ bool operator()(size_t offset, size_t, DataSink &sink) {
+ return content_provider_(offset, sink);
+ }
+
+private:
+ ContentProviderWithoutLength content_provider_;
+};
+
+} // namespace detail
+
+// Header utilities
+inline std::pair<std::string, std::string> make_range_header(Ranges ranges) {
+ std::string field = "bytes=";
+ auto i = 0;
+ for (auto r : ranges) {
+ if (i != 0) { field += ", "; }
+ if (r.first != -1) { field += std::to_string(r.first); }
+ field += '-';
+ if (r.second != -1) { field += std::to_string(r.second); }
+ i++;
+ }
+ return std::make_pair("Range", field);
+}
+
+inline std::pair<std::string, std::string>
+make_basic_authentication_header(const std::string &username,
+ const std::string &password,
+ bool is_proxy = false) {
+ auto field = "Basic " + detail::base64_encode(username + ":" + password);
+ auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
+ return std::make_pair(key, field);
+}
+
+inline std::pair<std::string, std::string>
+make_bearer_token_authentication_header(const std::string &token,
+ bool is_proxy = false) {
+ auto field = "Bearer " + token;
+ auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
+ return std::make_pair(key, field);
+}
+
// Request implementation
inline bool Request::has_header(const char *key) const {
return detail::has_header(headers, key);
@@ -2628,17 +3480,26 @@ inline std::string Request::get_header_value(const char *key, size_t id) const {
return detail::get_header_value(headers, key, id, "");
}
+template <typename T>
+inline T Request::get_header_value(const char *key, size_t id) const {
+ return detail::get_header_value<T>(headers, key, id, 0);
+}
+
inline size_t Request::get_header_value_count(const char *key) const {
auto r = headers.equal_range(key);
- return std::distance(r.first, r.second);
+ return static_cast<size_t>(std::distance(r.first, r.second));
}
inline void Request::set_header(const char *key, const char *val) {
- headers.emplace(key, val);
+ if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
+ headers.emplace(key, val);
+ }
}
inline void Request::set_header(const char *key, const std::string &val) {
- headers.emplace(key, val);
+ if (!detail::has_crlf(key) && !detail::has_crlf(val.c_str())) {
+ headers.emplace(key, val);
+ }
}
inline bool Request::has_param(const char *key) const {
@@ -2646,15 +3507,16 @@ inline bool Request::has_param(const char *key) const {
}
inline std::string Request::get_param_value(const char *key, size_t id) const {
- auto it = params.find(key);
- std::advance(it, id);
- if (it != params.end()) { return it->second; }
+ auto rng = params.equal_range(key);
+ auto it = rng.first;
+ std::advance(it, static_cast<ssize_t>(id));
+ if (it != rng.second) { return it->second; }
return std::string();
}
inline size_t Request::get_param_value_count(const char *key) const {
auto r = params.equal_range(key);
- return std::distance(r.first, r.second);
+ return static_cast<size_t>(std::distance(r.first, r.second));
}
inline bool Request::is_multipart_form_data() const {
@@ -2682,22 +3544,41 @@ inline std::string Response::get_header_value(const char *key,
return detail::get_header_value(headers, key, id, "");
}
+template <typename T>
+inline T Response::get_header_value(const char *key, size_t id) const {
+ return detail::get_header_value<T>(headers, key, id, 0);
+}
+
inline size_t Response::get_header_value_count(const char *key) const {
auto r = headers.equal_range(key);
- return std::distance(r.first, r.second);
+ return static_cast<size_t>(std::distance(r.first, r.second));
}
inline void Response::set_header(const char *key, const char *val) {
- headers.emplace(key, val);
+ if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
+ headers.emplace(key, val);
+ }
}
inline void Response::set_header(const char *key, const std::string &val) {
- headers.emplace(key, val);
+ if (!detail::has_crlf(key) && !detail::has_crlf(val.c_str())) {
+ headers.emplace(key, val);
+ }
+}
+
+inline void Response::set_redirect(const char *url, int stat) {
+ if (!detail::has_crlf(url)) {
+ set_header("Location", url);
+ if (300 <= stat && stat < 400) {
+ this->status = stat;
+ } else {
+ this->status = 302;
+ }
+ }
}
-inline void Response::set_redirect(const char *url) {
- set_header("Location", url);
- status = 302;
+inline void Response::set_redirect(const std::string &url, int stat) {
+ set_redirect(url.c_str(), stat);
}
inline void Response::set_content(const char *s, size_t n,
@@ -2706,62 +3587,79 @@ inline void Response::set_content(const char *s, size_t n,
set_header("Content-Type", content_type);
}
-inline void Response::set_content(const std::string &s,
- const char *content_type) {
- body = s;
+inline void Response::set_content(std::string s, const char *content_type) {
+ body = std::move(s);
set_header("Content-Type", content_type);
}
-inline void Response::set_content_provider(
- size_t in_length,
- std::function<void(size_t offset, size_t length, DataSink &sink)> provider,
- std::function<void()> resource_releaser) {
+inline void
+Response::set_content_provider(size_t in_length, const char *content_type,
+ ContentProvider provider,
+ const std::function<void()> &resource_releaser) {
assert(in_length > 0);
- content_length = in_length;
- content_provider = [provider](size_t offset, size_t length, DataSink &sink) {
- provider(offset, length, sink);
- };
- content_provider_resource_releaser = resource_releaser;
+ set_header("Content-Type", content_type);
+ content_length_ = in_length;
+ content_provider_ = std::move(provider);
+ content_provider_resource_releaser_ = resource_releaser;
+ is_chunked_content_provider = false;
+}
+
+inline void
+Response::set_content_provider(const char *content_type,
+ ContentProviderWithoutLength provider,
+ const std::function<void()> &resource_releaser) {
+ set_header("Content-Type", content_type);
+ content_length_ = 0;
+ content_provider_ = detail::ContentProviderAdapter(std::move(provider));
+ content_provider_resource_releaser_ = resource_releaser;
+ is_chunked_content_provider = false;
}
inline void Response::set_chunked_content_provider(
- std::function<void(size_t offset, DataSink &sink)> provider,
- std::function<void()> resource_releaser) {
- content_length = 0;
- content_provider = [provider](size_t offset, size_t, DataSink &sink) {
- provider(offset, sink);
- };
- content_provider_resource_releaser = resource_releaser;
+ const char *content_type, ContentProviderWithoutLength provider,
+ const std::function<void()> &resource_releaser) {
+ set_header("Content-Type", content_type);
+ content_length_ = 0;
+ content_provider_ = detail::ContentProviderAdapter(std::move(provider));
+ content_provider_resource_releaser_ = resource_releaser;
+ is_chunked_content_provider = true;
}
// Rstream implementation
-inline int Stream::write(const char *ptr) { return write(ptr, strlen(ptr)); }
+inline ssize_t Stream::write(const char *ptr) {
+ return write(ptr, strlen(ptr));
+}
-inline int Stream::write(const std::string &s) {
+inline ssize_t Stream::write(const std::string &s) {
return write(s.data(), s.size());
}
template <typename... Args>
-inline int Stream::write_format(const char *fmt, const Args &... args) {
- std::array<char, 2048> buf;
+inline ssize_t Stream::write_format(const char *fmt, const Args &... args) {
+ const auto bufsiz = 2048;
+ std::array<char, bufsiz> buf;
#if defined(_MSC_VER) && _MSC_VER < 1900
- auto n = _snprintf_s(buf, bufsiz, buf.size() - 1, fmt, args...);
+ auto sn = _snprintf_s(buf.data(), bufsiz - 1, buf.size() - 1, fmt, args...);
#else
- auto n = snprintf(buf.data(), buf.size() - 1, fmt, args...);
+ auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...);
#endif
- if (n <= 0) { return n; }
+ if (sn <= 0) { return sn; }
- if (n >= static_cast<int>(buf.size()) - 1) {
+ auto n = static_cast<size_t>(sn);
+
+ if (n >= buf.size() - 1) {
std::vector<char> glowable_buf(buf.size());
- while (n >= static_cast<int>(glowable_buf.size() - 1)) {
+ while (n >= glowable_buf.size() - 1) {
glowable_buf.resize(glowable_buf.size() * 2);
#if defined(_MSC_VER) && _MSC_VER < 1900
- n = _snprintf_s(&glowable_buf[0], glowable_buf.size(),
- glowable_buf.size() - 1, fmt, args...);
+ n = static_cast<size_t>(_snprintf_s(&glowable_buf[0], glowable_buf.size(),
+ glowable_buf.size() - 1, fmt,
+ args...));
#else
- n = snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...);
+ n = static_cast<size_t>(
+ snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...));
#endif
}
return write(&glowable_buf[0], n);
@@ -2774,32 +3672,53 @@ namespace detail {
// Socket stream implementation
inline SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec,
- time_t read_timeout_usec)
+ time_t read_timeout_usec,
+ time_t write_timeout_sec,
+ time_t write_timeout_usec)
: sock_(sock), read_timeout_sec_(read_timeout_sec),
- read_timeout_usec_(read_timeout_usec) {}
+ read_timeout_usec_(read_timeout_usec),
+ write_timeout_sec_(write_timeout_sec),
+ write_timeout_usec_(write_timeout_usec) {}
inline SocketStream::~SocketStream() {}
inline bool SocketStream::is_readable() const {
- return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
+ return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
}
inline bool SocketStream::is_writable() const {
- return detail::select_write(sock_, 0, 0) > 0;
+ return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0;
}
-inline int SocketStream::read(char *ptr, size_t size) {
- if (is_readable()) { return recv(sock_, ptr, static_cast<int>(size), 0); }
- return -1;
+inline ssize_t SocketStream::read(char *ptr, size_t size) {
+ if (!is_readable()) { return -1; }
+
+#ifdef _WIN32
+ if (size > static_cast<size_t>((std::numeric_limits<int>::max)())) {
+ return -1;
+ }
+ return recv(sock_, ptr, static_cast<int>(size), 0);
+#else
+ return handle_EINTR([&]() { return recv(sock_, ptr, size, 0); });
+#endif
}
-inline int SocketStream::write(const char *ptr, size_t size) {
- if (is_writable()) { return send(sock_, ptr, static_cast<int>(size), 0); }
- return -1;
+inline ssize_t SocketStream::write(const char *ptr, size_t size) {
+ if (!is_writable()) { return -1; }
+
+#ifdef _WIN32
+ if (size > static_cast<size_t>((std::numeric_limits<int>::max)())) {
+ return -1;
+ }
+ return send(sock_, ptr, static_cast<int>(size), 0);
+#else
+ return handle_EINTR([&]() { return send(sock_, ptr, size, 0); });
+#endif
}
-inline std::string SocketStream::get_remote_addr() const {
- return detail::get_remote_addr(sock_);
+inline void SocketStream::get_remote_ip_and_port(std::string &ip,
+ int &port) const {
+ return detail::get_remote_ip_and_port(sock_, ip, port);
}
// Buffer stream implementation
@@ -2807,22 +3726,23 @@ inline bool BufferStream::is_readable() const { return true; }
inline bool BufferStream::is_writable() const { return true; }
-inline int BufferStream::read(char *ptr, size_t size) {
-#if defined(_MSC_VER) && _MSC_VER < 1900
- int len_read = static_cast<int>(buffer._Copy_s(ptr, size, size, position));
+inline ssize_t BufferStream::read(char *ptr, size_t size) {
+#if defined(_MSC_VER) && _MSC_VER <= 1900
+ auto len_read = buffer._Copy_s(ptr, size, size, position);
#else
- int len_read = static_cast<int>(buffer.copy(ptr, size, position));
+ auto len_read = buffer.copy(ptr, size, position);
#endif
- position += len_read;
- return len_read;
+ position += static_cast<size_t>(len_read);
+ return static_cast<ssize_t>(len_read);
}
-inline int BufferStream::write(const char *ptr, size_t size) {
+inline ssize_t BufferStream::write(const char *ptr, size_t size) {
buffer.append(ptr, size);
- return static_cast<int>(size);
+ return static_cast<ssize_t>(size);
}
-inline std::string BufferStream::get_remote_addr() const { return ""; }
+inline void BufferStream::get_remote_ip_and_port(std::string & /*ip*/,
+ int & /*port*/) const {}
inline const std::string &BufferStream::get_buffer() const { return buffer; }
@@ -2830,15 +3750,12 @@ inline const std::string &BufferStream::get_buffer() const { return buffer; }
// HTTP server implementation
inline Server::Server()
- : keep_alive_max_count_(CPPHTTPLIB_KEEPALIVE_MAX_COUNT),
- read_timeout_sec_(CPPHTTPLIB_READ_TIMEOUT_SECOND),
- read_timeout_usec_(CPPHTTPLIB_READ_TIMEOUT_USECOND),
- payload_max_length_(CPPHTTPLIB_PAYLOAD_MAX_LENGTH), is_running_(false),
- svr_sock_(INVALID_SOCKET) {
+ : new_task_queue(
+ [] { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); }),
+ svr_sock_(INVALID_SOCKET), is_running_(false) {
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
- new_task_queue = [] { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); };
}
inline Server::~Server() {}
@@ -2889,6 +3806,13 @@ inline Server &Server::Delete(const char *pattern, Handler handler) {
return *this;
}
+inline Server &Server::Delete(const char *pattern,
+ HandlerWithContentReader handler) {
+ delete_handlers_for_content_reader_.push_back(
+ std::make_pair(std::regex(pattern), handler));
+ return *this;
+}
+
inline Server &Server::Options(const char *pattern, Handler handler) {
options_handlers_.push_back(std::make_pair(std::regex(pattern), handler));
return *this;
@@ -2898,11 +3822,12 @@ inline bool Server::set_base_dir(const char *dir, const char *mount_point) {
return set_mount_point(mount_point, dir);
}
-inline bool Server::set_mount_point(const char *mount_point, const char *dir) {
+inline bool Server::set_mount_point(const char *mount_point, const char *dir,
+ Headers headers) {
if (detail::is_dir(dir)) {
std::string mnt = mount_point ? mount_point : "/";
if (!mnt.empty() && mnt[0] == '/') {
- base_dirs_.emplace_back(mnt, dir);
+ base_dirs_.push_back({mnt, dir, std::move(headers)});
return true;
}
}
@@ -2911,7 +3836,7 @@ inline bool Server::set_mount_point(const char *mount_point, const char *dir) {
inline bool Server::remove_mount_point(const char *mount_point) {
for (auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it) {
- if (it->first == mount_point) {
+ if (it->mount_point == mount_point) {
base_dirs_.erase(it);
return true;
}
@@ -2932,6 +3857,12 @@ inline void Server::set_error_handler(Handler handler) {
error_handler_ = std::move(handler);
}
+inline void Server::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; }
+
+inline void Server::set_socket_options(SocketOptions socket_options) {
+ socket_options_ = socket_options;
+}
+
inline void Server::set_logger(Logger logger) { logger_ = std::move(logger); }
inline void
@@ -2943,11 +3874,25 @@ inline void Server::set_keep_alive_max_count(size_t count) {
keep_alive_max_count_ = count;
}
+inline void Server::set_keep_alive_timeout(time_t sec) {
+ keep_alive_timeout_sec_ = sec;
+}
+
inline void Server::set_read_timeout(time_t sec, time_t usec) {
read_timeout_sec_ = sec;
read_timeout_usec_ = usec;
}
+inline void Server::set_write_timeout(time_t sec, time_t usec) {
+ write_timeout_sec_ = sec;
+ write_timeout_usec_ = usec;
+}
+
+inline void Server::set_idle_interval(time_t sec, time_t usec) {
+ idle_interval_sec_ = sec;
+ idle_interval_usec_ = usec;
+}
+
inline void Server::set_payload_max_length(size_t length) {
payload_max_length_ = length;
}
@@ -2987,7 +3932,7 @@ inline bool Server::parse_request_line(const char *s, Request &req) {
req.version = std::string(m[5]);
req.method = std::string(m[1]);
req.target = std::string(m[2]);
- req.path = detail::decode_url(m[3]);
+ req.path = detail::decode_url(m[3], false);
// Parse query text
auto len = std::distance(m[4].first, m[4].second);
@@ -2999,7 +3944,7 @@ inline bool Server::parse_request_line(const char *s, Request &req) {
return false;
}
-inline bool Server::write_response(Stream &strm, bool last_connection,
+inline bool Server::write_response(Stream &strm, bool close_connection,
const Request &req, Response &res) {
assert(res.status != -1);
@@ -3014,16 +3959,17 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
}
// Headers
- if (last_connection || req.get_header_value("Connection") == "close") {
+ if (close_connection || req.get_header_value("Connection") == "close") {
res.set_header("Connection", "close");
- }
-
- if (!last_connection && req.get_header_value("Connection") == "Keep-Alive") {
- res.set_header("Connection", "Keep-Alive");
+ } else {
+ std::stringstream ss;
+ ss << "timeout=" << keep_alive_timeout_sec_
+ << ", max=" << keep_alive_max_count_;
+ res.set_header("Keep-Alive", ss.str());
}
if (!res.has_header("Content-Type") &&
- (!res.body.empty() || res.content_length > 0)) {
+ (!res.body.empty() || res.content_length_ > 0 || res.content_provider_)) {
res.set_header("Content-Type", "text/plain");
}
@@ -3047,18 +3993,20 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
"multipart/byteranges; boundary=" + boundary);
}
+ auto type = detail::encoding_type(req, res);
+
if (res.body.empty()) {
- if (res.content_length > 0) {
+ if (res.content_length_ > 0) {
size_t length = 0;
if (req.ranges.empty()) {
- length = res.content_length;
+ length = res.content_length_;
} else if (req.ranges.size() == 1) {
auto offsets =
- detail::get_range_offset_and_length(req, res.content_length, 0);
+ detail::get_range_offset_and_length(req, res.content_length_, 0);
auto offset = offsets.first;
length = offsets.second;
auto content_range = detail::make_content_range_header_field(
- offset, length, res.content_length);
+ offset, length, res.content_length_);
res.set_header("Content-Range", content_range);
} else {
length = detail::get_multipart_ranges_data_length(req, res, boundary,
@@ -3066,8 +4014,15 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
}
res.set_header("Content-Length", std::to_string(length));
} else {
- if (res.content_provider) {
- res.set_header("Transfer-Encoding", "chunked");
+ if (res.content_provider_) {
+ if (res.is_chunked_content_provider) {
+ res.set_header("Transfer-Encoding", "chunked");
+ if (type == detail::EncodingType::Gzip) {
+ res.set_header("Content-Encoding", "gzip");
+ } else if (type == detail::EncodingType::Brotli) {
+ res.set_header("Content-Encoding", "br");
+ }
+ }
} else {
res.set_header("Content-Length", "0");
}
@@ -3089,16 +4044,35 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
detail::make_multipart_ranges_data(req, res, boundary, content_type);
}
+ if (type != detail::EncodingType::None) {
+ std::shared_ptr<detail::compressor> compressor;
+
+ if (type == detail::EncodingType::Gzip) {
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
- // TODO: 'Accept-Encoding' has gzip, not gzip;q=0
- const auto &encodings = req.get_header_value("Accept-Encoding");
- if (encodings.find("gzip") != std::string::npos &&
- detail::can_compress(res.get_header_value("Content-Type"))) {
- if (detail::compress(res.body)) {
+ compressor = std::make_shared<detail::gzip_compressor>();
res.set_header("Content-Encoding", "gzip");
+#endif
+ } else if (type == detail::EncodingType::Brotli) {
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+ compressor = std::make_shared<detail::brotli_compressor>();
+ res.set_header("Content-Encoding", "brotli");
+#endif
+ }
+
+ if (compressor) {
+ std::string compressed;
+
+ if (!compressor->compress(res.body.data(), res.body.size(), true,
+ [&](const char *data, size_t data_len) {
+ compressed.append(data, data_len);
+ return true;
+ })) {
+ return false;
+ }
+
+ res.body.swap(compressed);
}
}
-#endif
auto length = std::to_string(res.body.size());
res.set_header("Content-Length", length);
@@ -3111,13 +4085,14 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
strm.write(data.data(), data.size());
// Body
+ auto ret = true;
if (req.method != "HEAD") {
if (!res.body.empty()) {
- if (!strm.write(res.body)) { return false; }
- } else if (res.content_provider) {
+ if (!strm.write(res.body)) { ret = false; }
+ } else if (res.content_provider_) {
if (!write_content_with_provider(strm, req, res, boundary,
content_type)) {
- return false;
+ ret = false;
}
}
}
@@ -3125,87 +4100,109 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
// Log
if (logger_) { logger_(req, res); }
- return true;
+ return ret;
}
inline bool
Server::write_content_with_provider(Stream &strm, const Request &req,
Response &res, const std::string &boundary,
const std::string &content_type) {
- if (res.content_length) {
+ auto is_shutting_down = [this]() {
+ return this->svr_sock_ == INVALID_SOCKET;
+ };
+
+ if (res.content_length_ > 0) {
if (req.ranges.empty()) {
- if (detail::write_content(strm, res.content_provider, 0,
- res.content_length) < 0) {
+ if (detail::write_content(strm, res.content_provider_, 0,
+ res.content_length_, is_shutting_down) < 0) {
return false;
}
} else if (req.ranges.size() == 1) {
auto offsets =
- detail::get_range_offset_and_length(req, res.content_length, 0);
+ detail::get_range_offset_and_length(req, res.content_length_, 0);
auto offset = offsets.first;
auto length = offsets.second;
- if (detail::write_content(strm, res.content_provider, offset, length) <
- 0) {
+ if (detail::write_content(strm, res.content_provider_, offset, length,
+ is_shutting_down) < 0) {
return false;
}
} else {
- if (!detail::write_multipart_ranges_data(strm, req, res, boundary,
- content_type)) {
+ if (!detail::write_multipart_ranges_data(
+ strm, req, res, boundary, content_type, is_shutting_down)) {
return false;
}
}
} else {
- auto is_shutting_down = [this]() {
- return this->svr_sock_ == INVALID_SOCKET;
- };
- if (detail::write_content_chunked(strm, res.content_provider,
- is_shutting_down) < 0) {
- return false;
+ if (res.is_chunked_content_provider) {
+ auto type = detail::encoding_type(req, res);
+
+ std::shared_ptr<detail::compressor> compressor;
+ if (type == detail::EncodingType::Gzip) {
+#ifdef CPPHTTPLIB_ZLIB_SUPPORT
+ compressor = std::make_shared<detail::gzip_compressor>();
+#endif
+ } else if (type == detail::EncodingType::Brotli) {
+#ifdef CPPHTTPLIB_BROTLI_SUPPORT
+ compressor = std::make_shared<detail::brotli_compressor>();
+#endif
+ } else {
+ compressor = std::make_shared<detail::nocompressor>();
+ }
+ assert(compressor != nullptr);
+
+ if (detail::write_content_chunked(strm, res.content_provider_,
+ is_shutting_down, *compressor) < 0) {
+ return false;
+ }
+ } else {
+ if (detail::write_content_without_length(strm, res.content_provider_,
+ is_shutting_down) < 0) {
+ return false;
+ }
}
}
return true;
}
-inline bool Server::read_content(Stream &strm, bool last_connection,
- Request &req, Response &res) {
+inline bool Server::read_content(Stream &strm, Request &req, Response &res) {
MultipartFormDataMap::iterator cur;
- auto ret = read_content_core(
- strm, last_connection, req, res,
- // Regular
- [&](const char *buf, size_t n) {
- if (req.body.size() + n > req.body.max_size()) { return false; }
- req.body.append(buf, n);
- return true;
- },
- // Multipart
- [&](const MultipartFormData &file) {
- cur = req.files.emplace(file.name, file);
- return true;
- },
- [&](const char *buf, size_t n) {
- auto &content = cur->second.content;
- if (content.size() + n > content.max_size()) { return false; }
- content.append(buf, n);
- return true;
- });
-
- const auto &content_type = req.get_header_value("Content-Type");
- if (!content_type.find("application/x-www-form-urlencoded")) {
- detail::parse_query_text(req.body, req.params);
+ if (read_content_core(
+ strm, req, res,
+ // Regular
+ [&](const char *buf, size_t n) {
+ if (req.body.size() + n > req.body.max_size()) { return false; }
+ req.body.append(buf, n);
+ return true;
+ },
+ // Multipart
+ [&](const MultipartFormData &file) {
+ cur = req.files.emplace(file.name, file);
+ return true;
+ },
+ [&](const char *buf, size_t n) {
+ auto &content = cur->second.content;
+ if (content.size() + n > content.max_size()) { return false; }
+ content.append(buf, n);
+ return true;
+ })) {
+ const auto &content_type = req.get_header_value("Content-Type");
+ if (!content_type.find("application/x-www-form-urlencoded")) {
+ detail::parse_query_text(req.body, req.params);
+ }
+ return true;
}
-
- return ret;
+ return false;
}
inline bool Server::read_content_with_content_receiver(
- Stream &strm, bool last_connection, Request &req, Response &res,
- ContentReceiver receiver, MultipartContentHeader multipart_header,
+ Stream &strm, Request &req, Response &res, ContentReceiver receiver,
+ MultipartContentHeader multipart_header,
ContentReceiver multipart_receiver) {
- return read_content_core(strm, last_connection, req, res, receiver,
- multipart_header, multipart_receiver);
+ return read_content_core(strm, req, res, receiver, multipart_header,
+ multipart_receiver);
}
-inline bool Server::read_content_core(Stream &strm, bool last_connection,
- Request &req, Response &res,
+inline bool Server::read_content_core(Stream &strm, Request &req, Response &res,
ContentReceiver receiver,
MultipartContentHeader mulitpart_header,
ContentReceiver multipart_receiver) {
@@ -3217,11 +4214,22 @@ inline bool Server::read_content_core(Stream &strm, bool last_connection,
std::string boundary;
if (!detail::parse_multipart_boundary(content_type, boundary)) {
res.status = 400;
- return write_response(strm, last_connection, req, res);
+ return false;
}
- multipart_form_data_parser.set_boundary(boundary);
+ multipart_form_data_parser.set_boundary(std::move(boundary));
out = [&](const char *buf, size_t n) {
+ /* For debug
+ size_t pos = 0;
+ while (pos < n) {
+ auto read_size = std::min<size_t>(1, n - pos);
+ auto ret = multipart_form_data_parser.parse(
+ buf + pos, read_size, multipart_receiver, mulitpart_header);
+ if (!ret) { return false; }
+ pos += read_size;
+ }
+ return true;
+ */
return multipart_form_data_parser.parse(buf, n, multipart_receiver,
mulitpart_header);
};
@@ -3229,15 +4237,19 @@ inline bool Server::read_content_core(Stream &strm, bool last_connection,
out = receiver;
}
- if (!detail::read_content(strm, req, payload_max_length_, res.status,
- Progress(), out)) {
- return write_response(strm, last_connection, req, res);
+ if (req.method == "DELETE" && !req.has_header("Content-Length")) {
+ return true;
+ }
+
+ if (!detail::read_content(strm, req, payload_max_length_, res.status, nullptr,
+ out, true)) {
+ return false;
}
if (req.is_multipart_form_data()) {
if (!multipart_form_data_parser.is_valid()) {
res.status = 400;
- return write_response(strm, last_connection, req, res);
+ return false;
}
}
@@ -3246,15 +4258,12 @@ inline bool Server::read_content_core(Stream &strm, bool last_connection,
inline bool Server::handle_file_request(Request &req, Response &res,
bool head) {
- for (const auto &kv : base_dirs_) {
- const auto &mount_point = kv.first;
- const auto &base_dir = kv.second;
-
+ for (const auto &entry : base_dirs_) {
// Prefix match
- if (!req.path.find(mount_point)) {
- std::string sub_path = "/" + req.path.substr(mount_point.size());
+ if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) {
+ std::string sub_path = "/" + req.path.substr(entry.mount_point.size());
if (detail::is_valid_path(sub_path)) {
- auto path = base_dir + sub_path;
+ auto path = entry.base_dir + sub_path;
if (path.back() == '/') { path += "index.html"; }
if (detail::is_file(path)) {
@@ -3262,6 +4271,9 @@ inline bool Server::handle_file_request(Request &req, Response &res,
auto type =
detail::find_content_type(path, file_extension_and_mimetype_map_);
if (type) { res.set_header("Content-Type", type); }
+ for (const auto& kv : entry.headers) {
+ res.set_header(kv.first.c_str(), kv.second);
+ }
res.status = 200;
if (!head && file_request_handler_) {
file_request_handler_(req, res);
@@ -3274,40 +4286,39 @@ inline bool Server::handle_file_request(Request &req, Response &res,
return false;
}
-inline socket_t Server::create_server_socket(const char *host, int port,
- int socket_flags) const {
+inline socket_t
+Server::create_server_socket(const char *host, int port, int socket_flags,
+ SocketOptions socket_options) const {
return detail::create_socket(
- host, port,
+ host, port, socket_flags, tcp_nodelay_, socket_options,
[](socket_t sock, struct addrinfo &ai) -> bool {
- if (::bind(sock, ai.ai_addr, static_cast<int>(ai.ai_addrlen))) {
+ if (::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
return false;
}
if (::listen(sock, 5)) { // Listen through 5 channels
return false;
}
return true;
- },
- socket_flags);
+ });
}
inline int Server::bind_internal(const char *host, int port, int socket_flags) {
if (!is_valid()) { return -1; }
- svr_sock_ = create_server_socket(host, port, socket_flags);
+ svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_);
if (svr_sock_ == INVALID_SOCKET) { return -1; }
if (port == 0) {
- struct sockaddr_storage address;
- socklen_t len = sizeof(address);
- if (getsockname(svr_sock_, reinterpret_cast<struct sockaddr *>(&address),
- &len) == -1) {
+ struct sockaddr_storage addr;
+ socklen_t addr_len = sizeof(addr);
+ if (getsockname(svr_sock_, reinterpret_cast<struct sockaddr *>(&addr),
+ &addr_len) == -1) {
return -1;
}
- if (address.ss_family == AF_INET) {
- return ntohs(reinterpret_cast<struct sockaddr_in *>(&address)->sin_port);
- } else if (address.ss_family == AF_INET6) {
- return ntohs(
- reinterpret_cast<struct sockaddr_in6 *>(&address)->sin6_port);
+ if (addr.ss_family == AF_INET) {
+ return ntohs(reinterpret_cast<struct sockaddr_in *>(&addr)->sin_port);
+ } else if (addr.ss_family == AF_INET6) {
+ return ntohs(reinterpret_cast<struct sockaddr_in6 *>(&addr)->sin6_port);
} else {
return -1;
}
@@ -3323,18 +4334,19 @@ inline bool Server::listen_internal() {
{
std::unique_ptr<TaskQueue> task_queue(new_task_queue());
- for (;;) {
- if (svr_sock_ == INVALID_SOCKET) {
- // The server socket was closed by 'stop' method.
- break;
- }
-
- auto val = detail::select_read(svr_sock_, 0, 100000);
-
- if (val == 0) { // Timeout
- continue;
+ while (svr_sock_ != INVALID_SOCKET) {
+#ifndef _WIN32
+ if (idle_interval_sec_ > 0 || idle_interval_usec_ > 0) {
+#endif
+ auto val = detail::select_read(svr_sock_, idle_interval_sec_,
+ idle_interval_usec_);
+ if (val == 0) { // Timeout
+ task_queue->on_idle();
+ continue;
+ }
+#ifndef _WIN32
}
-
+#endif
socket_t sock = accept(svr_sock_, nullptr, nullptr);
if (sock == INVALID_SOCKET) {
@@ -3353,7 +4365,11 @@ inline bool Server::listen_internal() {
break;
}
+#if __cplusplus > 201703L
+ task_queue->enqueue([=, this]() { process_and_close_socket(sock); });
+#else
task_queue->enqueue([=]() { process_and_close_socket(sock); });
+#endif
}
task_queue->shutdown();
@@ -3363,8 +4379,7 @@ inline bool Server::listen_internal() {
return ret;
}
-inline bool Server::routing(Request &req, Response &res, Stream &strm,
- bool last_connection) {
+inline bool Server::routing(Request &req, Response &res, Stream &strm) {
// File handler
bool is_head_request = req.method == "HEAD";
if ((req.method == "GET" || is_head_request) &&
@@ -3377,12 +4392,12 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm,
{
ContentReader reader(
[&](ContentReceiver receiver) {
- return read_content_with_content_receiver(
- strm, last_connection, req, res, receiver, nullptr, nullptr);
+ return read_content_with_content_receiver(strm, req, res, receiver,
+ nullptr, nullptr);
},
[&](MultipartContentHeader header, ContentReceiver receiver) {
- return read_content_with_content_receiver(
- strm, last_connection, req, res, nullptr, header, receiver);
+ return read_content_with_content_receiver(strm, req, res, nullptr,
+ header, receiver);
});
if (req.method == "POST") {
@@ -3400,11 +4415,16 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm,
req, res, reader, patch_handlers_for_content_reader_)) {
return true;
}
+ } else if (req.method == "DELETE") {
+ if (dispatch_request_for_content_reader(
+ req, res, reader, delete_handlers_for_content_reader_)) {
+ return true;
+ }
}
}
// Read content into `req.body`
- if (!read_content(strm, last_connection, req, res)) { return false; }
+ if (!read_content(strm, req, res)) { return false; }
}
// Regular handler
@@ -3427,22 +4447,31 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm,
}
inline bool Server::dispatch_request(Request &req, Response &res,
- Handlers &handlers) {
- for (const auto &x : handlers) {
- const auto &pattern = x.first;
- const auto &handler = x.second;
+ const Handlers &handlers) {
- if (std::regex_match(req.path, req.matches, pattern)) {
- handler(req, res);
- return true;
+ try {
+ for (const auto &x : handlers) {
+ const auto &pattern = x.first;
+ const auto &handler = x.second;
+
+ if (std::regex_match(req.path, req.matches, pattern)) {
+ handler(req, res);
+ return true;
+ }
}
+ } catch (const std::exception &ex) {
+ res.status = 500;
+ res.set_header("EXCEPTION_WHAT", ex.what());
+ } catch (...) {
+ res.status = 500;
+ res.set_header("EXCEPTION_WHAT", "UNKNOWN");
}
return false;
}
inline bool Server::dispatch_request_for_content_reader(
Request &req, Response &res, ContentReader content_reader,
- HandlersForContentReader &handlers) {
+ const HandlersForContentReader &handlers) {
for (const auto &x : handlers) {
const auto &pattern = x.first;
const auto &handler = x.second;
@@ -3456,8 +4485,8 @@ inline bool Server::dispatch_request_for_content_reader(
}
inline bool
-Server::process_request(Stream &strm, bool last_connection,
- bool &connection_close,
+Server::process_request(Stream &strm, bool close_connection,
+ bool &connection_closed,
const std::function<void(Request &)> &setup_request) {
std::array<char, 2048> buf{};
@@ -3476,26 +4505,28 @@ Server::process_request(Stream &strm, bool last_connection,
Headers dummy;
detail::read_headers(strm, dummy);
res.status = 414;
- return write_response(strm, last_connection, req, res);
+ return write_response(strm, close_connection, req, res);
}
// Request line and headers
if (!parse_request_line(line_reader.ptr(), req) ||
!detail::read_headers(strm, req.headers)) {
res.status = 400;
- return write_response(strm, last_connection, req, res);
+ return write_response(strm, close_connection, req, res);
}
if (req.get_header_value("Connection") == "close") {
- connection_close = true;
+ connection_closed = true;
}
if (req.version == "HTTP/1.0" &&
req.get_header_value("Connection") != "Keep-Alive") {
- connection_close = true;
+ connection_closed = true;
}
- req.set_header("REMOTE_ADDR", strm.get_remote_addr());
+ strm.get_remote_ip_and_port(req.remote_addr, req.remote_port);
+ req.set_header("REMOTE_ADDR", req.remote_addr);
+ req.set_header("REMOTE_PORT", std::to_string(req.remote_port));
if (req.has_header("Range")) {
const auto &range_header_value = req.get_header_value("Range");
@@ -3517,136 +4548,211 @@ Server::process_request(Stream &strm, bool last_connection,
strm.write_format("HTTP/1.1 %d %s\r\n\r\n", status,
detail::status_message(status));
break;
- default: return write_response(strm, last_connection, req, res);
+ default: return write_response(strm, close_connection, req, res);
}
}
// Rounting
- if (routing(req, res, strm, last_connection)) {
+ if (routing(req, res, strm)) {
if (res.status == -1) { res.status = req.ranges.empty() ? 200 : 206; }
} else {
if (res.status == -1) { res.status = 404; }
}
- return write_response(strm, last_connection, req, res);
+ return write_response(strm, close_connection, req, res);
}
inline bool Server::is_valid() const { return true; }
inline bool Server::process_and_close_socket(socket_t sock) {
- return detail::process_and_close_socket(
- false, sock, keep_alive_max_count_, read_timeout_sec_, read_timeout_usec_,
- [this](Stream &strm, bool last_connection, bool &connection_close) {
- return process_request(strm, last_connection, connection_close,
+ auto ret = detail::process_server_socket(
+ sock, keep_alive_max_count_, keep_alive_timeout_sec_, read_timeout_sec_,
+ read_timeout_usec_, write_timeout_sec_, write_timeout_usec_,
+ [this](Stream &strm, bool close_connection, bool &connection_closed) {
+ return process_request(strm, close_connection, connection_closed,
nullptr);
});
+
+ detail::shutdown_socket(sock);
+ detail::close_socket(sock);
+ return ret;
}
// HTTP client implementation
-inline Client::Client(const std::string &host, int port,
- const std::string &client_cert_path,
- const std::string &client_key_path)
+inline ClientImpl::ClientImpl(const std::string &host)
+ : ClientImpl(host, 80, std::string(), std::string()) {}
+
+inline ClientImpl::ClientImpl(const std::string &host, int port)
+ : ClientImpl(host, port, std::string(), std::string()) {}
+
+inline ClientImpl::ClientImpl(const std::string &host, int port,
+ const std::string &client_cert_path,
+ const std::string &client_key_path)
: host_(host), port_(port),
host_and_port_(host_ + ":" + std::to_string(port_)),
client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}
-inline Client::~Client() {}
+inline ClientImpl::~ClientImpl() { stop_core(); }
+
+inline bool ClientImpl::is_valid() const { return true; }
-inline bool Client::is_valid() const { return true; }
+inline Error ClientImpl::get_last_error() const { return error_; }
-inline socket_t Client::create_client_socket() const {
- if (!proxy_host_.empty()) {
- return detail::create_client_socket(proxy_host_.c_str(), proxy_port_,
- timeout_sec_, interface_);
+inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
+ client_cert_path_ = rhs.client_cert_path_;
+ client_key_path_ = rhs.client_key_path_;
+ connection_timeout_sec_ = rhs.connection_timeout_sec_;
+ read_timeout_sec_ = rhs.read_timeout_sec_;
+ read_timeout_usec_ = rhs.read_timeout_usec_;
+ write_timeout_sec_ = rhs.write_timeout_sec_;
+ write_timeout_usec_ = rhs.write_timeout_usec_;
+ basic_auth_username_ = rhs.basic_auth_username_;
+ basic_auth_password_ = rhs.basic_auth_password_;
+ bearer_token_auth_token_ = rhs.bearer_token_auth_token_;
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ digest_auth_username_ = rhs.digest_auth_username_;
+ digest_auth_password_ = rhs.digest_auth_password_;
+#endif
+ keep_alive_ = rhs.keep_alive_;
+ follow_location_ = rhs.follow_location_;
+ tcp_nodelay_ = rhs.tcp_nodelay_;
+ socket_options_ = rhs.socket_options_;
+ compress_ = rhs.compress_;
+ decompress_ = rhs.decompress_;
+ interface_ = rhs.interface_;
+ proxy_host_ = rhs.proxy_host_;
+ proxy_port_ = rhs.proxy_port_;
+ proxy_basic_auth_username_ = rhs.proxy_basic_auth_username_;
+ proxy_basic_auth_password_ = rhs.proxy_basic_auth_password_;
+ proxy_bearer_token_auth_token_ = rhs.proxy_bearer_token_auth_token_;
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
+ proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
+#endif
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ server_certificate_verification_ = rhs.server_certificate_verification_;
+#endif
+ logger_ = rhs.logger_;
+}
+
+inline socket_t ClientImpl::create_client_socket() const {
+ if (!proxy_host_.empty() && proxy_port_ != -1) {
+ return detail::create_client_socket(
+ proxy_host_.c_str(), proxy_port_, tcp_nodelay_, socket_options_,
+ connection_timeout_sec_, connection_timeout_usec_, interface_, error_);
}
- return detail::create_client_socket(host_.c_str(), port_, timeout_sec_,
- interface_);
+ return detail::create_client_socket(
+ host_.c_str(), port_, tcp_nodelay_, socket_options_,
+ connection_timeout_sec_, connection_timeout_usec_, interface_, error_);
}
-inline bool Client::read_response_line(Stream &strm, Response &res) {
+inline bool ClientImpl::create_and_connect_socket(Socket &socket) {
+ auto sock = create_client_socket();
+ if (sock == INVALID_SOCKET) { return false; }
+ socket.sock = sock;
+ return true;
+}
+
+inline void ClientImpl::close_socket(Socket &socket,
+ bool /*process_socket_ret*/) {
+ detail::close_socket(socket.sock);
+ socket_.sock = INVALID_SOCKET;
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ socket_.ssl = nullptr;
+#endif
+}
+
+inline bool ClientImpl::read_response_line(Stream &strm, Response &res) {
std::array<char, 2048> buf;
detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
if (!line_reader.getline()) { return false; }
- const static std::regex re("(HTTP/1\\.[01]) (\\d+?) .*\r\n");
+ const static std::regex re("(HTTP/1\\.[01]) (\\d+) (.*?)\r\n");
std::cmatch m;
- if (std::regex_match(line_reader.ptr(), m, re)) {
+ if (!std::regex_match(line_reader.ptr(), m, re)) { return false; }
+ res.version = std::string(m[1]);
+ res.status = std::stoi(std::string(m[2]));
+ res.reason = std::string(m[3]);
+
+ // Ignore '100 Continue'
+ while (res.status == 100) {
+ if (!line_reader.getline()) { return false; } // CRLF
+ if (!line_reader.getline()) { return false; } // next response line
+
+ if (!std::regex_match(line_reader.ptr(), m, re)) { return false; }
res.version = std::string(m[1]);
res.status = std::stoi(std::string(m[2]));
+ res.reason = std::string(m[3]);
}
return true;
}
-inline bool Client::send(const Request &req, Response &res) {
- auto sock = create_client_socket();
- if (sock == INVALID_SOCKET) { return false; }
+inline bool ClientImpl::send(const Request &req, Response &res) {
+ std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_);
-#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
- if (is_ssl() && !proxy_host_.empty()) {
- bool error;
- if (!connect(sock, res, error)) { return error; }
- }
-#endif
+ {
+ std::lock_guard<std::mutex> guard(socket_mutex_);
- return process_and_close_socket(
- sock, 1, [&](Stream &strm, bool last_connection, bool &connection_close) {
- return handle_request(strm, req, res, last_connection,
- connection_close);
- });
-}
+ auto is_alive = false;
+ if (socket_.is_open()) {
+ is_alive = detail::select_write(socket_.sock, 0, 0) > 0;
+ if (!is_alive) { close_socket(socket_, false); }
+ }
-inline bool Client::send(const std::vector<Request> &requests,
- std::vector<Response> &responses) {
- size_t i = 0;
- while (i < requests.size()) {
- auto sock = create_client_socket();
- if (sock == INVALID_SOCKET) { return false; }
+ if (!is_alive) {
+ if (!create_and_connect_socket(socket_)) { return false; }
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
- if (is_ssl() && !proxy_host_.empty()) {
- Response res;
- bool error;
- if (!connect(sock, res, error)) { return false; }
- }
-#endif
+ // TODO: refactoring
+ if (is_ssl()) {
+ auto &scli = static_cast<SSLClient &>(*this);
+ if (!proxy_host_.empty() && proxy_port_ != -1) {
+ bool success = false;
+ if (!scli.connect_with_proxy(socket_, res, success)) {
+ return success;
+ }
+ }
- if (!process_and_close_socket(sock, requests.size() - i,
- [&](Stream &strm, bool last_connection,
- bool &connection_close) -> bool {
- auto &req = requests[i++];
- auto res = Response();
- auto ret = handle_request(strm, req, res,
- last_connection,
- connection_close);
- if (ret) {
- responses.emplace_back(std::move(res));
- }
- return ret;
- })) {
- return false;
+ if (!scli.initialize_ssl(socket_)) { return false; }
+ }
+#endif
}
}
- return true;
+ auto close_connection = !keep_alive_;
+
+ auto ret = process_socket(socket_, [&](Stream &strm) {
+ return handle_request(strm, req, res, close_connection);
+ });
+
+ if (close_connection || !ret) { stop_core(); }
+
+ if (!ret) {
+ if (error_ == Error::Success) { error_ = Error::Unknown; }
+ }
+
+ return ret;
}
-inline bool Client::handle_request(Stream &strm, const Request &req,
- Response &res, bool last_connection,
- bool &connection_close) {
- if (req.path.empty()) { return false; }
+inline bool ClientImpl::handle_request(Stream &strm, const Request &req,
+ Response &res, bool close_connection) {
+ if (req.path.empty()) {
+ error_ = Error::Connection;
+ return false;
+ }
bool ret;
- if (!is_ssl() && !proxy_host_.empty()) {
+ if (!is_ssl() && !proxy_host_.empty() && proxy_port_ != -1) {
auto req2 = req;
req2.path = "http://" + host_and_port_ + req.path;
- ret = process_request(strm, req2, res, last_connection, connection_close);
+ ret = process_request(strm, req2, res, close_connection);
} else {
- ret = process_request(strm, req, res, last_connection, connection_close);
+ ret = process_request(strm, req, res, close_connection);
}
if (!ret) { return false; }
@@ -3656,7 +4762,8 @@ inline bool Client::handle_request(Stream &strm, const Request &req,
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
- if (res.status == 401 || res.status == 407) {
+ if ((res.status == 401 || res.status == 407) &&
+ req.authorization_count_ < 5) {
auto is_proxy = res.status == 407;
const auto &username =
is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
@@ -3665,12 +4772,14 @@ inline bool Client::handle_request(Stream &strm, const Request &req,
if (!username.empty() && !password.empty()) {
std::map<std::string, std::string> auth;
- if (parse_www_authenticate(res, auth, is_proxy)) {
+ if (detail::parse_www_authenticate(res, auth, is_proxy)) {
Request new_req = req;
- auto key = is_proxy ? "Proxy-Authorization" : "WWW-Authorization";
+ new_req.authorization_count_ += 1;
+ auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
new_req.headers.erase(key);
- new_req.headers.insert(make_digest_authentication_header(
- req, auth, 1, random_string(10), username, password, is_proxy));
+ new_req.headers.insert(detail::make_digest_authentication_header(
+ req, auth, new_req.authorization_count_, detail::random_string(10),
+ username, password, is_proxy));
Response new_res;
@@ -3684,102 +4793,64 @@ inline bool Client::handle_request(Stream &strm, const Request &req,
return ret;
}
-#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-inline bool Client::connect(socket_t sock, Response &res, bool &error) {
- error = true;
- Response res2;
-
- if (!detail::process_socket(
- true, sock, 1, read_timeout_sec_, read_timeout_usec_,
- [&](Stream &strm, bool /*last_connection*/, bool &connection_close) {
- Request req2;
- req2.method = "CONNECT";
- req2.path = host_and_port_;
- return process_request(strm, req2, res2, false, connection_close);
- })) {
- detail::close_socket(sock);
- error = false;
+inline bool ClientImpl::redirect(const Request &req, Response &res) {
+ if (req.redirect_count == 0) {
+ error_ = Error::ExceedRedirectCount;
return false;
}
- if (res2.status == 407) {
- if (!proxy_digest_auth_username_.empty() &&
- !proxy_digest_auth_password_.empty()) {
- std::map<std::string, std::string> auth;
- if (parse_www_authenticate(res2, auth, true)) {
- Response res3;
- if (!detail::process_socket(
- true, sock, 1, read_timeout_sec_, read_timeout_usec_,
- [&](Stream &strm, bool /*last_connection*/,
- bool &connection_close) {
- Request req3;
- req3.method = "CONNECT";
- req3.path = host_and_port_;
- req3.headers.insert(make_digest_authentication_header(
- req3, auth, 1, random_string(10),
- proxy_digest_auth_username_, proxy_digest_auth_password_,
- true));
- return process_request(strm, req3, res3, false,
- connection_close);
- })) {
- detail::close_socket(sock);
- error = false;
- return false;
- }
- }
- } else {
- res = res2;
- return false;
- }
- }
-
- return true;
-}
-#endif
-
-inline bool Client::redirect(const Request &req, Response &res) {
- if (req.redirect_count == 0) { return false; }
-
- auto location = res.get_header_value("location");
+ auto location = detail::decode_url(res.get_header_value("location"), true);
if (location.empty()) { return false; }
const static std::regex re(
- R"(^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");
+ R"(^(?:(https?):)?(?://([^:/?#]*)(?::(\d+))?)?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");
std::smatch m;
- if (!regex_match(location, m, re)) { return false; }
+ if (!std::regex_match(location, m, re)) { return false; }
auto scheme = is_ssl() ? "https" : "http";
auto next_scheme = m[1].str();
auto next_host = m[2].str();
- auto next_path = m[3].str();
- if (next_scheme.empty()) { next_scheme = scheme; }
+ auto port_str = m[3].str();
+ auto next_path = m[4].str();
+
+ auto next_port = port_;
+ if (!port_str.empty()) {
+ next_port = std::stoi(port_str);
+ } else if (!next_scheme.empty()) {
+ next_port = next_scheme == "https" ? 443 : 80;
+ }
+
if (next_scheme.empty()) { next_scheme = scheme; }
if (next_host.empty()) { next_host = host_; }
if (next_path.empty()) { next_path = "/"; }
- if (next_scheme == scheme && next_host == host_) {
+ if (next_scheme == scheme && next_host == host_ && next_port == port_) {
return detail::redirect(*this, req, res, next_path);
} else {
if (next_scheme == "https") {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
- SSLClient cli(next_host.c_str());
+ SSLClient cli(next_host.c_str(), next_port);
cli.copy_settings(*this);
- return detail::redirect(cli, req, res, next_path);
+ auto ret = detail::redirect(cli, req, res, next_path);
+ if (!ret) { error_ = cli.get_last_error(); }
+ return ret;
#else
return false;
#endif
} else {
- Client cli(next_host.c_str());
+ ClientImpl cli(next_host.c_str(), next_port);
cli.copy_settings(*this);
- return detail::redirect(cli, req, res, next_path);
+ auto ret = detail::redirect(cli, req, res, next_path);
+ if (!ret) { error_ = cli.get_last_error(); }
+ return ret;
}
}
}
-inline bool Client::write_request(Stream &strm, const Request &req,
- bool last_connection) {
+inline bool ClientImpl::write_request(Stream &strm, const Request &req,
+ bool close_connection) {
detail::BufferStream bstrm;
// Request line
@@ -3789,7 +4860,7 @@ inline bool Client::write_request(Stream &strm, const Request &req,
// Additonal headers
Headers headers;
- if (last_connection) { headers.emplace("Connection", "close"); }
+ if (close_connection) { headers.emplace("Connection", "close"); }
if (!req.has_header("Host")) {
if (is_ssl()) {
@@ -3810,7 +4881,7 @@ inline bool Client::write_request(Stream &strm, const Request &req,
if (!req.has_header("Accept")) { headers.emplace("Accept", "*/*"); }
if (!req.has_header("User-Agent")) {
- headers.emplace("User-Agent", "cpp-httplib/0.5");
+ headers.emplace("User-Agent", "cpp-httplib/0.7");
}
if (req.body.empty()) {
@@ -3818,7 +4889,10 @@ inline bool Client::write_request(Stream &strm, const Request &req,
auto length = std::to_string(req.content_length);
headers.emplace("Content-Length", length);
} else {
- headers.emplace("Content-Length", "0");
+ if (req.method == "POST" || req.method == "PUT" ||
+ req.method == "PATCH") {
+ headers.emplace("Content-Length", "0");
+ }
}
} else {
if (!req.has_header("Content-Type")) {
@@ -3831,7 +4905,7 @@ inline bool Client::write_request(Stream &strm, const Request &req,
}
}
- if (!basic_auth_username_.empty() && !basic_auth_password_.empty()) {
+ if (!basic_auth_password_.empty()) {
headers.insert(make_basic_authentication_header(
basic_auth_username_, basic_auth_password_, false));
}
@@ -3842,11 +4916,24 @@ inline bool Client::write_request(Stream &strm, const Request &req,
proxy_basic_auth_username_, proxy_basic_auth_password_, true));
}
+ if (!bearer_token_auth_token_.empty()) {
+ headers.insert(make_bearer_token_authentication_header(
+ bearer_token_auth_token_, false));
+ }
+
+ if (!proxy_bearer_token_auth_token_.empty()) {
+ headers.insert(make_bearer_token_authentication_header(
+ proxy_bearer_token_auth_token_, true));
+ }
+
detail::write_headers(bstrm, req, headers);
// Flush buffer
auto &data = bstrm.get_buffer();
- strm.write(data.data(), data.size());
+ if (!detail::write_data(strm, data.data(), data.size())) {
+ error_ = Error::Write;
+ return false;
+ }
// Body
if (req.body.empty()) {
@@ -3854,55 +4941,95 @@ inline bool Client::write_request(Stream &strm, const Request &req,
size_t offset = 0;
size_t end_offset = req.content_length;
+ bool ok = true;
+
DataSink data_sink;
data_sink.write = [&](const char *d, size_t l) {
- auto written_length = strm.write(d, l);
- offset += written_length;
+ if (ok) {
+ if (detail::write_data(strm, d, l)) {
+ offset += l;
+ } else {
+ ok = false;
+ }
+ }
};
- data_sink.is_writable = [&](void) { return strm.is_writable(); };
+ data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };
while (offset < end_offset) {
- req.content_provider(offset, end_offset - offset, data_sink);
+ if (!req.content_provider(offset, end_offset - offset, data_sink)) {
+ error_ = Error::Canceled;
+ return false;
+ }
+ if (!ok) {
+ error_ = Error::Write;
+ return false;
+ }
}
}
} else {
- strm.write(req.body);
+ return detail::write_data(strm, req.body.data(), req.body.size());
}
return true;
}
-inline std::shared_ptr<Response> Client::send_with_content_provider(
+inline std::shared_ptr<Response> ClientImpl::send_with_content_provider(
const char *method, const char *path, const Headers &headers,
const std::string &body, size_t content_length,
ContentProvider content_provider, const char *content_type) {
+
Request req;
req.method = method;
- req.headers = headers;
+ req.headers = default_headers_;
+ req.headers.insert(headers.begin(), headers.end());
req.path = path;
- req.headers.emplace("Content-Type", content_type);
+ if (content_type) { req.headers.emplace("Content-Type", content_type); }
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
if (compress_) {
+ detail::gzip_compressor compressor;
+
if (content_provider) {
+ auto ok = true;
size_t offset = 0;
DataSink data_sink;
data_sink.write = [&](const char *data, size_t data_len) {
- req.body.append(data, data_len);
- offset += data_len;
+ if (ok) {
+ auto last = offset + data_len == content_length;
+
+ auto ret = compressor.compress(
+ data, data_len, last, [&](const char *data, size_t data_len) {
+ req.body.append(data, data_len);
+ return true;
+ });
+
+ if (ret) {
+ offset += data_len;
+ } else {
+ ok = false;
+ }
+ }
};
- data_sink.is_writable = [&](void) { return true; };
+ data_sink.is_writable = [&](void) { return ok && true; };
- while (offset < content_length) {
- content_provider(offset, content_length - offset, data_sink);
+ while (ok && offset < content_length) {
+ if (!content_provider(offset, content_length - offset, data_sink)) {
+ error_ = Error::Canceled;
+ return nullptr;
+ }
}
} else {
- req.body = body;
+ if (!compressor.compress(body.data(), body.size(), true,
+ [&](const char *data, size_t data_len) {
+ req.body.append(data, data_len);
+ return true;
+ })) {
+ return nullptr;
+ }
}
- if (!detail::compress(req.body)) { return nullptr; }
req.headers.emplace("Content-Encoding", "gzip");
} else
#endif
@@ -3920,215 +5047,232 @@ inline std::shared_ptr<Response> Client::send_with_content_provider(
return send(req, *res) ? res : nullptr;
}
-inline bool Client::process_request(Stream &strm, const Request &req,
- Response &res, bool last_connection,
- bool &connection_close) {
+inline bool ClientImpl::process_request(Stream &strm, const Request &req,
+ Response &res, bool close_connection) {
// Send request
- if (!write_request(strm, req, last_connection)) { return false; }
+ if (!write_request(strm, req, close_connection)) { return false; }
// Receive response and headers
if (!read_response_line(strm, res) ||
!detail::read_headers(strm, res.headers)) {
+ error_ = Error::Read;
return false;
}
- if (res.get_header_value("Connection") == "close" ||
- res.version == "HTTP/1.0") {
- connection_close = true;
- }
-
if (req.response_handler) {
- if (!req.response_handler(res)) { return false; }
+ if (!req.response_handler(res)) {
+ error_ = Error::Canceled;
+ return false;
+ }
}
// Body
if (req.method != "HEAD" && req.method != "CONNECT") {
- ContentReceiver out = [&](const char *buf, size_t n) {
- if (res.body.size() + n > res.body.max_size()) { return false; }
- res.body.append(buf, n);
- return true;
+ auto out =
+ req.content_receiver
+ ? static_cast<ContentReceiver>([&](const char *buf, size_t n) {
+ auto ret = req.content_receiver(buf, n);
+ if (!ret) { error_ = Error::Canceled; }
+ return ret;
+ })
+ : static_cast<ContentReceiver>([&](const char *buf, size_t n) {
+ if (res.body.size() + n > res.body.max_size()) { return false; }
+ res.body.append(buf, n);
+ return true;
+ });
+
+ auto progress = [&](uint64_t current, uint64_t total) {
+ if (!req.progress) { return true; }
+ auto ret = req.progress(current, total);
+ if (!ret) { error_ = Error::Canceled; }
+ return ret;
};
- if (req.content_receiver) {
- out = [&](const char *buf, size_t n) {
- return req.content_receiver(buf, n);
- };
- }
-
int dummy_status;
- if (!detail::read_content(strm, res, std::numeric_limits<size_t>::max(),
- dummy_status, req.progress, out)) {
+ if (!detail::read_content(strm, res, (std::numeric_limits<size_t>::max)(),
+ dummy_status, progress, out, decompress_)) {
+ if (error_ != Error::Canceled) { error_ = Error::Read; }
return false;
}
}
+ if (res.get_header_value("Connection") == "close" ||
+ (res.version == "HTTP/1.0" && res.reason != "Connection established")) {
+ stop_core();
+ }
+
// Log
if (logger_) { logger_(req, res); }
return true;
}
-inline bool Client::process_and_close_socket(
- socket_t sock, size_t request_count,
- std::function<bool(Stream &strm, bool last_connection,
- bool &connection_close)>
- callback) {
- request_count = std::min(request_count, keep_alive_max_count_);
- return detail::process_and_close_socket(true, sock, request_count,
- read_timeout_sec_, read_timeout_usec_,
- callback);
+inline bool
+ClientImpl::process_socket(Socket &socket,
+ std::function<bool(Stream &strm)> callback) {
+ return detail::process_client_socket(socket.sock, read_timeout_sec_,
+ read_timeout_usec_, write_timeout_sec_,
+ write_timeout_usec_, callback);
}
-inline bool Client::is_ssl() const { return false; }
+inline bool ClientImpl::is_ssl() const { return false; }
-inline std::shared_ptr<Response> Client::Get(const char *path) {
+inline Result ClientImpl::Get(const char *path) {
return Get(path, Headers(), Progress());
}
-inline std::shared_ptr<Response> Client::Get(const char *path,
- Progress progress) {
+inline Result ClientImpl::Get(const char *path, Progress progress) {
return Get(path, Headers(), std::move(progress));
}
-inline std::shared_ptr<Response> Client::Get(const char *path,
- const Headers &headers) {
+inline Result ClientImpl::Get(const char *path, const Headers &headers) {
return Get(path, headers, Progress());
}
-inline std::shared_ptr<Response>
-Client::Get(const char *path, const Headers &headers, Progress progress) {
+inline Result ClientImpl::Get(const char *path, const Headers &headers,
+ Progress progress) {
Request req;
req.method = "GET";
req.path = path;
- req.headers = headers;
+ req.headers = default_headers_;
+ req.headers.insert(headers.begin(), headers.end());
req.progress = std::move(progress);
auto res = std::make_shared<Response>();
- return send(req, *res) ? res : nullptr;
+ auto ret = send(req, *res);
+ return Result{ret ? res : nullptr, get_last_error()};
}
-inline std::shared_ptr<Response> Client::Get(const char *path,
- ContentReceiver content_receiver) {
- return Get(path, Headers(), nullptr, std::move(content_receiver), Progress());
+inline Result ClientImpl::Get(const char *path,
+ ContentReceiver content_receiver) {
+ return Get(path, Headers(), nullptr, std::move(content_receiver), nullptr);
}
-inline std::shared_ptr<Response> Client::Get(const char *path,
- ContentReceiver content_receiver,
- Progress progress) {
+inline Result ClientImpl::Get(const char *path,
+ ContentReceiver content_receiver,
+ Progress progress) {
return Get(path, Headers(), nullptr, std::move(content_receiver),
std::move(progress));
}
-inline std::shared_ptr<Response> Client::Get(const char *path,
- const Headers &headers,
- ContentReceiver content_receiver) {
- return Get(path, headers, nullptr, std::move(content_receiver), Progress());
+inline Result ClientImpl::Get(const char *path, const Headers &headers,
+ ContentReceiver content_receiver) {
+ return Get(path, headers, nullptr, std::move(content_receiver), nullptr);
}
-inline std::shared_ptr<Response> Client::Get(const char *path,
- const Headers &headers,
- ContentReceiver content_receiver,
- Progress progress) {
+inline Result ClientImpl::Get(const char *path, const Headers &headers,
+ ContentReceiver content_receiver,
+ Progress progress) {
return Get(path, headers, nullptr, std::move(content_receiver),
std::move(progress));
}
-inline std::shared_ptr<Response> Client::Get(const char *path,
- const Headers &headers,
- ResponseHandler response_handler,
- ContentReceiver content_receiver) {
+inline Result ClientImpl::Get(const char *path,
+ ResponseHandler response_handler,
+ ContentReceiver content_receiver) {
+ return Get(path, Headers(), std::move(response_handler), content_receiver,
+ nullptr);
+}
+
+inline Result ClientImpl::Get(const char *path, const Headers &headers,
+ ResponseHandler response_handler,
+ ContentReceiver content_receiver) {
return Get(path, headers, std::move(response_handler), content_receiver,
- Progress());
+ nullptr);
}
-inline std::shared_ptr<Response> Client::Get(const char *path,
- const Headers &headers,
- ResponseHandler response_handler,
- ContentReceiver content_receiver,
- Progress progress) {
+inline Result ClientImpl::Get(const char *path,
+ ResponseHandler response_handler,
+ ContentReceiver content_receiver,
+ Progress progress) {
+ return Get(path, Headers(), std::move(response_handler), content_receiver,
+ progress);
+}
+
+inline Result ClientImpl::Get(const char *path, const Headers &headers,
+ ResponseHandler response_handler,
+ ContentReceiver content_receiver,
+ Progress progress) {
Request req;
req.method = "GET";
req.path = path;
- req.headers = headers;
+ req.headers = default_headers_;
+ req.headers.insert(headers.begin(), headers.end());
req.response_handler = std::move(response_handler);
req.content_receiver = std::move(content_receiver);
req.progress = std::move(progress);
auto res = std::make_shared<Response>();
- return send(req, *res) ? res : nullptr;
+ auto ret = send(req, *res);
+ return Result{ret ? res : nullptr, get_last_error()};
}
-inline std::shared_ptr<Response> Client::Head(const char *path) {
+inline Result ClientImpl::Head(const char *path) {
return Head(path, Headers());
}
-inline std::shared_ptr<Response> Client::Head(const char *path,
- const Headers &headers) {
+inline Result ClientImpl::Head(const char *path, const Headers &headers) {
Request req;
req.method = "HEAD";
- req.headers = headers;
+ req.headers = default_headers_;
+ req.headers.insert(headers.begin(), headers.end());
req.path = path;
auto res = std::make_shared<Response>();
+ auto ret = send(req, *res);
+ return Result{ret ? res : nullptr, get_last_error()};
+}
- return send(req, *res) ? res : nullptr;
+inline Result ClientImpl::Post(const char *path) {
+ return Post(path, std::string(), nullptr);
}
-inline std::shared_ptr<Response> Client::Post(const char *path,
- const std::string &body,
- const char *content_type) {
+inline Result ClientImpl::Post(const char *path, const std::string &body,
+ const char *content_type) {
return Post(path, Headers(), body, content_type);
}
-inline std::shared_ptr<Response> Client::Post(const char *path,
- const Headers &headers,
- const std::string &body,
- const char *content_type) {
- return send_with_content_provider("POST", path, headers, body, 0, nullptr,
- content_type);
+inline Result ClientImpl::Post(const char *path, const Headers &headers,
+ const std::string &body,
+ const char *content_type) {
+ auto ret = send_with_content_provider("POST", path, headers, body, 0, nullptr,
+ content_type);
+ return Result{ret, get_last_error()};
}
-inline std::shared_ptr<Response> Client::Post(const char *path,
- const Params &params) {
+inline Result ClientImpl::Post(const char *path, const Params &params) {
return Post(path, Headers(), params);
}
-inline std::shared_ptr<Response> Client::Post(const char *path,
- size_t content_length,
- ContentProvider content_provider,
- const char *content_type) {
+inline Result ClientImpl::Post(const char *path, size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
return Post(path, Headers(), content_length, content_provider, content_type);
}
-inline std::shared_ptr<Response>
-Client::Post(const char *path, const Headers &headers, size_t content_length,
- ContentProvider content_provider, const char *content_type) {
- return send_with_content_provider("POST", path, headers, std::string(),
- content_length, content_provider,
- content_type);
+inline Result ClientImpl::Post(const char *path, const Headers &headers,
+ size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
+ auto ret = send_with_content_provider("POST", path, headers, std::string(),
+ content_length, content_provider,
+ content_type);
+ return Result{ret, get_last_error()};
}
-inline std::shared_ptr<Response>
-Client::Post(const char *path, const Headers &headers, const Params &params) {
- std::string query;
- for (auto it = params.begin(); it != params.end(); ++it) {
- if (it != params.begin()) { query += "&"; }
- query += it->first;
- query += "=";
- query += detail::encode_url(it->second);
- }
-
+inline Result ClientImpl::Post(const char *path, const Headers &headers,
+ const Params &params) {
+ auto query = detail::params_to_query_str(params);
return Post(path, headers, query, "application/x-www-form-urlencoded");
}
-inline std::shared_ptr<Response>
-Client::Post(const char *path, const MultipartFormDataItems &items) {
+inline Result ClientImpl::Post(const char *path,
+ const MultipartFormDataItems &items) {
return Post(path, Headers(), items);
}
-inline std::shared_ptr<Response>
-Client::Post(const char *path, const Headers &headers,
- const MultipartFormDataItems &items) {
+inline Result ClientImpl::Post(const char *path, const Headers &headers,
+ const MultipartFormDataItems &items) {
auto boundary = detail::make_multipart_data_boundary();
std::string body;
@@ -4153,182 +5297,229 @@ Client::Post(const char *path, const Headers &headers,
return Post(path, headers, body, content_type.c_str());
}
-inline std::shared_ptr<Response> Client::Put(const char *path,
- const std::string &body,
- const char *content_type) {
+inline Result ClientImpl::Put(const char *path) {
+ return Put(path, std::string(), nullptr);
+}
+
+inline Result ClientImpl::Put(const char *path, const std::string &body,
+ const char *content_type) {
return Put(path, Headers(), body, content_type);
}
-inline std::shared_ptr<Response> Client::Put(const char *path,
- const Headers &headers,
- const std::string &body,
- const char *content_type) {
- return send_with_content_provider("PUT", path, headers, body, 0, nullptr,
- content_type);
+inline Result ClientImpl::Put(const char *path, const Headers &headers,
+ const std::string &body,
+ const char *content_type) {
+ auto ret = send_with_content_provider("PUT", path, headers, body, 0, nullptr,
+ content_type);
+ return Result{ret, get_last_error()};
}
-inline std::shared_ptr<Response> Client::Put(const char *path,
- size_t content_length,
- ContentProvider content_provider,
- const char *content_type) {
+inline Result ClientImpl::Put(const char *path, size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
return Put(path, Headers(), content_length, content_provider, content_type);
}
-inline std::shared_ptr<Response>
-Client::Put(const char *path, const Headers &headers, size_t content_length,
- ContentProvider content_provider, const char *content_type) {
- return send_with_content_provider("PUT", path, headers, std::string(),
- content_length, content_provider,
- content_type);
+inline Result ClientImpl::Put(const char *path, const Headers &headers,
+ size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
+ auto ret = send_with_content_provider("PUT", path, headers, std::string(),
+ content_length, content_provider,
+ content_type);
+ return Result{ret, get_last_error()};
}
-inline std::shared_ptr<Response> Client::Put(const char *path,
- const Params &params) {
+inline Result ClientImpl::Put(const char *path, const Params &params) {
return Put(path, Headers(), params);
}
-inline std::shared_ptr<Response>
-Client::Put(const char *path, const Headers &headers, const Params &params) {
- std::string query;
- for (auto it = params.begin(); it != params.end(); ++it) {
- if (it != params.begin()) { query += "&"; }
- query += it->first;
- query += "=";
- query += detail::encode_url(it->second);
- }
-
+inline Result ClientImpl::Put(const char *path, const Headers &headers,
+ const Params &params) {
+ auto query = detail::params_to_query_str(params);
return Put(path, headers, query, "application/x-www-form-urlencoded");
}
-inline std::shared_ptr<Response> Client::Patch(const char *path,
- const std::string &body,
- const char *content_type) {
+inline Result ClientImpl::Patch(const char *path, const std::string &body,
+ const char *content_type) {
return Patch(path, Headers(), body, content_type);
}
-inline std::shared_ptr<Response> Client::Patch(const char *path,
- const Headers &headers,
- const std::string &body,
- const char *content_type) {
- return send_with_content_provider("PATCH", path, headers, body, 0, nullptr,
- content_type);
+inline Result ClientImpl::Patch(const char *path, const Headers &headers,
+ const std::string &body,
+ const char *content_type) {
+ auto ret = send_with_content_provider("PATCH", path, headers, body, 0,
+ nullptr, content_type);
+ return Result{ret, get_last_error()};
}
-inline std::shared_ptr<Response> Client::Patch(const char *path,
- size_t content_length,
- ContentProvider content_provider,
- const char *content_type) {
+inline Result ClientImpl::Patch(const char *path, size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
return Patch(path, Headers(), content_length, content_provider, content_type);
}
-inline std::shared_ptr<Response>
-Client::Patch(const char *path, const Headers &headers, size_t content_length,
- ContentProvider content_provider, const char *content_type) {
- return send_with_content_provider("PATCH", path, headers, std::string(),
- content_length, content_provider,
- content_type);
+inline Result ClientImpl::Patch(const char *path, const Headers &headers,
+ size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
+ auto ret = send_with_content_provider("PATCH", path, headers, std::string(),
+ content_length, content_provider,
+ content_type);
+ return Result{ret, get_last_error()};
}
-inline std::shared_ptr<Response> Client::Delete(const char *path) {
+inline Result ClientImpl::Delete(const char *path) {
return Delete(path, Headers(), std::string(), nullptr);
}
-inline std::shared_ptr<Response> Client::Delete(const char *path,
- const std::string &body,
- const char *content_type) {
+inline Result ClientImpl::Delete(const char *path, const std::string &body,
+ const char *content_type) {
return Delete(path, Headers(), body, content_type);
}
-inline std::shared_ptr<Response> Client::Delete(const char *path,
- const Headers &headers) {
+inline Result ClientImpl::Delete(const char *path, const Headers &headers) {
return Delete(path, headers, std::string(), nullptr);
}
-inline std::shared_ptr<Response> Client::Delete(const char *path,
- const Headers &headers,
- const std::string &body,
- const char *content_type) {
+inline Result ClientImpl::Delete(const char *path, const Headers &headers,
+ const std::string &body,
+ const char *content_type) {
Request req;
req.method = "DELETE";
- req.headers = headers;
+ req.headers = default_headers_;
+ req.headers.insert(headers.begin(), headers.end());
req.path = path;
if (content_type) { req.headers.emplace("Content-Type", content_type); }
req.body = body;
auto res = std::make_shared<Response>();
-
- return send(req, *res) ? res : nullptr;
+ auto ret = send(req, *res);
+ return Result{ret ? res : nullptr, get_last_error()};
}
-inline std::shared_ptr<Response> Client::Options(const char *path) {
+inline Result ClientImpl::Options(const char *path) {
return Options(path, Headers());
}
-inline std::shared_ptr<Response> Client::Options(const char *path,
- const Headers &headers) {
+inline Result ClientImpl::Options(const char *path, const Headers &headers) {
Request req;
req.method = "OPTIONS";
+ req.headers = default_headers_;
+ req.headers.insert(headers.begin(), headers.end());
req.path = path;
- req.headers = headers;
auto res = std::make_shared<Response>();
+ auto ret = send(req, *res);
+ return Result{ret ? res : nullptr, get_last_error()};
+}
- return send(req, *res) ? res : nullptr;
+inline size_t ClientImpl::is_socket_open() const {
+ std::lock_guard<std::mutex> guard(socket_mutex_);
+ return socket_.is_open();
}
-inline void Client::set_timeout_sec(time_t timeout_sec) {
- timeout_sec_ = timeout_sec;
+inline void ClientImpl::stop() {
+ stop_core();
+ error_ = Error::Canceled;
}
-inline void Client::set_read_timeout(time_t sec, time_t usec) {
+inline void ClientImpl::stop_core() {
+ std::lock_guard<std::mutex> guard(socket_mutex_);
+ if (socket_.is_open()) {
+ detail::shutdown_socket(socket_.sock);
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ close_socket(socket_, true);
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+}
+
+inline void ClientImpl::set_connection_timeout(time_t sec, time_t usec) {
+ connection_timeout_sec_ = sec;
+ connection_timeout_usec_ = usec;
+}
+
+inline void ClientImpl::set_read_timeout(time_t sec, time_t usec) {
read_timeout_sec_ = sec;
read_timeout_usec_ = usec;
}
-inline void Client::set_keep_alive_max_count(size_t count) {
- keep_alive_max_count_ = count;
+inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) {
+ write_timeout_sec_ = sec;
+ write_timeout_usec_ = usec;
}
-inline void Client::set_basic_auth(const char *username, const char *password) {
+inline void ClientImpl::set_basic_auth(const char *username,
+ const char *password) {
basic_auth_username_ = username;
basic_auth_password_ = password;
}
+inline void ClientImpl::set_bearer_token_auth(const char *token) {
+ bearer_token_auth_token_ = token;
+}
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-inline void Client::set_digest_auth(const char *username,
- const char *password) {
+inline void ClientImpl::set_digest_auth(const char *username,
+ const char *password) {
digest_auth_username_ = username;
digest_auth_password_ = password;
}
#endif
-inline void Client::set_follow_location(bool on) { follow_location_ = on; }
+inline void ClientImpl::set_keep_alive(bool on) { keep_alive_ = on; }
-inline void Client::set_compress(bool on) { compress_ = on; }
+inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; }
-inline void Client::set_interface(const char *intf) { interface_ = intf; }
+inline void ClientImpl::set_default_headers(Headers headers) {
+ default_headers_ = std::move(headers);
+}
-inline void Client::set_proxy(const char *host, int port) {
+inline void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; }
+
+inline void ClientImpl::set_socket_options(SocketOptions socket_options) {
+ socket_options_ = socket_options;
+}
+
+inline void ClientImpl::set_compress(bool on) { compress_ = on; }
+
+inline void ClientImpl::set_decompress(bool on) { decompress_ = on; }
+
+inline void ClientImpl::set_interface(const char *intf) { interface_ = intf; }
+
+inline void ClientImpl::set_proxy(const char *host, int port) {
proxy_host_ = host;
proxy_port_ = port;
}
-inline void Client::set_proxy_basic_auth(const char *username,
- const char *password) {
+inline void ClientImpl::set_proxy_basic_auth(const char *username,
+ const char *password) {
proxy_basic_auth_username_ = username;
proxy_basic_auth_password_ = password;
}
+inline void ClientImpl::set_proxy_bearer_token_auth(const char *token) {
+ proxy_bearer_token_auth_token_ = token;
+}
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-inline void Client::set_proxy_digest_auth(const char *username,
- const char *password) {
+inline void ClientImpl::set_proxy_digest_auth(const char *username,
+ const char *password) {
proxy_digest_auth_username_ = username;
proxy_digest_auth_password_ = password;
}
#endif
-inline void Client::set_logger(Logger logger) { logger_ = std::move(logger); }
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+inline void ClientImpl::enable_server_certificate_verification(bool enabled) {
+ server_certificate_verification_ = enabled;
+}
+#endif
+
+inline void ClientImpl::set_logger(Logger logger) {
+ logger_ = std::move(logger);
+}
/*
* SSL Implementation
@@ -4336,72 +5527,66 @@ inline void Client::set_logger(Logger logger) { logger_ = std::move(logger); }
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
namespace detail {
-template <typename U, typename V, typename T>
-inline bool process_and_close_socket_ssl(
- bool is_client_request, socket_t sock, size_t keep_alive_max_count,
- time_t read_timeout_sec, time_t read_timeout_usec, SSL_CTX *ctx,
- std::mutex &ctx_mutex, U SSL_connect_or_accept, V setup, T callback) {
- assert(keep_alive_max_count > 0);
-
+template <typename U, typename V>
+inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex,
+ U SSL_connect_or_accept, V setup) {
SSL *ssl = nullptr;
{
std::lock_guard<std::mutex> guard(ctx_mutex);
ssl = SSL_new(ctx);
}
- if (!ssl) {
- close_socket(sock);
- return false;
- }
-
- auto bio = BIO_new_socket(static_cast<int>(sock), BIO_NOCLOSE);
- SSL_set_bio(ssl, bio, bio);
+ if (ssl) {
+ auto bio = BIO_new_socket(static_cast<int>(sock), BIO_NOCLOSE);
+ SSL_set_bio(ssl, bio, bio);
- if (!setup(ssl)) {
- SSL_shutdown(ssl);
- {
- std::lock_guard<std::mutex> guard(ctx_mutex);
- SSL_free(ssl);
+ if (!setup(ssl) || SSL_connect_or_accept(ssl) != 1) {
+ SSL_shutdown(ssl);
+ {
+ std::lock_guard<std::mutex> guard(ctx_mutex);
+ SSL_free(ssl);
+ }
+ return nullptr;
}
-
- close_socket(sock);
- return false;
}
- auto ret = false;
+ return ssl;
+}
- if (SSL_connect_or_accept(ssl) == 1) {
- if (keep_alive_max_count > 1) {
- auto count = keep_alive_max_count;
- while (count > 0 &&
- (is_client_request ||
- detail::select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND,
- CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND) > 0)) {
- SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec);
- auto last_connection = count == 1;
- auto connection_close = false;
-
- ret = callback(ssl, strm, last_connection, connection_close);
- if (!ret || connection_close) { break; }
-
- count--;
- }
- } else {
- SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec);
- auto dummy_connection_close = false;
- ret = callback(ssl, strm, true, dummy_connection_close);
- }
+inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl,
+ bool process_socket_ret) {
+ if (process_socket_ret) {
+ SSL_shutdown(ssl); // shutdown only if not already closed by remote
}
- SSL_shutdown(ssl);
- {
- std::lock_guard<std::mutex> guard(ctx_mutex);
- SSL_free(ssl);
- }
+ std::lock_guard<std::mutex> guard(ctx_mutex);
+ SSL_free(ssl);
+}
- close_socket(sock);
+template <typename T>
+inline bool
+process_server_socket_ssl(SSL *ssl, socket_t sock, size_t keep_alive_max_count,
+ time_t keep_alive_timeout_sec,
+ time_t read_timeout_sec, time_t read_timeout_usec,
+ time_t write_timeout_sec, time_t write_timeout_usec,
+ T callback) {
+ return process_server_socket_core(
+ sock, keep_alive_max_count, keep_alive_timeout_sec,
+ [&](bool close_connection, bool &connection_closed) {
+ SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
+ write_timeout_sec, write_timeout_usec);
+ return callback(strm, close_connection, connection_closed);
+ });
+}
- return ret;
+template <typename T>
+inline bool
+process_client_socket_ssl(SSL *ssl, socket_t sock, time_t read_timeout_sec,
+ time_t read_timeout_usec, time_t write_timeout_sec,
+ time_t write_timeout_usec, T callback) {
+ SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
+ write_timeout_sec, write_timeout_usec);
+ return callback(strm);
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -4420,11 +5605,11 @@ public:
private:
static void locking_callback(int mode, int type, const char * /*file*/,
int /*line*/) {
- auto &locks = *openSSL_locks_;
+ auto &lk = (*openSSL_locks_)[static_cast<size_t>(type)];
if (mode & CRYPTO_LOCK) {
- locks[type].lock();
+ lk.lock();
} else {
- locks[type].unlock();
+ lk.unlock();
}
}
};
@@ -4458,9 +5643,30 @@ private:
// SSL socket stream implementation
inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl,
time_t read_timeout_sec,
- time_t read_timeout_usec)
+ time_t read_timeout_usec,
+ time_t write_timeout_sec,
+ time_t write_timeout_usec)
: sock_(sock), ssl_(ssl), read_timeout_sec_(read_timeout_sec),
- read_timeout_usec_(read_timeout_usec) {}
+ read_timeout_usec_(read_timeout_usec),
+ write_timeout_sec_(write_timeout_sec),
+ write_timeout_usec_(write_timeout_usec) {
+ {
+ timeval tv;
+ tv.tv_sec = static_cast<long>(read_timeout_sec);
+ tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec);
+
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char *>(&tv),
+ sizeof(tv));
+ }
+ {
+ timeval tv;
+ tv.tv_sec = static_cast<long>(write_timeout_sec);
+ tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec);
+
+ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char *>(&tv),
+ sizeof(tv));
+ }
+}
inline SSLSocketStream::~SSLSocketStream() {}
@@ -4469,24 +5675,25 @@ inline bool SSLSocketStream::is_readable() const {
}
inline bool SSLSocketStream::is_writable() const {
- return detail::select_write(sock_, 0, 0) > 0;
+ return detail::select_write(sock_, write_timeout_sec_, write_timeout_usec_) >
+ 0;
}
-inline int SSLSocketStream::read(char *ptr, size_t size) {
- if (SSL_pending(ssl_) > 0 ||
- select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0) {
+inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
+ if (SSL_pending(ssl_) > 0 || is_readable()) {
return SSL_read(ssl_, ptr, static_cast<int>(size));
}
return -1;
}
-inline int SSLSocketStream::write(const char *ptr, size_t size) {
+inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
if (is_writable()) { return SSL_write(ssl_, ptr, static_cast<int>(size)); }
return -1;
}
-inline std::string SSLSocketStream::get_remote_addr() const {
- return detail::get_remote_addr(sock_);
+inline void SSLSocketStream::get_remote_ip_and_port(std::string &ip,
+ int &port) const {
+ detail::get_remote_ip_and_port(sock_, ip, port);
}
static SSLInit sslinit_;
@@ -4532,6 +5739,33 @@ inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path,
}
}
+inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key,
+ X509_STORE *client_ca_cert_store) {
+ ctx_ = SSL_CTX_new(SSLv23_server_method());
+
+ if (ctx_) {
+ SSL_CTX_set_options(ctx_,
+ SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
+ SSL_OP_NO_COMPRESSION |
+ SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+
+ if (SSL_CTX_use_certificate(ctx_, cert) != 1 ||
+ SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) {
+ SSL_CTX_free(ctx_);
+ ctx_ = nullptr;
+ } else if (client_ca_cert_store) {
+
+ SSL_CTX_set_cert_store(ctx_, client_ca_cert_store);
+
+ SSL_CTX_set_verify(
+ ctx_,
+ SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT, // SSL_VERIFY_CLIENT_ONCE,
+ nullptr);
+ }
+ }
+}
+
inline SSLServer::~SSLServer() {
if (ctx_) { SSL_CTX_free(ctx_); }
}
@@ -4539,21 +5773,39 @@ inline SSLServer::~SSLServer() {
inline bool SSLServer::is_valid() const { return ctx_; }
inline bool SSLServer::process_and_close_socket(socket_t sock) {
- return detail::process_and_close_socket_ssl(
- false, sock, keep_alive_max_count_, read_timeout_sec_, read_timeout_usec_,
- ctx_, ctx_mutex_, SSL_accept, [](SSL * /*ssl*/) { return true; },
- [this](SSL *ssl, Stream &strm, bool last_connection,
- bool &connection_close) {
- return process_request(strm, last_connection, connection_close,
- [&](Request &req) { req.ssl = ssl; });
- });
+ auto ssl = detail::ssl_new(sock, ctx_, ctx_mutex_, SSL_accept,
+ [](SSL * /*ssl*/) { return true; });
+
+ if (ssl) {
+ auto ret = detail::process_server_socket_ssl(
+ ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
+ read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
+ write_timeout_usec_,
+ [this, ssl](Stream &strm, bool close_connection,
+ bool &connection_closed) {
+ return process_request(strm, close_connection, connection_closed,
+ [&](Request &req) { req.ssl = ssl; });
+ });
+
+ detail::ssl_delete(ctx_mutex_, ssl, ret);
+ return ret;
+ }
+
+ detail::close_socket(sock);
+ return false;
}
// SSL HTTP client implementation
+inline SSLClient::SSLClient(const std::string &host)
+ : SSLClient(host, 443, std::string(), std::string()) {}
+
+inline SSLClient::SSLClient(const std::string &host, int port)
+ : SSLClient(host, port, std::string(), std::string()) {}
+
inline SSLClient::SSLClient(const std::string &host, int port,
const std::string &client_cert_path,
const std::string &client_key_path)
- : Client(host, port, client_cert_path, client_key_path) {
+ : ClientImpl(host, port, client_cert_path, client_key_path) {
ctx_ = SSL_CTX_new(SSLv23_client_method());
detail::split(&host_[0], &host_[host_.size()], '.',
@@ -4571,6 +5823,24 @@ inline SSLClient::SSLClient(const std::string &host, int port,
}
}
+inline SSLClient::SSLClient(const std::string &host, int port,
+ X509 *client_cert, EVP_PKEY *client_key)
+ : ClientImpl(host, port) {
+ ctx_ = SSL_CTX_new(SSLv23_client_method());
+
+ detail::split(&host_[0], &host_[host_.size()], '.',
+ [&](const char *b, const char *e) {
+ host_components_.emplace_back(std::string(b, e));
+ });
+ if (client_cert != nullptr && client_key != nullptr) {
+ if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 ||
+ SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) {
+ SSL_CTX_free(ctx_);
+ ctx_ = nullptr;
+ }
+ }
+}
+
inline SSLClient::~SSLClient() {
if (ctx_) { SSL_CTX_free(ctx_); }
}
@@ -4583,67 +5853,178 @@ inline void SSLClient::set_ca_cert_path(const char *ca_cert_file_path,
if (ca_cert_dir_path) { ca_cert_dir_path_ = ca_cert_dir_path; }
}
-inline void SSLClient::enable_server_certificate_verification(bool enabled) {
- server_certificate_verification_ = enabled;
+inline void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) {
+ if (ca_cert_store) {
+ if (ctx_) {
+ if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store) {
+ // Free memory allocated for old cert and use new store `ca_cert_store`
+ SSL_CTX_set_cert_store(ctx_, ca_cert_store);
+ }
+ } else {
+ X509_STORE_free(ca_cert_store);
+ }
+ }
}
inline long SSLClient::get_openssl_verify_result() const {
return verify_result_;
}
-inline SSL_CTX *SSLClient::ssl_context() const noexcept { return ctx_; }
+inline SSL_CTX *SSLClient::ssl_context() const { return ctx_; }
+
+inline bool SSLClient::create_and_connect_socket(Socket &socket) {
+ return is_valid() && ClientImpl::create_and_connect_socket(socket);
+}
+
+inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
+ bool &success) {
+ success = true;
+ Response res2;
+
+ if (!detail::process_client_socket(
+ socket.sock, read_timeout_sec_, read_timeout_usec_,
+ write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
+ Request req2;
+ req2.method = "CONNECT";
+ req2.path = host_and_port_;
+ return process_request(strm, req2, res2, false);
+ })) {
+ close_socket(socket, true);
+ success = false;
+ return false;
+ }
+
+ if (res2.status == 407) {
+ if (!proxy_digest_auth_username_.empty() &&
+ !proxy_digest_auth_password_.empty()) {
+ std::map<std::string, std::string> auth;
+ if (detail::parse_www_authenticate(res2, auth, true)) {
+ Response res3;
+ if (!detail::process_client_socket(
+ socket.sock, read_timeout_sec_, read_timeout_usec_,
+ write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
+ Request req3;
+ req3.method = "CONNECT";
+ req3.path = host_and_port_;
+ req3.headers.insert(detail::make_digest_authentication_header(
+ req3, auth, 1, detail::random_string(10),
+ proxy_digest_auth_username_, proxy_digest_auth_password_,
+ true));
+ return process_request(strm, req3, res3, false);
+ })) {
+ close_socket(socket, true);
+ success = false;
+ return false;
+ }
+ }
+ } else {
+ res = res2;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+inline bool SSLClient::load_certs() {
+ bool ret = true;
+
+ std::call_once(initialize_cert_, [&]() {
+ std::lock_guard<std::mutex> guard(ctx_mutex_);
+ if (!ca_cert_file_path_.empty()) {
+ if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(),
+ nullptr)) {
+ ret = false;
+ }
+ } else if (!ca_cert_dir_path_.empty()) {
+ if (!SSL_CTX_load_verify_locations(ctx_, nullptr,
+ ca_cert_dir_path_.c_str())) {
+ ret = false;
+ }
+ } else {
+#ifdef _WIN32
+ detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_));
+#else
+ SSL_CTX_set_default_verify_paths(ctx_);
+#endif
+ }
+ });
+
+ return ret;
+}
+
+inline bool SSLClient::initialize_ssl(Socket &socket) {
+ auto ssl = detail::ssl_new(
+ socket.sock, ctx_, ctx_mutex_,
+ [&](SSL *ssl) {
+ if (server_certificate_verification_) {
+ if (!load_certs()) {
+ error_ = Error::SSLLoadingCerts;
+ return false;
+ }
+ SSL_set_verify(ssl, SSL_VERIFY_NONE, nullptr);
+ }
-inline bool SSLClient::process_and_close_socket(
- socket_t sock, size_t request_count,
- std::function<bool(Stream &strm, bool last_connection,
- bool &connection_close)>
- callback) {
+ if (SSL_connect(ssl) != 1) {
+ error_ = Error::SSLConnection;
+ return false;
+ }
- request_count = std::min(request_count, keep_alive_max_count_);
+ if (server_certificate_verification_) {
+ verify_result_ = SSL_get_verify_result(ssl);
- return is_valid() &&
- detail::process_and_close_socket_ssl(
- true, sock, request_count, read_timeout_sec_, read_timeout_usec_,
- ctx_, ctx_mutex_,
- [&](SSL *ssl) {
- if (ca_cert_file_path_.empty()) {
- SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, nullptr);
- } else {
- if (!SSL_CTX_load_verify_locations(
- ctx_, ca_cert_file_path_.c_str(), nullptr)) {
- return false;
- }
- SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr);
- }
+ if (verify_result_ != X509_V_OK) {
+ error_ = Error::SSLServerVerification;
+ return false;
+ }
+
+ auto server_cert = SSL_get_peer_certificate(ssl);
- if (SSL_connect(ssl) != 1) { return false; }
+ if (server_cert == nullptr) {
+ error_ = Error::SSLServerVerification;
+ return false;
+ }
- if (server_certificate_verification_) {
- verify_result_ = SSL_get_verify_result(ssl);
+ if (!verify_host(server_cert)) {
+ X509_free(server_cert);
+ error_ = Error::SSLServerVerification;
+ return false;
+ }
+ X509_free(server_cert);
+ }
- if (verify_result_ != X509_V_OK) { return false; }
+ return true;
+ },
+ [&](SSL *ssl) {
+ SSL_set_tlsext_host_name(ssl, host_.c_str());
+ return true;
+ });
- auto server_cert = SSL_get_peer_certificate(ssl);
+ if (ssl) {
+ socket.ssl = ssl;
+ return true;
+ }
- if (server_cert == nullptr) { return false; }
+ close_socket(socket, false);
+ return false;
+}
- if (!verify_host(server_cert)) {
- X509_free(server_cert);
- return false;
- }
- X509_free(server_cert);
- }
+inline void SSLClient::close_socket(Socket &socket, bool process_socket_ret) {
+ detail::close_socket(socket.sock);
+ socket_.sock = INVALID_SOCKET;
+ if (socket.ssl) {
+ detail::ssl_delete(ctx_mutex_, socket.ssl, process_socket_ret);
+ socket_.ssl = nullptr;
+ }
+}
- return true;
- },
- [&](SSL *ssl) {
- SSL_set_tlsext_host_name(ssl, host_.c_str());
- return true;
- },
- [&](SSL * /*ssl*/, Stream &strm, bool last_connection,
- bool &connection_close) {
- return callback(strm, last_connection, connection_close);
- });
+inline bool
+SSLClient::process_socket(Socket &socket,
+ std::function<bool(Stream &strm)> callback) {
+ assert(socket.ssl);
+ return detail::process_client_socket_ssl(
+ socket.ssl, socket.sock, read_timeout_sec_, read_timeout_usec_,
+ write_timeout_sec_, write_timeout_usec_, callback);
}
inline bool SSLClient::is_ssl() const { return true; }
@@ -4703,7 +6084,7 @@ SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const {
auto count = sk_GENERAL_NAME_num(alt_names);
- for (auto i = 0; i < count && !dsn_matched; i++) {
+ for (decltype(count) i = 0; i < count && !dsn_matched; i++) {
auto val = sk_GENERAL_NAME_value(alt_names, i);
if (val->type == type) {
auto name = (const char *)ASN1_STRING_get0_data(val->d.ia5);
@@ -4728,7 +6109,6 @@ SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const {
}
GENERAL_NAMES_free((STACK_OF(GENERAL_NAME) *)alt_names);
-
return ret;
}
@@ -4740,7 +6120,9 @@ inline bool SSLClient::verify_host_with_common_name(X509 *server_cert) const {
auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
name, sizeof(name));
- if (name_len != -1) { return check_host_name(name, name_len); }
+ if (name_len != -1) {
+ return check_host_name(name, static_cast<size_t>(name_len));
+ }
}
return false;
@@ -4775,6 +6157,327 @@ inline bool SSLClient::check_host_name(const char *pattern,
}
#endif
+// Universal client implementation
+inline Client::Client(const char *scheme_host_port)
+ : Client(scheme_host_port, std::string(), std::string()) {}
+
+inline Client::Client(const char *scheme_host_port,
+ const std::string &client_cert_path,
+ const std::string &client_key_path) {
+ const static std::regex re(R"(^(?:([a-z]+)://)?([^:/?#]+)(?::(\d+))?)");
+
+ std::cmatch m;
+ if (std::regex_match(scheme_host_port, m, re)) {
+ auto scheme = m[1].str();
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ if (!scheme.empty() && (scheme != "http" && scheme != "https")) {
+#else
+ if (!scheme.empty() && scheme != "http") {
+#endif
+ return;
+ }
+
+ auto is_ssl = scheme == "https";
+
+ auto host = m[2].str();
+
+ auto port_str = m[3].str();
+ auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);
+
+ if (is_ssl) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+ cli_ = std::make_shared<SSLClient>(host.c_str(), port, client_cert_path,
+ client_key_path);
+ is_ssl_ = is_ssl;
+#endif
+ } else {
+ cli_ = std::make_shared<ClientImpl>(host.c_str(), port, client_cert_path,
+ client_key_path);
+ }
+ } else {
+ cli_ = std::make_shared<ClientImpl>(scheme_host_port, 80, client_cert_path,
+ client_key_path);
+ }
+}
+
+inline Client::Client(const std::string &host, int port)
+ : cli_(std::make_shared<ClientImpl>(host, port)) {}
+
+inline Client::Client(const std::string &host, int port,
+ const std::string &client_cert_path,
+ const std::string &client_key_path)
+ : cli_(std::make_shared<ClientImpl>(host, port, client_cert_path,
+ client_key_path)) {}
+
+inline Client::~Client() {}
+
+inline bool Client::is_valid() const {
+ return cli_ != nullptr && cli_->is_valid();
+}
+
+inline Result Client::Get(const char *path) { return cli_->Get(path); }
+inline Result Client::Get(const char *path, const Headers &headers) {
+ return cli_->Get(path, headers);
+}
+inline Result Client::Get(const char *path, Progress progress) {
+ return cli_->Get(path, progress);
+}
+inline Result Client::Get(const char *path, const Headers &headers,
+ Progress progress) {
+ return cli_->Get(path, headers, progress);
+}
+inline Result Client::Get(const char *path, ContentReceiver content_receiver) {
+ return cli_->Get(path, std::move(content_receiver));
+}
+inline Result Client::Get(const char *path, const Headers &headers,
+ ContentReceiver content_receiver) {
+ return cli_->Get(path, headers, std::move(content_receiver));
+}
+inline Result Client::Get(const char *path, ContentReceiver content_receiver,
+ Progress progress) {
+ return cli_->Get(path, std::move(content_receiver), std::move(progress));
+}
+inline Result Client::Get(const char *path, const Headers &headers,
+ ContentReceiver content_receiver, Progress progress) {
+ return cli_->Get(path, headers, std::move(content_receiver),
+ std::move(progress));
+}
+inline Result Client::Get(const char *path, ResponseHandler response_handler,
+ ContentReceiver content_receiver) {
+ return cli_->Get(path, std::move(response_handler),
+ std::move(content_receiver));
+}
+inline Result Client::Get(const char *path, const Headers &headers,
+ ResponseHandler response_handler,
+ ContentReceiver content_receiver) {
+ return cli_->Get(path, headers, std::move(response_handler),
+ std::move(content_receiver));
+}
+inline Result Client::Get(const char *path, ResponseHandler response_handler,
+ ContentReceiver content_receiver, Progress progress) {
+ return cli_->Get(path, std::move(response_handler),
+ std::move(content_receiver), std::move(progress));
+}
+inline Result Client::Get(const char *path, const Headers &headers,
+ ResponseHandler response_handler,
+ ContentReceiver content_receiver, Progress progress) {
+ return cli_->Get(path, headers, response_handler, content_receiver, progress);
+}
+
+inline Result Client::Head(const char *path) { return cli_->Head(path); }
+inline Result Client::Head(const char *path, const Headers &headers) {
+ return cli_->Head(path, headers);
+}
+
+inline Result Client::Post(const char *path) { return cli_->Post(path); }
+inline Result Client::Post(const char *path, const std::string &body,
+ const char *content_type) {
+ return cli_->Post(path, body, content_type);
+}
+inline Result Client::Post(const char *path, const Headers &headers,
+ const std::string &body, const char *content_type) {
+ return cli_->Post(path, headers, body, content_type);
+}
+inline Result Client::Post(const char *path, size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
+ return cli_->Post(path, content_length, content_provider, content_type);
+}
+inline Result Client::Post(const char *path, const Headers &headers,
+ size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
+ return cli_->Post(path, headers, content_length, content_provider,
+ content_type);
+}
+inline Result Client::Post(const char *path, const Params &params) {
+ return cli_->Post(path, params);
+}
+inline Result Client::Post(const char *path, const Headers &headers,
+ const Params &params) {
+ return cli_->Post(path, headers, params);
+}
+inline Result Client::Post(const char *path,
+ const MultipartFormDataItems &items) {
+ return cli_->Post(path, items);
+}
+inline Result Client::Post(const char *path, const Headers &headers,
+ const MultipartFormDataItems &items) {
+ return cli_->Post(path, headers, items);
+}
+inline Result Client::Put(const char *path) { return cli_->Put(path); }
+inline Result Client::Put(const char *path, const std::string &body,
+ const char *content_type) {
+ return cli_->Put(path, body, content_type);
+}
+inline Result Client::Put(const char *path, const Headers &headers,
+ const std::string &body, const char *content_type) {
+ return cli_->Put(path, headers, body, content_type);
+}
+inline Result Client::Put(const char *path, size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
+ return cli_->Put(path, content_length, content_provider, content_type);
+}
+inline Result Client::Put(const char *path, const Headers &headers,
+ size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
+ return cli_->Put(path, headers, content_length, content_provider,
+ content_type);
+}
+inline Result Client::Put(const char *path, const Params &params) {
+ return cli_->Put(path, params);
+}
+inline Result Client::Put(const char *path, const Headers &headers,
+ const Params &params) {
+ return cli_->Put(path, headers, params);
+}
+inline Result Client::Patch(const char *path, const std::string &body,
+ const char *content_type) {
+ return cli_->Patch(path, body, content_type);
+}
+inline Result Client::Patch(const char *path, const Headers &headers,
+ const std::string &body, const char *content_type) {
+ return cli_->Patch(path, headers, body, content_type);
+}
+inline Result Client::Patch(const char *path, size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
+ return cli_->Patch(path, content_length, content_provider, content_type);
+}
+inline Result Client::Patch(const char *path, const Headers &headers,
+ size_t content_length,
+ ContentProvider content_provider,
+ const char *content_type) {
+ return cli_->Patch(path, headers, content_length, content_provider,
+ content_type);
+}
+inline Result Client::Delete(const char *path) { return cli_->Delete(path); }
+inline Result Client::Delete(const char *path, const std::string &body,
+ const char *content_type) {
+ return cli_->Delete(path, body, content_type);
+}
+inline Result Client::Delete(const char *path, const Headers &headers) {
+ return cli_->Delete(path, headers);
+}
+inline Result Client::Delete(const char *path, const Headers &headers,
+ const std::string &body,
+ const char *content_type) {
+ return cli_->Delete(path, headers, body, content_type);
+}
+inline Result Client::Options(const char *path) { return cli_->Options(path); }
+inline Result Client::Options(const char *path, const Headers &headers) {
+ return cli_->Options(path, headers);
+}
+
+inline bool Client::send(const Request &req, Response &res) {
+ return cli_->send(req, res);
+}
+
+inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); }
+
+inline void Client::stop() { cli_->stop(); }
+
+inline void Client::set_default_headers(Headers headers) {
+ cli_->set_default_headers(std::move(headers));
+}
+
+inline void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); }
+inline void Client::set_socket_options(SocketOptions socket_options) {
+ cli_->set_socket_options(socket_options);
+}
+
+inline void Client::set_connection_timeout(time_t sec, time_t usec) {
+ cli_->set_connection_timeout(sec, usec);
+}
+inline void Client::set_read_timeout(time_t sec, time_t usec) {
+ cli_->set_read_timeout(sec, usec);
+}
+inline void Client::set_write_timeout(time_t sec, time_t usec) {
+ cli_->set_write_timeout(sec, usec);
+}
+
+inline void Client::set_basic_auth(const char *username, const char *password) {
+ cli_->set_basic_auth(username, password);
+}
+inline void Client::set_bearer_token_auth(const char *token) {
+ cli_->set_bearer_token_auth(token);
+}
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+inline void Client::set_digest_auth(const char *username,
+ const char *password) {
+ cli_->set_digest_auth(username, password);
+}
+#endif
+
+inline void Client::set_keep_alive(bool on) { cli_->set_keep_alive(on); }
+inline void Client::set_follow_location(bool on) {
+ cli_->set_follow_location(on);
+}
+
+inline void Client::set_compress(bool on) { cli_->set_compress(on); }
+
+inline void Client::set_decompress(bool on) { cli_->set_decompress(on); }
+
+inline void Client::set_interface(const char *intf) {
+ cli_->set_interface(intf);
+}
+
+inline void Client::set_proxy(const char *host, int port) {
+ cli_->set_proxy(host, port);
+}
+inline void Client::set_proxy_basic_auth(const char *username,
+ const char *password) {
+ cli_->set_proxy_basic_auth(username, password);
+}
+inline void Client::set_proxy_bearer_token_auth(const char *token) {
+ cli_->set_proxy_bearer_token_auth(token);
+}
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+inline void Client::set_proxy_digest_auth(const char *username,
+ const char *password) {
+ cli_->set_proxy_digest_auth(username, password);
+}
+#endif
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+inline void Client::enable_server_certificate_verification(bool enabled) {
+ cli_->enable_server_certificate_verification(enabled);
+}
+#endif
+
+inline void Client::set_logger(Logger logger) { cli_->set_logger(logger); }
+
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+inline void Client::set_ca_cert_path(const char *ca_cert_file_path,
+ const char *ca_cert_dir_path) {
+ if (is_ssl_) {
+ static_cast<SSLClient &>(*cli_).set_ca_cert_path(ca_cert_file_path,
+ ca_cert_dir_path);
+ }
+}
+
+inline void Client::set_ca_cert_store(X509_STORE *ca_cert_store) {
+ if (is_ssl_) {
+ static_cast<SSLClient &>(*cli_).set_ca_cert_store(ca_cert_store);
+ }
+}
+
+inline long Client::get_openssl_verify_result() const {
+ if (is_ssl_) {
+ return static_cast<SSLClient &>(*cli_).get_openssl_verify_result();
+ }
+ return -1; // NOTE: -1 doesn't match any of X509_V_ERR_???
+}
+
+inline SSL_CTX *Client::ssl_context() const {
+ if (is_ssl_) { return static_cast<SSLClient &>(*cli_).ssl_context(); }
+ return nullptr;
+}
+#endif
+
// ----------------------------------------------------------------------------
} // namespace httplib
diff --git a/externals/libusb b/externals/libusb
deleted file mode 160000
-Subproject 3406d72cda879f8792a88bf5f6bd0b7a65636f7
diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt
new file mode 100644
index 000000000..c0d24b126
--- /dev/null
+++ b/externals/libusb/CMakeLists.txt
@@ -0,0 +1,150 @@
+add_library(usb STATIC EXCLUDE_FROM_ALL
+ libusb/libusb/core.c
+ libusb/libusb/core.c
+ libusb/libusb/descriptor.c
+ libusb/libusb/hotplug.c
+ libusb/libusb/io.c
+ libusb/libusb/strerror.c
+ libusb/libusb/sync.c
+)
+set_target_properties(usb PROPERTIES VERSION 1.0.23)
+if(WIN32)
+ target_include_directories(usb
+ BEFORE
+ PUBLIC
+ libusb/libusb
+
+ PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ )
+
+ if (NOT MINGW)
+ target_include_directories(usb BEFORE PRIVATE libusb/msvc)
+ endif()
+
+ # Works around other libraries providing their own definition of USB GUIDs (e.g. SDL2)
+ target_compile_definitions(usb PRIVATE "-DGUID_DEVINTERFACE_USB_DEVICE=(GUID){ 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}")
+else()
+target_include_directories(usb
+ # turns out other projects also have "config.h", so make sure the
+ # LibUSB one comes first
+ BEFORE
+
+ PUBLIC
+ libusb/libusb
+
+ PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}"
+)
+endif()
+
+if(WIN32 OR CYGWIN)
+ target_sources(usb PRIVATE
+ libusb/libusb/os/threads_windows.c
+ libusb/libusb/os/windows_winusb.c
+ libusb/libusb/os/windows_usbdk.c
+ libusb/libusb/os/windows_nt_common.c
+ )
+ set(OS_WINDOWS TRUE)
+elseif(APPLE)
+ target_sources(usb PRIVATE
+ libusb/libusb/os/darwin_usb.c
+ )
+ find_library(COREFOUNDATION_LIBRARY CoreFoundation)
+ find_library(IOKIT_LIBRARY IOKit)
+ find_library(OBJC_LIBRARY objc)
+ target_link_libraries(usb PRIVATE
+ ${COREFOUNDATION_LIBRARY}
+ ${IOKIT_LIBRARY}
+ ${OBJC_LIBRARY}
+ )
+ set(OS_DARWIN TRUE)
+elseif(ANDROID)
+ target_sources(usb PRIVATE
+ libusb/libusb/os/linux_usbfs.c
+ libusb/libusb/os/linux_netlink.c
+ )
+ find_library(LOG_LIBRARY log)
+ target_link_libraries(usb PRIVATE ${LOG_LIBRARY})
+ set(OS_LINUX TRUE)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ target_sources(usb PRIVATE
+ libusb/libusb/os/linux_usbfs.c
+ )
+ find_package(Libudev)
+ if(LIBUDEV_FOUND)
+ target_sources(usb PRIVATE
+ libusb/libusb/os/linux_udev.c
+ )
+ target_link_libraries(usb PRIVATE "${LIBUDEV_LIBRARIES}")
+ target_include_directories(usb PRIVATE "${LIBUDEV_INCLUDE_DIR}")
+ set(HAVE_LIBUDEV TRUE)
+ set(USE_UDEV TRUE)
+ else()
+ target_sources(usb PRIVATE
+ libusb/libusb/os/linux_netlink.c
+ )
+ endif()
+ set(OS_LINUX TRUE)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
+ target_sources(usb PRIVATE
+ libusb/libusb/os/netbsd_usb.c
+ )
+ set(OS_NETBSD TRUE)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
+ target_sources(usb PRIVATE
+ libusb/libusb/os/openbsd_usb.c
+ )
+ set(OS_OPENBSD TRUE)
+endif()
+
+if(UNIX)
+ target_sources(usb PRIVATE
+ libusb/libusb/os/poll_posix.c
+ libusb/libusb/os/threads_posix.c
+ )
+ find_package(Threads REQUIRED)
+ if(THREADS_HAVE_PTHREAD_ARG)
+ target_compile_options(usb PUBLIC "-pthread")
+ endif()
+ if(CMAKE_THREAD_LIBS_INIT)
+ target_link_libraries(usb PRIVATE "${CMAKE_THREAD_LIBS_INIT}")
+ endif()
+ set(THREADS_POSIX TRUE)
+elseif(WIN32)
+ target_sources(usb PRIVATE
+ libusb/libusb/os/poll_windows.c
+ libusb/libusb/os/threads_windows.c
+ )
+endif()
+
+include(CheckFunctionExists)
+include(CheckIncludeFiles)
+include(CheckTypeSize)
+check_include_files(asm/types.h HAVE_ASM_TYPES_H)
+check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
+check_include_files(linux/filter.h HAVE_LINUX_FILTER_H)
+check_include_files(linux/netlink.h HAVE_LINUX_NETLINK_H)
+check_include_files(poll.h HAVE_POLL_H)
+check_include_files(signal.h HAVE_SIGNAL_H)
+check_include_files(strings.h HAVE_STRINGS_H)
+check_type_size("struct timespec" STRUCT_TIMESPEC)
+check_function_exists(syslog HAVE_SYSLOG_FUNC)
+check_include_files(syslog.h HAVE_SYSLOG_H)
+check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
+check_include_files(sys/time.h HAVE_SYS_TIME_H)
+check_include_files(sys/types.h HAVE_SYS_TYPES_H)
+
+set(CMAKE_EXTRA_INCLUDE_FILES poll.h)
+check_type_size("nfds_t" nfds_t)
+unset(CMAKE_EXTRA_INCLUDE_FILES)
+if(HAVE_NFDS_T)
+ set(POLL_NFDS_TYPE "nfds_t")
+else()
+ set(POLL_NFDS_TYPE "unsigned int")
+endif()
+
+check_include_files(sys/timerfd.h USBI_TIMERFD_AVAILABLE)
+
+
+configure_file(config.h.in config.h)
diff --git a/externals/libusb/config.h.in b/externals/libusb/config.h.in
new file mode 100644
index 000000000..915b7390f
--- /dev/null
+++ b/externals/libusb/config.h.in
@@ -0,0 +1,90 @@
+/* Default visibility */
+#if defined(__GNUC__) || defined(__clang__)
+ #define DEFAULT_VISIBILITY __attribute__((visibility("default")))
+#elif defined(_MSC_VER)
+ #define DEFAULT_VISIBILITY __declspec(dllexport)
+#endif
+
+/* Start with debug message logging enabled */
+#undef ENABLE_DEBUG_LOGGING
+
+/* Message logging */
+#undef ENABLE_LOGGING
+
+/* Define to 1 if you have the <asm/types.h> header file. */
+#cmakedefine HAVE_ASM_TYPES_H 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#cmakedefine HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `udev' library (-ludev). */
+#cmakedefine HAVE_LIBUDEV 1
+
+/* Define to 1 if you have the <linux/filter.h> header file. */
+#cmakedefine HAVE_LINUX_FILTER_H 1
+
+/* Define to 1 if you have the <linux/netlink.h> header file. */
+#cmakedefine HAVE_LINUX_NETLINK_H 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#cmakedefine HAVE_POLL_H 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#cmakedefine HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine HAVE_STRINGS_H 1
+
+/* Define to 1 if the system has the type `struct timespec'. */
+#cmakedefine HAVE_STRUCT_TIMESPEC 1
+
+/* syslog() function available */
+#cmakedefine HAVE_SYSLOG_FUNC 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#cmakedefine HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#cmakedefine HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#cmakedefine HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H 1
+
+/* Darwin backend */
+#cmakedefine OS_DARWIN 1
+
+/* Linux backend */
+#cmakedefine OS_LINUX 1
+
+/* NetBSD backend */
+#cmakedefine OS_NETBSD 1
+
+/* OpenBSD backend */
+#cmakedefine OS_OPENBSD 1
+
+/* Windows backend */
+#cmakedefine OS_WINDOWS 1
+
+/* type of second poll() argument */
+#define POLL_NFDS_TYPE @POLL_NFDS_TYPE@
+
+/* Use POSIX Threads */
+#cmakedefine THREADS_POSIX
+
+/* timerfd headers available */
+#cmakedefine USBI_TIMERFD_AVAILABLE 1
+
+/* Enable output to system log */
+#define USE_SYSTEM_LOGGING_FACILITY 1
+
+/* Use udev for device enumeration/hotplug */
+#cmakedefine USE_UDEV 1
+
+/* Use GNU extensions */
+#define _GNU_SOURCE
+
+/* Oldest Windows version supported */
+#define WINVER 0x0501
diff --git a/externals/libusb/libusb b/externals/libusb/libusb
new file mode 160000
+Subproject e782eeb2514266f6738e242cdcb18e3ae1ed06f
diff --git a/externals/microprofile/microprofile.h b/externals/microprofile/microprofile.h
index 0c0d0a4d3..85d5bd5de 100644
--- a/externals/microprofile/microprofile.h
+++ b/externals/microprofile/microprofile.h
@@ -152,9 +152,11 @@ typedef uint16_t MicroProfileGroupId;
#include <stdint.h>
#include <string.h>
-#include <thread>
-#include <mutex>
+#include <algorithm>
+#include <array>
#include <atomic>
+#include <mutex>
+#include <thread>
#ifndef MICROPROFILE_API
#define MICROPROFILE_API
@@ -605,28 +607,45 @@ struct MicroProfileFrameState
struct MicroProfileThreadLog
{
- MicroProfileLogEntry Log[MICROPROFILE_BUFFER_SIZE];
+ std::array<MicroProfileLogEntry, MICROPROFILE_BUFFER_SIZE> Log{};
- std::atomic<uint32_t> nPut;
- std::atomic<uint32_t> nGet;
- uint32_t nActive;
- uint32_t nGpu;
- ThreadIdType nThreadId;
+ std::atomic<uint32_t> nPut{0};
+ std::atomic<uint32_t> nGet{0};
+ uint32_t nActive = 0;
+ uint32_t nGpu = 0;
+ ThreadIdType nThreadId{};
- uint32_t nStack[MICROPROFILE_STACK_MAX];
- int64_t nChildTickStack[MICROPROFILE_STACK_MAX];
- uint32_t nStackPos;
+ std::array<uint32_t, MICROPROFILE_STACK_MAX> nStack{};
+ std::array<int64_t, MICROPROFILE_STACK_MAX> nChildTickStack{};
+ uint32_t nStackPos = 0;
- uint8_t nGroupStackPos[MICROPROFILE_MAX_GROUPS];
- int64_t nGroupTicks[MICROPROFILE_MAX_GROUPS];
- int64_t nAggregateGroupTicks[MICROPROFILE_MAX_GROUPS];
+ std::array<uint8_t, MICROPROFILE_MAX_GROUPS> nGroupStackPos{};
+ std::array<int64_t, MICROPROFILE_MAX_GROUPS> nGroupTicks{};
+ std::array<int64_t, MICROPROFILE_MAX_GROUPS> nAggregateGroupTicks{};
enum
{
THREAD_MAX_LEN = 64,
};
- char ThreadName[64];
- int nFreeListNext;
+ char ThreadName[64]{};
+ int nFreeListNext = 0;
+
+ void Reset() {
+ Log.fill({});
+ nPut = 0;
+ nGet = 0;
+ nActive = 0;
+ nGpu = 0;
+ nThreadId = {};
+ nStack.fill(0);
+ nChildTickStack.fill(0);
+ nStackPos = 0;
+ nGroupStackPos.fill(0);
+ nGroupTicks.fill(0);
+ nAggregateGroupTicks.fill(0);
+ std::fill(std::begin(ThreadName), std::end(ThreadName), '\0');
+ nFreeListNext = 0;
+ }
};
#if MICROPROFILE_GPU_TIMERS_D3D11
@@ -1018,7 +1037,7 @@ static void MicroProfileCreateThreadLogKey()
#else
MP_THREAD_LOCAL MicroProfileThreadLog* g_MicroProfileThreadLog = 0;
#endif
-static bool g_bUseLock = false; /// This is used because windows does not support using mutexes under dll init(which is where global initialization is handled)
+static std::atomic<bool> g_bUseLock{false}; /// This is used because windows does not support using mutexes under dll init(which is where global initialization is handled)
MICROPROFILE_DEFINE(g_MicroProfileFlip, "MicroProfile", "MicroProfileFlip", 0x3355ee);
@@ -1151,6 +1170,7 @@ MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName)
MP_ASSERT(pLog->nPut.load() == 0);
MP_ASSERT(pLog->nGet.load() == 0);
S.nFreeListHead = S.Pool[S.nFreeListHead]->nFreeListNext;
+ pLog->Reset();
}
else
{
@@ -1158,7 +1178,6 @@ MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName)
S.nMemUsage += sizeof(MicroProfileThreadLog);
S.Pool[S.nNumLogs++] = pLog;
}
- memset(pLog, 0, sizeof(*pLog));
int len = (int)strlen(pName);
int maxlen = sizeof(pLog->ThreadName)-1;
len = len < maxlen ? len : maxlen;
@@ -1206,8 +1225,8 @@ void MicroProfileOnThreadExit()
{
S.Frames[i].nLogStart[nLogIndex] = 0;
}
- memset(pLog->nGroupStackPos, 0, sizeof(pLog->nGroupStackPos));
- memset(pLog->nGroupTicks, 0, sizeof(pLog->nGroupTicks));
+ pLog->nGroupStackPos.fill(0);
+ pLog->nGroupTicks.fill(0);
}
}
diff --git a/externals/microprofile/microprofileui.h b/externals/microprofile/microprofileui.h
index fe2410cf4..85fbf2cb9 100644
--- a/externals/microprofile/microprofileui.h
+++ b/externals/microprofile/microprofileui.h
@@ -169,14 +169,13 @@ MICROPROFILEUI_API void MicroProfileCustomGroup(const char* pCustomName, uint32_
MICROPROFILEUI_API void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer);
#ifdef MICROPROFILEUI_IMPL
-#ifdef _WIN32
-#define snprintf _snprintf
-#endif
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <algorithm>
+#include <array>
MICROPROFILE_DEFINE(g_MicroProfileDetailed, "MicroProfile", "Detailed View", 0x8888000);
MICROPROFILE_DEFINE(g_MicroProfileDrawGraph, "MicroProfile", "Draw Graph", 0xff44ee00);
@@ -227,10 +226,10 @@ struct SOptionDesc
uint8_t nIndex;
bool bSelected;
};
-static uint32_t g_MicroProfileAggregatePresets[] = {0, 10, 20, 30, 60, 120};
-static float g_MicroProfileReferenceTimePresets[] = {5.f, 10.f, 15.f,20.f, 33.33f, 66.66f, 100.f, 250.f, 500.f, 1000.f};
-static uint32_t g_MicroProfileOpacityPresets[] = {0x40, 0x80, 0xc0, 0xff};
-static const char* g_MicroProfilePresetNames[] =
+static const std::array<uint32_t, 6> g_MicroProfileAggregatePresets{0, 10, 20, 30, 60, 120};
+static const std::array<float, 10> g_MicroProfileReferenceTimePresets{5.f, 10.f, 15.f,20.f, 33.33f, 66.66f, 100.f, 250.f, 500.f, 1000.f};
+static const std::array<uint32_t, 4> g_MicroProfileOpacityPresets{0x40, 0x80, 0xc0, 0xff};
+static const std::array<const char*, 7> g_MicroProfilePresetNames
{
MICROPROFILE_DEFAULT_PRESET,
"Render",
@@ -243,8 +242,8 @@ static const char* g_MicroProfilePresetNames[] =
enum
{
- MICROPROFILE_NUM_REFERENCE_PRESETS = sizeof(g_MicroProfileReferenceTimePresets)/sizeof(g_MicroProfileReferenceTimePresets[0]),
- MICROPROFILE_NUM_OPACITY_PRESETS = sizeof(g_MicroProfileOpacityPresets)/sizeof(g_MicroProfileOpacityPresets[0]),
+ MICROPROFILE_NUM_REFERENCE_PRESETS = g_MicroProfileReferenceTimePresets.size(),
+ MICROPROFILE_NUM_OPACITY_PRESETS = g_MicroProfileOpacityPresets.size(),
#if MICROPROFILE_CONTEXT_SWITCH_TRACE
MICROPROFILE_OPTION_SIZE = MICROPROFILE_NUM_REFERENCE_PRESETS + MICROPROFILE_NUM_OPACITY_PRESETS * 2 + 2 + 7,
#else
@@ -326,9 +325,9 @@ struct MicroProfileUI
MicroProfileUI g_MicroProfileUI;
#define UI g_MicroProfileUI
-static uint32_t g_nMicroProfileBackColors[2] = { 0x474747, 0x313131 };
+static const std::array<uint32_t, 2> g_nMicroProfileBackColors{ 0x474747, 0x313131 };
#define MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS 16
-static uint32_t g_nMicroProfileContextSwitchThreadColors[MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS] = //palette generated by http://tools.medialab.sciences-po.fr/iwanthue/index.php
+static const std::array<uint32_t, MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS> g_nMicroProfileContextSwitchThreadColors //palette generated by http://tools.medialab.sciences-po.fr/iwanthue/index.php
{
0x63607B,
0x755E2B,
@@ -356,7 +355,7 @@ void MicroProfileInitUI()
{
bInitialized = true;
memset(&g_MicroProfileUI, 0, sizeof(g_MicroProfileUI));
- UI.nActiveMenu = (uint32_t)-1;
+ UI.nActiveMenu = UINT32_MAX;
UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f;
UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f;
@@ -368,7 +367,7 @@ void MicroProfileInitUI()
UI.nWidth = 100;
UI.nHeight = 100;
- UI.nCustomActive = (uint32_t)-1;
+ UI.nCustomActive = UINT32_MAX;
UI.nCustomTimerCount = 0;
UI.nCustomCount = 0;
@@ -498,8 +497,8 @@ inline void MicroProfileDrawFloatWindow(uint32_t nX, uint32_t nY, const char** p
{
MicroProfileDrawBox(nX-MICROPROFILE_TEXT_WIDTH, nY, nX, nY + MICROPROFILE_TEXT_WIDTH, pColors[i]|0xff000000);
}
- MicroProfileDrawText(nX + 1, nY + 1, (uint32_t)-1, ppStrings[i0], (uint32_t)strlen(ppStrings[i0]));
- MicroProfileDrawText(nX + nWidth - nStringLengths[i0+1] * (MICROPROFILE_TEXT_WIDTH+1), nY + 1, (uint32_t)-1, ppStrings[i0+1], (uint32_t)strlen(ppStrings[i0+1]));
+ MicroProfileDrawText(nX + 1, nY + 1, UINT32_MAX, ppStrings[i0], (uint32_t)strlen(ppStrings[i0]));
+ MicroProfileDrawText(nX + nWidth - nStringLengths[i0+1] * (MICROPROFILE_TEXT_WIDTH+1), nY + 1, UINT32_MAX, ppStrings[i0+1], (uint32_t)strlen(ppStrings[i0+1]));
nY += (MICROPROFILE_TEXT_HEIGHT+1);
}
}
@@ -522,7 +521,7 @@ inline void MicroProfileDrawTextBox(uint32_t nX, uint32_t nY, const char** ppStr
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000);
for(uint32_t i = 0; i < nNumStrings; ++i)
{
- MicroProfileDrawText(nX + 1, nY + 1, (uint32_t)-1, ppStrings[i], (uint32_t)strlen(ppStrings[i]));
+ MicroProfileDrawText(nX + 1, nY + 1, UINT32_MAX, ppStrings[i], (uint32_t)strlen(ppStrings[i]));
nY += (MICROPROFILE_TEXT_HEIGHT+1);
}
}
@@ -781,7 +780,7 @@ inline void MicroProfileDrawDetailedContextSwitchBars(uint32_t nY, uint32_t nThr
{
MicroProfile& S = *MicroProfileGet();
int64_t nTickIn = -1;
- uint32_t nThreadBefore = -1;
+ uint32_t nThreadBefore = UINT32_MAX;
float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
float fMsToScreen = UI.nWidth / UI.fDetailedRange;
float fMouseX = (float)UI.nMouseX;
@@ -949,10 +948,10 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
uint32_t nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadAfter;
uint32_t nContextSwitchHoverThreadBefore = S.nContextSwitchHoverThreadBefore;
- S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = -1;
+ S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = UINT32_MAX;
- uint32_t nContextSwitchStart = -1;
- uint32_t nContextSwitchEnd = -1;
+ uint32_t nContextSwitchStart = UINT32_MAX;
+ uint32_t nContextSwitchEnd = UINT32_MAX;
S.nContextSwitchHoverCpuNext = 0xff;
S.nContextSwitchHoverTickIn = -1;
S.nContextSwitchHoverTickOut = -1;
@@ -1005,9 +1004,10 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
}while(pFrameLogFirst != pFrameFirst);
- if(nGet == (uint32_t)-1)
+ if (nGet == UINT32_MAX) {
continue;
- MP_ASSERT(nGet != (uint32_t)-1);
+ }
+ MP_ASSERT(nGet != UINT32_MAX);
nPut = pFrameLogLast->nLogStart[i];
@@ -1023,9 +1023,9 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
int64_t nBaseTicks = bGpu ? nBaseTicksGpu : nBaseTicksCpu;
char ThreadName[MicroProfileThreadLog::THREAD_MAX_LEN + 16];
uint64_t nThreadId = pLog->nThreadId;
- snprintf(ThreadName, sizeof(ThreadName)-1, "%04llx: %s", nThreadId, &pLog->ThreadName[0] );
+ snprintf(ThreadName, sizeof(ThreadName)-1, "%04" PRIx64 ": %s", nThreadId, &pLog->ThreadName[0] );
nY += 3;
- uint32_t nThreadColor = -1;
+ uint32_t nThreadColor = UINT32_MAX;
if(pLog->nThreadId == nContextSwitchHoverThreadAfter || pLog->nThreadId == nContextSwitchHoverThreadBefore)
nThreadColor = UI.nHoverColorShared|0x906060;
MicroProfileDrawText(0, nY, nThreadColor, &ThreadName[0], (uint32_t)strlen(&ThreadName[0]));
@@ -1048,7 +1048,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
uint32_t nEnd = nRange[j][1];
for(uint32_t k = nStart; k < nEnd; ++k)
{
- MicroProfileLogEntry* pEntry = pLog->Log + k;
+ MicroProfileLogEntry* pEntry = &pLog->Log[k];
int nType = MicroProfileLogType(*pEntry);
if(MP_LOG_ENTER == nType)
{
@@ -1066,7 +1066,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
continue;
}
- MicroProfileLogEntry* pEntryEnter = pLog->Log + nStack[nStackPos-1];
+ MicroProfileLogEntry* pEntryEnter = &pLog->Log[nStack[nStackPos-1]];
if(MicroProfileLogTimerIndex(*pEntryEnter) != MicroProfileLogTimerIndex(*pEntry))
{
//uprintf("mismatch %llx %llx\n", pEntryEnter->nToken, pEntry->nToken);
@@ -1126,7 +1126,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
uint32_t nIntegerWidth = (uint32_t)(fXEnd - fXStart);
if(nIntegerWidth)
{
- if(bHover && UI.nActiveMenu == -1)
+ if(bHover && UI.nActiveMenu == UINT32_MAX)
{
nHoverToken = MicroProfileLogTimerIndex(*pEntry);
#if MICROPROFILE_DEBUG
@@ -1146,7 +1146,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
int nCharacters = (nTextWidth - 2*MICROPROFILE_TEXT_WIDTH) / MICROPROFILE_TEXT_WIDTH;
if(nCharacters>0)
{
- MicroProfileDrawText(fXStartText+1, fYStart+1, -1, S.TimerInfo[nTimerIndex].pName, MicroProfileMin<uint32_t>(S.TimerInfo[nTimerIndex].nNameLen, nCharacters));
+ MicroProfileDrawText(fXStartText + 1, fYStart + 1, UINT32_MAX, S.TimerInfo[nTimerIndex].pName, MicroProfileMin<uint32_t>(S.TimerInfo[nTimerIndex].nNameLen, nCharacters));
}
}
#endif
@@ -1158,7 +1158,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
int nLineX = (int)floor(fXAvg+0.5f);
if(nLineX != (int)nLinesDrawn[nStackPos])
{
- if(bHover && UI.nActiveMenu == -1)
+ if(bHover && UI.nActiveMenu == UINT32_MAX)
{
nHoverToken = (uint32_t)MicroProfileLogTimerIndex(*pEntry);
nHoverTime = MicroProfileLogTickDifference(nTickStart, nTickEnd);
@@ -1235,9 +1235,9 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
// nThreadId is 32-bit on Windows
int nStrLen = snprintf(ThreadName, sizeof(ThreadName)-1, "%04x: %s%s", nThreadId, cLocal, i < nNumThreadsBase ? &S.Pool[i]->ThreadName[0] : MICROPROFILE_THREAD_NAME_FROM_ID(nThreadId) );
#else
- int nStrLen = snprintf(ThreadName, sizeof(ThreadName)-1, "%04llx: %s%s", nThreadId, cLocal, i < nNumThreadsBase ? &S.Pool[i]->ThreadName[0] : MICROPROFILE_THREAD_NAME_FROM_ID(nThreadId) );
+ int nStrLen = snprintf(ThreadName, sizeof(ThreadName)-1, "%04" PRIx64 ": %s%s", nThreadId, cLocal, i < nNumThreadsBase ? &S.Pool[i]->ThreadName[0] : MICROPROFILE_THREAD_NAME_FROM_ID(nThreadId) );
#endif
- uint32_t nThreadColor = -1;
+ uint32_t nThreadColor = UINT32_MAX;
if(nThreadId == nContextSwitchHoverThreadAfter || nThreadId == nContextSwitchHoverThreadBefore)
nThreadColor = UI.nHoverColorShared|0x906060;
MicroProfileDrawDetailedContextSwitchBars(nY+2, nThreadId, nContextSwitchStart, nContextSwitchEnd, nBaseTicksCpu, nBaseY);
@@ -1249,9 +1249,6 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
S.nContextSwitchHoverCpu = S.nContextSwitchHoverCpuNext;
-
-
-
UI.pDisplayMouseOver = pMouseOverNext;
if(!S.nRunning)
@@ -1286,10 +1283,10 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
float fStartTextX = fXStart - fStartTextWidth - 2;
MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
- MicroProfileDrawText(fStartTextX+1, nBaseY, (uint32_t)-1, sBuffer, nLenStart);
+ MicroProfileDrawText(fStartTextX+1, nBaseY, UINT32_MAX, sBuffer, nLenStart);
uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
- MicroProfileDrawText(fXEnd+2, nBaseY+1, (uint32_t)-1, sBuffer, nLenEnd);
+ MicroProfileDrawText(fXEnd+2, nBaseY+1, UINT32_MAX, sBuffer, nLenEnd);
if(UI.nMouseRight)
{
@@ -1316,10 +1313,10 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
float fStartTextX = fXStart - fStartTextWidth - 2;
MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
- MicroProfileDrawText(fStartTextX+1, nBaseY, (uint32_t)-1, sBuffer, nLenStart);
+ MicroProfileDrawText(fStartTextX+1, nBaseY, UINT32_MAX, sBuffer, nLenStart);
uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
- MicroProfileDrawText(fXEnd+2, nBaseY+1, (uint32_t)-1, sBuffer, nLenEnd);
+ MicroProfileDrawText(fXEnd+2, nBaseY+1, UINT32_MAX, sBuffer, nLenEnd);
}
}
}
@@ -1365,7 +1362,7 @@ inline void MicroProfileDrawDetailedFrameHistory(uint32_t nWidth, uint32_t nHeig
fBaseX = fXStart;
uint32_t nColor = MICROPROFILE_FRAME_HISTORY_COLOR_CPU;
if(nIndex == nSelectedFrame)
- nColor = (uint32_t)-1;
+ nColor = UINT32_MAX;
MicroProfileDrawBox(fXStart, nBaseY + fScale * nBarHeight, fXEnd, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, nColor, MicroProfileBoxTypeBar);
if(pNext->nFrameStartCpu > nCpuStart)
{
@@ -1387,7 +1384,7 @@ inline void MicroProfileDrawDetailedView(uint32_t nWidth, uint32_t nHeight)
uint32_t nBaseY = MICROPROFILE_TEXT_HEIGHT + 1;
int nSelectedFrame = -1;
- if(UI.nMouseY > nBaseY && UI.nMouseY <= nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT && UI.nActiveMenu == -1)
+ if(UI.nMouseY > nBaseY && UI.nMouseY <= nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT && UI.nActiveMenu == UINT32_MAX)
{
nSelectedFrame = ((MICROPROFILE_NUM_FRAMES) * (UI.nWidth-UI.nMouseX) / UI.nWidth);
@@ -1425,7 +1422,7 @@ inline void MicroProfileDrawHeader(int32_t nX, uint32_t nWidth, const char* pNam
if(pName)
{
MicroProfileDrawBox(nX-8, MICROPROFILE_TEXT_HEIGHT + 2, nX + nWidth+5, MICROPROFILE_TEXT_HEIGHT + 2 + (MICROPROFILE_TEXT_HEIGHT+1), 0xff000000|g_nMicroProfileBackColors[1]);
- MicroProfileDrawText(nX, MICROPROFILE_TEXT_HEIGHT + 2, (uint32_t)-1, pName, (uint32_t)strlen(pName));
+ MicroProfileDrawText(nX, MICROPROFILE_TEXT_HEIGHT + 2, UINT32_MAX, pName, (uint32_t)strlen(pName));
}
}
@@ -1440,7 +1437,7 @@ inline void MicroProfileLoopActiveGroupsDraw(int32_t nX, int32_t nY, const char*
uint32_t nCount = 0;
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
{
- uint64_t nMask = 1ll << j;
+ uint64_t nMask = 1ULL << j;
if(nMask & nGroup)
{
nY += MICROPROFILE_TEXT_HEIGHT + 1;
@@ -1521,7 +1518,7 @@ inline void MicroProfileCalcTimers(float* pTimers, float* pAverage, float* pMax,
}
}
}
- nMask <<= 1ll;
+ nMask <<= 1;
}
}
@@ -1543,7 +1540,7 @@ inline void MicroProfileDrawBarArrayCallback(uint32_t nTimer, uint32_t nIdx, uin
snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pTimers[nIdx]);
if (!pTimers2)
MicroProfileDrawBox(nX + nTextWidth, nY, nX + nTextWidth + fWidth * pTimers[nIdx+1], nY + nHeight, UI.nOpacityForeground|S.TimerInfo[nTimer].nColor, MicroProfileBoxTypeBar);
- MicroProfileDrawText(nX, nY, (uint32_t)-1, sBuffer, (uint32_t)strlen(sBuffer));
+ MicroProfileDrawText(nX, nY, UINT32_MAX, sBuffer, (uint32_t)strlen(sBuffer));
}
@@ -1564,7 +1561,7 @@ inline void MicroProfileDrawBarCallCountCallback(uint32_t nTimer, uint32_t nIdx,
MicroProfile& S = *MicroProfileGet();
char sBuffer[SBUF_MAX];
int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5d", S.Frame[nTimer].nCount);//fix
- MicroProfileDrawText(nX, nY, (uint32_t)-1, sBuffer, nLen);
+ MicroProfileDrawText(nX, nY, UINT32_MAX, sBuffer, nLen);
}
inline uint32_t MicroProfileDrawBarCallCount(int32_t nX, int32_t nY, const char* pName)
@@ -1588,7 +1585,7 @@ inline void MicroProfileDrawBarMetaAverageCallback(uint32_t nTimer, uint32_t nId
float fRcpFrames = pArgs->fRcpFrames;
char sBuffer[SBUF_MAX];
int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pCounters[nTimer] * fRcpFrames);
- MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, (uint32_t)-1, sBuffer, nLen);
+ MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, UINT32_MAX, sBuffer, nLen);
}
inline uint32_t MicroProfileDrawBarMetaAverage(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
@@ -1609,8 +1606,8 @@ inline void MicroProfileDrawBarMetaCountCallback(uint32_t nTimer, uint32_t nIdx,
{
uint64_t* pCounters = (uint64_t*)pExtra;
char sBuffer[SBUF_MAX];
- int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5llu", pCounters[nTimer]);
- MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, (uint32_t)-1, sBuffer, nLen);
+ int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5" PRIu64, pCounters[nTimer]);
+ MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, UINT32_MAX, sBuffer, nLen);
}
inline uint32_t MicroProfileDrawBarMetaCount(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
@@ -1667,7 +1664,7 @@ bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight)
if(bMouseOver)
{
float fXAvg = fMouseXPrc * MICROPROFILE_GRAPH_WIDTH + nX;
- MicroProfileDrawLineVertical(fXAvg, nY, nY + MICROPROFILE_GRAPH_HEIGHT, (uint32_t)-1);
+ MicroProfileDrawLineVertical(fXAvg, nY, nY + MICROPROFILE_GRAPH_HEIGHT, UINT32_MAX);
}
@@ -1706,7 +1703,7 @@ bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight)
char buf[32];
int nLen = snprintf(buf, sizeof(buf)-1, "%5.2fms", S.fReferenceTime);
- MicroProfileDrawText(nX+1, fY1 - (2+MICROPROFILE_TEXT_HEIGHT), (uint32_t)-1, buf, nLen);
+ MicroProfileDrawText(nX+1, fY1 - (2+MICROPROFILE_TEXT_HEIGHT), UINT32_MAX, buf, nLen);
}
@@ -1782,7 +1779,7 @@ void MicroProfileDumpTimers()
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
{
- uint64_t nMask = 1ll << j;
+ uint64_t nMask = 1ULL << j;
if(nMask & nActiveGroup)
{
MICROPROFILE_PRINTF("%s\n", S.GroupInfo[j].pName);
@@ -1823,7 +1820,7 @@ inline void MicroProfileDrawBarView(uint32_t nScreenWidth, uint32_t nScreenHeigh
uint32_t nNumGroups = 0;
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
{
- if(nActiveGroup & (1ll << j))
+ if(nActiveGroup & (1ULL << j))
{
nNumTimers += S.GroupInfo[j].nNumTimers;
nNumGroups += 1;
@@ -1878,7 +1875,7 @@ inline void MicroProfileDrawBarView(uint32_t nScreenWidth, uint32_t nScreenHeigh
for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
{
uint32_t nY0 = nY + i * (nHeight + 1);
- bool bInside = (UI.nActiveMenu == -1) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
+ bool bInside = (UI.nActiveMenu == UINT32_MAX) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
MicroProfileDrawBox(nX, nY0, nWidth+nX, nY0 + (nHeight+1)+1, UI.nOpacityBackground | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
}
nX += 10;
@@ -1927,22 +1924,22 @@ inline void MicroProfileDrawBarView(uint32_t nScreenWidth, uint32_t nScreenHeigh
nY = nHeight + 3 - UI.nOffsetY;
for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
{
- uint32_t nY0 = nY + i * (nHeight + 1);
- bool bInside = (UI.nActiveMenu == -1) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
+ const uint32_t nY0 = nY + i * (nHeight + 1);
+ const bool bInside = (UI.nActiveMenu == UINT32_MAX) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
MicroProfileDrawBox(nX, nY0, nTimerWidth, nY0 + (nHeight+1)+1, 0xff0000000 | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
}
nX += MicroProfileDrawBarLegend(nX, nY, nTotalHeight, nTimerWidth-5) + 1;
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
{
- if(nActiveGroup & (1ll << j))
+ if(nActiveGroup & (1ULL << j))
{
- MicroProfileDrawText(nX, nY + (1+nHeight) * nLegendOffset, (uint32_t)-1, S.GroupInfo[j].pName, S.GroupInfo[j].nNameLen);
+ MicroProfileDrawText(nX, nY + (1+nHeight) * nLegendOffset, UINT32_MAX, S.GroupInfo[j].pName, S.GroupInfo[j].nNameLen);
nLegendOffset += S.GroupInfo[j].nNumTimers+1;
}
}
MicroProfileDrawHeader(nX, nTimerWidth-5, "Group");
- MicroProfileDrawTextRight(nTimerWidth-3, MICROPROFILE_TEXT_HEIGHT + 2, (uint32_t)-1, "Timer", 5);
+ MicroProfileDrawTextRight(nTimerWidth-3, MICROPROFILE_TEXT_HEIGHT + 2, UINT32_MAX, "Timer", 5);
MicroProfileDrawLineVertical(nTimerWidth, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
MicroProfileDrawLineHorizontal(0, nWidth, 2*MICROPROFILE_TEXT_HEIGHT + 3, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
}
@@ -2003,7 +2000,7 @@ inline const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
}
else
{
- *bSelected = 0 != (S.nActiveGroupWanted & (1ll << Item.nIndex));
+ *bSelected = 0 != (S.nActiveGroupWanted & (1ULL << Item.nIndex));
snprintf(buffer, sizeof(buffer)-1, " %s", Item.pName);
}
return buffer;
@@ -2015,16 +2012,18 @@ inline const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
inline const char* MicroProfileUIMenuAggregate(int nIndex, bool* bSelected)
{
MicroProfile& S = *MicroProfileGet();
- if(nIndex < sizeof(g_MicroProfileAggregatePresets)/sizeof(g_MicroProfileAggregatePresets[0]))
+ if(static_cast<uint32_t>(nIndex) < g_MicroProfileAggregatePresets.size())
{
- int val = g_MicroProfileAggregatePresets[nIndex];
- *bSelected = (int)S.nAggregateFlip == val;
- if(0 == val)
+ uint32_t val = g_MicroProfileAggregatePresets[nIndex];
+ *bSelected = S.nAggregateFlip == val;
+ if (0 == val)
+ {
return "Infinite";
+ }
else
{
static char buf[128];
- snprintf(buf, sizeof(buf)-1, "%7d", val);
+ snprintf(buf, sizeof(buf)-1, "%7u", val);
return buf;
}
}
@@ -2098,11 +2097,13 @@ inline const char* MicroProfileUIMenuPreset(int nIndex, bool* bSelected)
{
static char buf[128];
*bSelected = false;
- int nNumPresets = sizeof(g_MicroProfilePresetNames) / sizeof(g_MicroProfilePresetNames[0]);
+ int nNumPresets = static_cast<int>(g_MicroProfilePresetNames.size());
int nIndexSave = nIndex - nNumPresets - 1;
- if(nIndex == nNumPresets)
+ if (nIndex == nNumPresets)
+ {
return "--";
- else if(nIndexSave >=0 && nIndexSave <nNumPresets)
+ }
+ else if(nIndexSave >=0 && nIndexSave < nNumPresets)
{
snprintf(buf, sizeof(buf)-1, "Save '%s'", g_MicroProfilePresetNames[nIndexSave]);
return buf;
@@ -2120,13 +2121,13 @@ inline const char* MicroProfileUIMenuPreset(int nIndex, bool* bSelected)
inline const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected)
{
- if((uint32_t)-1 == UI.nCustomActive)
+ if(UINT32_MAX == UI.nCustomActive)
{
*bSelected = nIndex == 0;
}
else
{
- *bSelected = nIndex-2 == UI.nCustomActive;
+ *bSelected = nIndex-2 == static_cast<int>(UI.nCustomActive);
}
switch(nIndex)
{
@@ -2202,7 +2203,7 @@ inline void MicroProfileUIClickGroups(int nIndex)
else
{
MP_ASSERT(Item.nIndex < S.nGroupCount);
- S.nActiveGroupWanted ^= (1ll << Item.nIndex);
+ S.nActiveGroupWanted ^= (1ULL << Item.nIndex);
}
}
}
@@ -2273,7 +2274,7 @@ inline void MicroProfileUIClickOptions(int nIndex)
inline void MicroProfileUIClickPreset(int nIndex)
{
- int nNumPresets = sizeof(g_MicroProfilePresetNames) / sizeof(g_MicroProfilePresetNames[0]);
+ int nNumPresets = static_cast<int>(g_MicroProfilePresetNames.size());
int nIndexSave = nIndex - nNumPresets - 1;
if(nIndexSave >= 0 && nIndexSave < nNumPresets)
{
@@ -2310,7 +2311,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
uint32_t nX = 0;
uint32_t nY = 0;
- bool bMouseOver = UI.nMouseY < MICROPROFILE_TEXT_HEIGHT + 1;
+
#define SBUF_SIZE 256
char buffer[256];
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + (MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff000000|g_nMicroProfileBackColors[1]);
@@ -2321,7 +2322,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
uint32_t nNumMenuItems = 0;
int nLen = snprintf(buffer, 127, "MicroProfile");
- MicroProfileDrawText(nX, nY, (uint32_t)-1, buffer, nLen);
+ MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nLen);
nX += (sizeof("MicroProfile")+2) * (MICROPROFILE_TEXT_WIDTH+1);
pMenuText[nNumMenuItems++] = "Mode";
pMenuText[nNumMenuItems++] = "Groups";
@@ -2409,7 +2410,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
};
- uint32_t nSelectMenu = (uint32_t)-1;
+ uint32_t nSelectMenu = UINT32_MAX;
for(uint32_t i = 0; i < nNumMenuItems; ++i)
{
nMenuX[i] = nX;
@@ -2419,17 +2420,17 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
{
MicroProfileDrawBox(nX-1, nY, nX + nLen * (MICROPROFILE_TEXT_WIDTH+1), nY +(MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff888888);
nSelectMenu = i;
- if((UI.nMouseLeft || UI.nMouseRight) && i == (int)nPauseIndex)
+ if((UI.nMouseLeft || UI.nMouseRight) && i == (uint32_t)nPauseIndex)
{
S.nToggleRunning = 1;
}
}
- MicroProfileDrawText(nX, nY, (uint32_t)-1, pMenuText[i], (uint32_t)strlen(pMenuText[i]));
+ MicroProfileDrawText(nX, nY, UINT32_MAX, pMenuText[i], (uint32_t)strlen(pMenuText[i]));
nX += (nLen+1) * (MICROPROFILE_TEXT_WIDTH+1);
}
- uint32_t nMenu = nSelectMenu != (uint32_t)-1 ? nSelectMenu : UI.nActiveMenu;
+ uint32_t nMenu = nSelectMenu != UINT32_MAX ? nSelectMenu : UI.nActiveMenu;
UI.nActiveMenu = nMenu;
- if((uint32_t)-1 != nMenu)
+ if(UINT32_MAX != nMenu)
{
nX = nMenuX[nMenu];
nY += MICROPROFILE_TEXT_HEIGHT+1;
@@ -2450,9 +2451,9 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
{
UI.nActiveMenu = nMenu;
}
- else if(nSelectMenu == (uint32_t)-1)
+ else if(nSelectMenu == UINT32_MAX)
{
- UI.nActiveMenu = (uint32_t)-1;
+ UI.nActiveMenu = UINT32_MAX;
}
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000|g_nMicroProfileBackColors[1]);
for(int i = 0; i < nNumLines; ++i)
@@ -2461,7 +2462,6 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
const char* pString = CB(i, &bSelected);
if(UI.nMouseY >= nY && UI.nMouseY < nY + MICROPROFILE_TEXT_HEIGHT + 1)
{
- bMouseOver = true;
if(UI.nMouseLeft || UI.nMouseRight)
{
CBClick[nMenu](i);
@@ -2469,7 +2469,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + MICROPROFILE_TEXT_HEIGHT + 1, 0xff888888);
}
int nLen = snprintf(buffer, SBUF_SIZE-1, "%c %s", bSelected ? '*' : ' ' ,pString);
- MicroProfileDrawText(nX, nY, (uint32_t)-1, buffer, nLen);
+ MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nLen);
nY += MICROPROFILE_TEXT_HEIGHT+1;
}
}
@@ -2484,7 +2484,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
float fMaxMs = fToMs * S.nFlipMaxDisplay;
int nLen = snprintf(FrameTimeMessage, sizeof(FrameTimeMessage)-1, "Time[%6.2f] Avg[%6.2f] Max[%6.2f]", fMs, fAverageMs, fMaxMs);
pMenuText[nNumMenuItems++] = &FrameTimeMessage[0];
- MicroProfileDrawText(nWidth - nLen * (MICROPROFILE_TEXT_WIDTH+1), 0, -1, FrameTimeMessage, nLen);
+ MicroProfileDrawText(nWidth - nLen * (MICROPROFILE_TEXT_WIDTH+1), 0, UINT32_MAX, FrameTimeMessage, nLen);
}
}
@@ -2538,7 +2538,7 @@ inline void MicroProfileMoveGraph()
inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
{
- if((uint32_t)-1 != UI.nCustomActive)
+ if(UINT32_MAX != UI.nCustomActive)
{
MicroProfile& S = *MicroProfileGet();
MP_ASSERT(UI.nCustomActive < MICROPROFILE_CUSTOM_MAX);
@@ -2571,8 +2571,8 @@ inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
pColors[i] = S.TimerInfo[nTimerIndex].nColor;
}
- MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 3*MICROPROFILE_TEXT_WIDTH, nOffsetY, (uint32_t)-1, "Avg", sizeof("Avg")-1);
- MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 13*MICROPROFILE_TEXT_WIDTH, nOffsetY, (uint32_t)-1, "Max", sizeof("Max")-1);
+ MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 3*MICROPROFILE_TEXT_WIDTH, nOffsetY, UINT32_MAX, "Avg", sizeof("Avg")-1);
+ MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 13*MICROPROFILE_TEXT_WIDTH, nOffsetY, UINT32_MAX, "Max", sizeof("Max")-1);
for(uint32_t i = 0; i < nCount; ++i)
{
nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
@@ -2582,10 +2582,10 @@ inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
int nSize;
uint32_t nOffsetX = MICROPROFILE_CUSTOM_PADDING;
nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeAvg[i]);
- MicroProfileDrawText(nOffsetX, nOffsetY, (uint32_t)-1, Buffer, nSize);
+ MicroProfileDrawText(nOffsetX, nOffsetY, UINT32_MAX, Buffer, nSize);
nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeMax[i]);
- MicroProfileDrawText(nOffsetX, nOffsetY, (uint32_t)-1, Buffer, nSize);
+ MicroProfileDrawText(nOffsetX, nOffsetY, UINT32_MAX, Buffer, nSize);
nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
nSize = snprintf(Buffer, sizeof(Buffer)-1, "%s:%s", S.GroupInfo[nGroupIndex].pName, pTimerInfo->pName);
MicroProfileDrawText(nOffsetX, nOffsetY, pTimerInfo->nColor, Buffer, nSize);
@@ -2599,9 +2599,9 @@ inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
nOffsetY = nOffsetYBase;
float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? pTimeMax : pTimeAvg;
const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? "Max" : "Avg";
- MicroProfileDrawText(nMaxOffsetX, nOffsetY, (uint32_t)-1, pString, static_cast<uint32_t>(strlen(pString)));
+ MicroProfileDrawText(nMaxOffsetX, nOffsetY, UINT32_MAX, pString, static_cast<uint32_t>(strlen(pString)));
int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
- MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, (uint32_t)-1, Buffer, nSize);
+ MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, UINT32_MAX, Buffer, nSize);
for(uint32_t i = 0; i < nCount; ++i)
{
nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
@@ -2613,9 +2613,9 @@ inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
{
nOffsetY += 2*(1+MICROPROFILE_TEXT_HEIGHT);
const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? "Max" : "Avg";
- MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING, nOffsetY, (uint32_t)-1, pString, static_cast<uint32_t>(strlen(pString)));
+ MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING, nOffsetY, UINT32_MAX, pString, static_cast<uint32_t>(strlen(pString)));
int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
- MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, (uint32_t)-1, Buffer, nSize);
+ MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, UINT32_MAX, Buffer, nSize);
nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
float fPosX = MICROPROFILE_CUSTOM_PADDING;
float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? pTimeMax : pTimeAvg;
@@ -2668,7 +2668,7 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
UI.nHoverTime = 0;
UI.nHoverFrame = -1;
if(S.nDisplay != MP_DRAW_DETAILED)
- S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = -1;
+ S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = UINT32_MAX;
MicroProfileMoveGraph();
@@ -2798,13 +2798,13 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
- if(UI.nActiveMenu == -1 && !bMouseOverGraph)
+ if(UI.nActiveMenu == UINT32_MAX && !bMouseOverGraph)
{
if(UI.nHoverToken != MICROPROFILE_INVALID_TOKEN)
{
MicroProfileDrawFloatTooltip(UI.nMouseX, UI.nMouseY, UI.nHoverToken, UI.nHoverTime);
}
- else if(S.nContextSwitchHoverThreadAfter != -1 && S.nContextSwitchHoverThreadBefore != -1)
+ else if(S.nContextSwitchHoverThreadAfter != UINT32_MAX && S.nContextSwitchHoverThreadBefore != UINT32_MAX)
{
float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
MicroProfileStringArray ToolTip;
@@ -2820,7 +2820,7 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fToMs * nDifference );
MicroProfileStringArrayAddLiteral(&ToolTip, "CPU");
MicroProfileStringArrayFormat(&ToolTip, "%d", S.nContextSwitchHoverCpu);
- MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, -1);
+ MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, UINT32_MAX);
}
@@ -2858,7 +2858,7 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
}
}
#endif
- MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, -1);
+ MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, UINT32_MAX);
}
if(UI.nMouseLeft)
{
@@ -2883,7 +2883,7 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
#endif
m.unlock();
}
- else if(UI.nCustomActive != (uint32_t)-1)
+ else if(UI.nCustomActive != UINT32_MAX)
{
std::recursive_mutex& m = MicroProfileGetMutex();
m.lock();
@@ -3179,7 +3179,7 @@ void MicroProfileLoadPreset(const char* pSuffix)
{
if(0 == MP_STRCASECMP(pGroupName, S.GroupInfo[j].pName))
{
- S.nActiveGroupWanted |= (1ll << j);
+ S.nActiveGroupWanted |= (1ULL << j);
}
}
}
@@ -3212,7 +3212,7 @@ void MicroProfileLoadPreset(const char* pSuffix)
uint64_t nGroupIndex = S.TimerInfo[j].nGroupIndex;
if(0 == MP_STRCASECMP(pGraphName, S.TimerInfo[j].pName) && 0 == MP_STRCASECMP(pGraphGroupName, S.GroupInfo[nGroupIndex].pName))
{
- MicroProfileToken nToken = MicroProfileMakeToken(1ll << nGroupIndex, (uint16_t)j);
+ MicroProfileToken nToken = MicroProfileMakeToken(1ULL << nGroupIndex, (uint16_t)j);
S.Graph[i].nToken = nToken; // note: group index is stored here but is checked without in MicroProfileToggleGraph()!
S.TimerInfo[j].bGraph = true;
if(nToken != nPrevToken)
@@ -3235,7 +3235,7 @@ inline uint32_t MicroProfileCustomGroupFind(const char* pCustomName)
return i;
}
}
- return (uint32_t)-1;
+ return UINT32_MAX;
}
inline uint32_t MicroProfileCustomGroup(const char* pCustomName)
@@ -3251,7 +3251,7 @@ inline uint32_t MicroProfileCustomGroup(const char* pCustomName)
uint32_t nIndex = UI.nCustomCount;
UI.nCustomCount++;
memset(&UI.Custom[nIndex], 0, sizeof(UI.Custom[nIndex]));
- uint32_t nLen = (uint32_t)strlen(pCustomName);
+ size_t nLen = strlen(pCustomName);
if(nLen > MICROPROFILE_NAME_MAX_LEN-1)
nLen = MICROPROFILE_NAME_MAX_LEN-1;
memcpy(&UI.Custom[nIndex].pName[0], pCustomName, nLen);
@@ -3309,7 +3309,7 @@ inline void MicroProfileCustomGroupEnable(uint32_t nIndex)
void MicroProfileCustomGroupToggle(const char* pCustomName)
{
uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
- if(nIndex == (uint32_t)-1 || nIndex == UI.nCustomActive)
+ if(nIndex == UINT32_MAX || nIndex == UI.nCustomActive)
{
MicroProfileCustomGroupDisable();
}
@@ -3328,13 +3328,13 @@ void MicroProfileCustomGroupDisable()
{
MicroProfile& S = *MicroProfileGet();
S.nForceGroupUI = 0;
- UI.nCustomActive = (uint32_t)-1;
+ UI.nCustomActive = UINT32_MAX;
}
void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer)
{
uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
- if((uint32_t)-1 == nIndex)
+ if(UINT32_MAX == nIndex)
{
return;
}
@@ -3344,7 +3344,7 @@ void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup
MP_ASSERT(nToken != MICROPROFILE_INVALID_TOKEN); //Timer must be registered first.
UI.Custom[nIndex].pTimers[nTimerIndex] = nToken;
uint16_t nGroup = MicroProfileGetGroupIndex(nToken);
- UI.Custom[nIndex].nGroupMask |= (1ll << nGroup);
+ UI.Custom[nIndex].nGroupMask |= (1ULL << nGroup);
UI.Custom[nIndex].nNumTimers++;
}
diff --git a/externals/xbyak b/externals/xbyak
-Subproject 82b70e665918efc2ee348091742fd0237b3b68c
+Subproject c306b8e5786eeeb87b8925a8af5c3bf057ff5a9
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index 5ef38a337..54940a034 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -12,22 +12,51 @@ add_library(audio_core STATIC
buffer.h
codec.cpp
codec.h
+ command_generator.cpp
+ command_generator.h
common.h
+ effect_context.cpp
+ effect_context.h
+ info_updater.cpp
+ info_updater.h
+ memory_pool.cpp
+ memory_pool.h
+ mix_context.cpp
+ mix_context.h
null_sink.h
sink.h
+ sink_context.cpp
+ sink_context.h
sink_details.cpp
sink_details.h
sink_stream.h
+ splitter_context.cpp
+ splitter_context.h
stream.cpp
stream.h
time_stretch.cpp
time_stretch.h
+ voice_context.cpp
+ voice_context.h
$<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h>
)
create_target_directory_groups(audio_core)
+if (NOT MSVC)
+ target_compile_options(audio_core PRIVATE
+ -Werror=conversion
+ -Werror=ignored-qualifiers
+ -Werror=implicit-fallthrough
+ -Werror=reorder
+ -Werror=sign-compare
+ -Werror=unused-but-set-parameter
+ -Werror=unused-but-set-variable
+ -Werror=unused-variable
+ )
+endif()
+
target_link_libraries(audio_core PUBLIC common core)
target_link_libraries(audio_core PRIVATE SoundTouch)
diff --git a/src/audio_core/algorithm/filter.cpp b/src/audio_core/algorithm/filter.cpp
index f65bf64f7..f34a5b9f3 100644
--- a/src/audio_core/algorithm/filter.cpp
+++ b/src/audio_core/algorithm/filter.cpp
@@ -55,7 +55,8 @@ void Filter::Process(std::vector<s16>& signal) {
/// @param total_count The total number of biquads to be cascaded.
/// @param index 0-index of the biquad to calculate the Q value for.
static double CascadingBiquadQ(std::size_t total_count, std::size_t index) {
- const double pole = M_PI * (2 * index + 1) / (4.0 * total_count);
+ const auto pole =
+ M_PI * static_cast<double>(2 * index + 1) / (4.0 * static_cast<double>(total_count));
return 1.0 / (2.0 * std::cos(pole));
}
diff --git a/src/audio_core/algorithm/interpolate.cpp b/src/audio_core/algorithm/interpolate.cpp
index 49ab9d3e1..699fcb84c 100644
--- a/src/audio_core/algorithm/interpolate.cpp
+++ b/src/audio_core/algorithm/interpolate.cpp
@@ -146,7 +146,7 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
return {};
if (ratio <= 0) {
- LOG_CRITICAL(Audio, "Nonsensical interpolation ratio {}", ratio);
+ LOG_ERROR(Audio, "Nonsensical interpolation ratio {}", ratio);
return input;
}
@@ -164,7 +164,8 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
const std::size_t num_frames{input.size() / 2};
std::vector<s16> output;
- output.reserve(static_cast<std::size_t>(input.size() / ratio + InterpolationState::taps));
+ output.reserve(static_cast<std::size_t>(static_cast<double>(input.size()) / ratio +
+ InterpolationState::taps));
for (std::size_t frame{}; frame < num_frames; ++frame) {
const std::size_t lut_index{(state.fraction >> 8) * InterpolationState::taps};
@@ -197,4 +198,36 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
return output;
}
+void Resample(s32* output, const s32* input, s32 pitch, s32& fraction, std::size_t sample_count) {
+ const std::array<s16, 512>& lut = [pitch] {
+ if (pitch > 0xaaaa) {
+ return curve_lut0;
+ }
+ if (pitch <= 0x8000) {
+ return curve_lut1;
+ }
+ return curve_lut2;
+ }();
+
+ std::size_t index{};
+
+ for (std::size_t i = 0; i < sample_count; i++) {
+ const std::size_t lut_index{(static_cast<std::size_t>(fraction) >> 8) * 4};
+ const auto l0 = lut[lut_index + 0];
+ const auto l1 = lut[lut_index + 1];
+ const auto l2 = lut[lut_index + 2];
+ const auto l3 = lut[lut_index + 3];
+
+ const auto s0 = static_cast<s32>(input[index]);
+ const auto s1 = static_cast<s32>(input[index + 1]);
+ const auto s2 = static_cast<s32>(input[index + 2]);
+ const auto s3 = static_cast<s32>(input[index + 3]);
+
+ output[i] = (l0 * s0 + l1 * s1 + l2 * s2 + l3 * s3) >> 15;
+ fraction += pitch;
+ index += (fraction >> 15);
+ fraction &= 0x7fff;
+ }
+}
+
} // namespace AudioCore
diff --git a/src/audio_core/algorithm/interpolate.h b/src/audio_core/algorithm/interpolate.h
index ab1a31754..d534077af 100644
--- a/src/audio_core/algorithm/interpolate.h
+++ b/src/audio_core/algorithm/interpolate.h
@@ -38,4 +38,7 @@ inline std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16>
return Interpolate(state, std::move(input), ratio);
}
+/// Nintendo Switchs DSP resampling algorithm. Based on a single channel
+void Resample(s32* output, const s32* input, s32 pitch, s32& fraction, std::size_t sample_count);
+
} // namespace AudioCore
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index d64452617..a7e851bb8 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -2,95 +2,46 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "audio_core/algorithm/interpolate.h"
+#include <vector>
+
#include "audio_core/audio_out.h"
#include "audio_core/audio_renderer.h"
-#include "audio_core/codec.h"
#include "audio_core/common.h"
-#include "common/assert.h"
+#include "audio_core/info_updater.h"
+#include "audio_core/voice_context.h"
#include "common/logging/log.h"
-#include "core/core.h"
#include "core/hle/kernel/writable_event.h"
#include "core/memory.h"
+#include "core/settings.h"
namespace AudioCore {
-
-constexpr u32 STREAM_SAMPLE_RATE{48000};
-constexpr u32 STREAM_NUM_CHANNELS{2};
-using VoiceChannelHolder = std::array<VoiceResourceInformation*, 6>;
-class AudioRenderer::VoiceState {
-public:
- bool IsPlaying() const {
- return is_in_use && info.play_state == PlayState::Started;
- }
-
- const VoiceOutStatus& GetOutStatus() const {
- return out_status;
- }
-
- const VoiceInfo& GetInfo() const {
- return info;
- }
-
- VoiceInfo& GetInfo() {
- return info;
- }
-
- void SetWaveIndex(std::size_t index);
- std::vector<s16> DequeueSamples(std::size_t sample_count, Core::Memory::Memory& memory,
- const VoiceChannelHolder& voice_resources);
- void UpdateState();
- void RefreshBuffer(Core::Memory::Memory& memory, const VoiceChannelHolder& voice_resources);
-
-private:
- bool is_in_use{};
- bool is_refresh_pending{};
- std::size_t wave_index{};
- std::size_t offset{};
- Codec::ADPCMState adpcm_state{};
- InterpolationState interp_state{};
- std::vector<s16> samples;
- VoiceOutStatus out_status{};
- VoiceInfo info{};
-};
-
-class AudioRenderer::EffectState {
-public:
- const EffectOutStatus& GetOutStatus() const {
- return out_status;
- }
-
- const EffectInStatus& GetInfo() const {
- return info;
- }
-
- EffectInStatus& GetInfo() {
- return info;
- }
-
- void UpdateState(Core::Memory::Memory& memory);
-
-private:
- EffectOutStatus out_status{};
- EffectInStatus info{};
-};
-
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
- AudioRendererParameter params,
+ AudioCommon::AudioRendererParameter params,
std::shared_ptr<Kernel::WritableEvent> buffer_event,
std::size_t instance_number)
- : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
- voice_resources(params.voice_count), effects(params.effect_count), memory{memory_} {
+ : worker_params{params}, buffer_event{buffer_event},
+ memory_pool_info(params.effect_count + params.voice_count * 4),
+ voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
+ sink_context(params.sink_count), splitter_context(),
+ voices(params.voice_count), memory{memory_},
+ command_generator(worker_params, voice_context, mix_context, splitter_context, effect_context,
+ memory),
+ temp_mix_buffer(AudioCommon::TOTAL_TEMP_MIX_SIZE) {
behavior_info.SetUserRevision(params.revision);
+ splitter_context.Initialize(behavior_info, params.splitter_count,
+ params.num_splitter_send_channels);
+ mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count);
audio_out = std::make_unique<AudioCore::AudioOut>();
- stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS,
- fmt::format("AudioRenderer-Instance{}", instance_number),
- [=]() { buffer_event->Signal(); });
+ stream =
+ audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
+ fmt::format("AudioRenderer-Instance{}", instance_number),
+ [=]() { buffer_event->Signal(); });
audio_out->StartStream(stream);
QueueMixedBuffer(0);
QueueMixedBuffer(1);
QueueMixedBuffer(2);
+ QueueMixedBuffer(3);
}
AudioRenderer::~AudioRenderer() = default;
@@ -111,355 +62,200 @@ Stream::State AudioRenderer::GetStreamState() const {
return stream->GetState();
}
-ResultVal<std::vector<u8>> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
- // Copy UpdateDataHeader struct
- UpdateDataHeader config{};
- std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader));
- u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
-
- if (!behavior_info.UpdateInput(input_params, sizeof(UpdateDataHeader))) {
- LOG_ERROR(Audio, "Failed to update behavior info input parameters");
- return Audren::ERR_INVALID_PARAMETERS;
- }
-
- // Copy MemoryPoolInfo structs
- std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
- std::memcpy(mem_pool_info.data(),
- input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size,
- memory_pool_count * sizeof(MemoryPoolInfo));
-
- // Copy voice resources
- const std::size_t voice_resource_offset{sizeof(UpdateDataHeader) + config.behavior_size +
- config.memory_pools_size};
- std::memcpy(voice_resources.data(), input_params.data() + voice_resource_offset,
- sizeof(VoiceResourceInformation) * voice_resources.size());
-
- // Copy VoiceInfo structs
- std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size +
- config.memory_pools_size + config.voice_resource_size};
- for (auto& voice : voices) {
- std::memcpy(&voice.GetInfo(), input_params.data() + voice_offset, sizeof(VoiceInfo));
- voice_offset += sizeof(VoiceInfo);
- }
-
- std::size_t effect_offset{sizeof(UpdateDataHeader) + config.behavior_size +
- config.memory_pools_size + config.voice_resource_size +
- config.voices_size};
- for (auto& effect : effects) {
- std::memcpy(&effect.GetInfo(), input_params.data() + effect_offset, sizeof(EffectInStatus));
- effect_offset += sizeof(EffectInStatus);
- }
-
- // Update memory pool state
- std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
- for (std::size_t index = 0; index < memory_pool.size(); ++index) {
- if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
- memory_pool[index].state = MemoryPoolStates::Attached;
- } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
- memory_pool[index].state = MemoryPoolStates::Detached;
- }
- }
-
- // Update voices
- for (auto& voice : voices) {
- voice.UpdateState();
- if (!voice.GetInfo().is_in_use) {
- continue;
- }
- if (voice.GetInfo().is_new) {
- voice.SetWaveIndex(voice.GetInfo().wave_buffer_head);
- }
- }
-
- for (auto& effect : effects) {
- effect.UpdateState(memory);
- }
-
- // Release previous buffers and queue next ones for playback
- ReleaseAndQueueBuffers();
-
- // Copy output header
- UpdateDataHeader response_data{worker_params};
- if (behavior_info.IsElapsedFrameCountSupported()) {
- response_data.render_info = sizeof(RendererInfo);
- response_data.total_size += sizeof(RendererInfo);
- }
-
- std::vector<u8> output_params(response_data.total_size);
- std::memcpy(output_params.data(), &response_data, sizeof(UpdateDataHeader));
-
- // Copy output memory pool entries
- std::memcpy(output_params.data() + sizeof(UpdateDataHeader), memory_pool.data(),
- response_data.memory_pools_size);
-
- // Copy output voice status
- std::size_t voice_out_status_offset{sizeof(UpdateDataHeader) + response_data.memory_pools_size};
- for (const auto& voice : voices) {
- std::memcpy(output_params.data() + voice_out_status_offset, &voice.GetOutStatus(),
- sizeof(VoiceOutStatus));
- voice_out_status_offset += sizeof(VoiceOutStatus);
- }
+static constexpr s16 ClampToS16(s32 value) {
+ return static_cast<s16>(std::clamp(value, -32768, 32767));
+}
- std::size_t effect_out_status_offset{
- sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size +
- response_data.voice_resource_size};
- for (const auto& effect : effects) {
- std::memcpy(output_params.data() + effect_out_status_offset, &effect.GetOutStatus(),
- sizeof(EffectOutStatus));
- effect_out_status_offset += sizeof(EffectOutStatus);
- }
+ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
+ std::vector<u8>& output_params) {
- // Update behavior info output
- const std::size_t behavior_out_status_offset{
- sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size +
- response_data.effects_size + response_data.sinks_size +
- response_data.performance_manager_size};
+ InfoUpdater info_updater{input_params, output_params, behavior_info};
- if (!behavior_info.UpdateOutput(output_params, behavior_out_status_offset)) {
- LOG_ERROR(Audio, "Failed to update behavior info output parameters");
- return Audren::ERR_INVALID_PARAMETERS;
+ if (!info_updater.UpdateBehaviorInfo(behavior_info)) {
+ LOG_ERROR(Audio, "Failed to update behavior info input parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- if (behavior_info.IsElapsedFrameCountSupported()) {
- const std::size_t renderer_info_offset{
- sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size +
- response_data.effects_size + response_data.sinks_size +
- response_data.performance_manager_size + response_data.behavior_size};
- RendererInfo renderer_info{};
- renderer_info.elasped_frame_count = elapsed_frame_count;
- std::memcpy(output_params.data() + renderer_info_offset, &renderer_info,
- sizeof(RendererInfo));
+ if (!info_updater.UpdateMemoryPools(memory_pool_info)) {
+ LOG_ERROR(Audio, "Failed to update memory pool parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- return MakeResult(output_params);
-}
-
-void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) {
- wave_index = index & 3;
- is_refresh_pending = true;
-}
-
-std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(
- std::size_t sample_count, Core::Memory::Memory& memory,
- const VoiceChannelHolder& voice_resources) {
- if (!IsPlaying()) {
- return {};
+ if (!info_updater.UpdateVoiceChannelResources(voice_context)) {
+ LOG_ERROR(Audio, "Failed to update voice channel resource parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- if (is_refresh_pending) {
- RefreshBuffer(memory, voice_resources);
+ if (!info_updater.UpdateVoices(voice_context, memory_pool_info, 0)) {
+ LOG_ERROR(Audio, "Failed to update voice parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- const std::size_t max_size{samples.size() - offset};
- const std::size_t dequeue_offset{offset};
- std::size_t size{sample_count * STREAM_NUM_CHANNELS};
- if (size > max_size) {
- size = max_size;
+ // TODO(ogniK): Deal with stopped audio renderer but updates still taking place
+ if (!info_updater.UpdateEffects(effect_context, true)) {
+ LOG_ERROR(Audio, "Failed to update effect parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- out_status.played_sample_count += size / STREAM_NUM_CHANNELS;
- offset += size;
-
- const auto& wave_buffer{info.wave_buffer[wave_index]};
- if (offset == samples.size()) {
- offset = 0;
-
- if (!wave_buffer.is_looping && wave_buffer.buffer_sz) {
- SetWaveIndex(wave_index + 1);
- }
-
- if (wave_buffer.buffer_sz) {
- out_status.wave_buffer_consumed++;
- }
-
- if (wave_buffer.end_of_stream || wave_buffer.buffer_sz == 0) {
- info.play_state = PlayState::Paused;
+ if (behavior_info.IsSplitterSupported()) {
+ if (!info_updater.UpdateSplitterInfo(splitter_context)) {
+ LOG_ERROR(Audio, "Failed to update splitter parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
}
- return {samples.begin() + dequeue_offset, samples.begin() + dequeue_offset + size};
-}
+ auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
+ splitter_context, effect_context);
-void AudioRenderer::VoiceState::UpdateState() {
- if (is_in_use && !info.is_in_use) {
- // No longer in use, reset state
- is_refresh_pending = true;
- wave_index = 0;
- offset = 0;
- out_status = {};
+ if (mix_result.IsError()) {
+ LOG_ERROR(Audio, "Failed to update mix parameters");
+ return mix_result;
}
- is_in_use = info.is_in_use;
-}
-void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory,
- const VoiceChannelHolder& voice_resources) {
- const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr;
- const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz;
- std::vector<s16> new_samples(wave_buffer_size / sizeof(s16));
- memory.ReadBlock(wave_buffer_address, new_samples.data(), wave_buffer_size);
-
- switch (static_cast<Codec::PcmFormat>(info.sample_format)) {
- case Codec::PcmFormat::Int16: {
- // PCM16 is played as-is
- break;
+ // TODO(ogniK): Sinks
+ if (!info_updater.UpdateSinks(sink_context)) {
+ LOG_ERROR(Audio, "Failed to update sink parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- case Codec::PcmFormat::Adpcm: {
- // Decode ADPCM to PCM16
- Codec::ADPCM_Coeff coeffs;
- memory.ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff));
- new_samples = Codec::DecodeADPCM(reinterpret_cast<u8*>(new_samples.data()),
- new_samples.size() * sizeof(s16), coeffs, adpcm_state);
- break;
- }
- default:
- UNIMPLEMENTED_MSG("Unimplemented sample_format={}", info.sample_format);
- break;
- }
-
- switch (info.channel_count) {
- case 1: {
- // 1 channel is upsampled to 2 channel
- samples.resize(new_samples.size() * 2);
- for (std::size_t index = 0; index < new_samples.size(); ++index) {
- auto sample = static_cast<float>(new_samples[index]);
- if (voice_resources[0]->in_use) {
- sample *= voice_resources[0]->mix_volumes[0];
- }
-
- samples[index * 2] = static_cast<s16>(sample * info.volume);
- samples[index * 2 + 1] = static_cast<s16>(sample * info.volume);
- }
- break;
+ // TODO(ogniK): Performance buffer
+ if (!info_updater.UpdatePerformanceBuffer()) {
+ LOG_ERROR(Audio, "Failed to update performance buffer parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- case 2: {
- // 2 channel is played as is
- samples = std::move(new_samples);
- const std::size_t sample_count = (samples.size() / 2);
- for (std::size_t index = 0; index < sample_count; ++index) {
- const std::size_t index_l = index * 2;
- const std::size_t index_r = index * 2 + 1;
-
- auto sample_l = static_cast<float>(samples[index_l]);
- auto sample_r = static_cast<float>(samples[index_r]);
-
- if (voice_resources[0]->in_use) {
- sample_l *= voice_resources[0]->mix_volumes[0];
- }
-
- if (voice_resources[1]->in_use) {
- sample_r *= voice_resources[1]->mix_volumes[1];
- }
- samples[index_l] = static_cast<s16>(sample_l * info.volume);
- samples[index_r] = static_cast<s16>(sample_r * info.volume);
- }
- break;
+ if (!info_updater.UpdateErrorInfo(behavior_info)) {
+ LOG_ERROR(Audio, "Failed to update error info");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- case 6: {
- samples.resize((new_samples.size() / 6) * 2);
- const std::size_t sample_count = samples.size() / 2;
-
- for (std::size_t index = 0; index < sample_count; ++index) {
- auto FL = static_cast<float>(new_samples[index * 6]);
- auto FR = static_cast<float>(new_samples[index * 6 + 1]);
- auto FC = static_cast<float>(new_samples[index * 6 + 2]);
- auto BL = static_cast<float>(new_samples[index * 6 + 4]);
- auto BR = static_cast<float>(new_samples[index * 6 + 5]);
-
- if (voice_resources[0]->in_use) {
- FL *= voice_resources[0]->mix_volumes[0];
- }
- if (voice_resources[1]->in_use) {
- FR *= voice_resources[1]->mix_volumes[1];
- }
- if (voice_resources[2]->in_use) {
- FC *= voice_resources[2]->mix_volumes[2];
- }
- if (voice_resources[4]->in_use) {
- BL *= voice_resources[4]->mix_volumes[4];
- }
- if (voice_resources[5]->in_use) {
- BR *= voice_resources[5]->mix_volumes[5];
- }
- samples[index * 2] =
- static_cast<s16>((0.3694f * FL + 0.2612f * FC + 0.3694f * BL) * info.volume);
- samples[index * 2 + 1] =
- static_cast<s16>((0.3694f * FR + 0.2612f * FC + 0.3694f * BR) * info.volume);
+ if (behavior_info.IsElapsedFrameCountSupported()) {
+ if (!info_updater.UpdateRendererInfo(elapsed_frame_count)) {
+ LOG_ERROR(Audio, "Failed to update renderer info");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- break;
- }
- default:
- UNIMPLEMENTED_MSG("Unimplemented channel_count={}", info.channel_count);
- break;
}
+ // TODO(ogniK): Statistics
- // Only interpolate when necessary, expensive.
- if (GetInfo().sample_rate != STREAM_SAMPLE_RATE) {
- samples = Interpolate(interp_state, std::move(samples), GetInfo().sample_rate,
- STREAM_SAMPLE_RATE);
+ if (!info_updater.WriteOutputHeader()) {
+ LOG_ERROR(Audio, "Failed to write output header");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- is_refresh_pending = false;
-}
+ // TODO(ogniK): Check when all sections are implemented
-void AudioRenderer::EffectState::UpdateState(Core::Memory::Memory& memory) {
- if (info.is_new) {
- out_status.state = EffectStatus::New;
- } else {
- if (info.type == Effect::Aux) {
- ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_info) == 0,
- "Aux buffers tried to update");
- ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_info) == 0,
- "Aux buffers tried to update");
- ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_base) == 0,
- "Aux buffers tried to update");
- ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_base) == 0,
- "Aux buffers tried to update");
- }
+ if (!info_updater.CheckConsumedSize()) {
+ LOG_ERROR(Audio, "Audio buffers were not consumed!");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
-}
-static constexpr s16 ClampToS16(s32 value) {
- return static_cast<s16>(std::clamp(value, -32768, 32767));
+ ReleaseAndQueueBuffers();
+
+ return RESULT_SUCCESS;
}
void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
- constexpr std::size_t BUFFER_SIZE{512};
+ command_generator.PreCommand();
+ // Clear mix buffers before our next operation
+ command_generator.ClearMixBuffers();
+
+ // If the splitter is not in use, sort our mixes
+ if (!splitter_context.UsingSplitter()) {
+ mix_context.SortInfo();
+ }
+ // Sort our voices
+ voice_context.SortInfo();
+
+ // Handle samples
+ command_generator.GenerateVoiceCommands();
+ command_generator.GenerateSubMixCommands();
+ command_generator.GenerateFinalMixCommands();
+
+ command_generator.PostCommand();
+ // Base sample size
+ std::size_t BUFFER_SIZE{worker_params.sample_count};
+ // Samples
std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels());
-
- for (auto& voice : voices) {
- if (!voice.IsPlaying()) {
- continue;
- }
- VoiceChannelHolder resources{};
- for (u32 channel = 0; channel < voice.GetInfo().channel_count; channel++) {
- const auto channel_resource_id = voice.GetInfo().voice_channel_resource_ids[channel];
- resources[channel] = &voice_resources[channel_resource_id];
+ // Make sure to clear our samples
+ std::memset(buffer.data(), 0, buffer.size() * sizeof(s16));
+
+ if (sink_context.InUse()) {
+ const auto stream_channel_count = stream->GetNumChannels();
+ const auto buffer_offsets = sink_context.OutputBuffers();
+ const auto channel_count = buffer_offsets.size();
+ const auto& final_mix = mix_context.GetFinalMixInfo();
+ const auto& in_params = final_mix.GetInParams();
+ std::vector<s32*> mix_buffers(channel_count);
+ for (std::size_t i = 0; i < channel_count; i++) {
+ mix_buffers[i] =
+ command_generator.GetMixBuffer(in_params.buffer_offset + buffer_offsets[i]);
}
- std::size_t offset{};
- s64 samples_remaining{BUFFER_SIZE};
- while (samples_remaining > 0) {
- const std::vector<s16> samples{
- voice.DequeueSamples(samples_remaining, memory, resources)};
-
- if (samples.empty()) {
- break;
- }
-
- samples_remaining -= samples.size() / stream->GetNumChannels();
-
- for (const auto& sample : samples) {
- const s32 buffer_sample{buffer[offset]};
- buffer[offset++] =
- ClampToS16(buffer_sample + static_cast<s32>(sample * voice.GetInfo().volume));
+ for (std::size_t i = 0; i < BUFFER_SIZE; i++) {
+ if (channel_count == 1) {
+ const auto sample = ClampToS16(mix_buffers[0][i]);
+ buffer[i * stream_channel_count + 0] = sample;
+ if (stream_channel_count > 1) {
+ buffer[i * stream_channel_count + 1] = sample;
+ }
+ if (stream_channel_count == 6) {
+ buffer[i * stream_channel_count + 2] = sample;
+ buffer[i * stream_channel_count + 4] = sample;
+ buffer[i * stream_channel_count + 5] = sample;
+ }
+ } else if (channel_count == 2) {
+ const auto l_sample = ClampToS16(mix_buffers[0][i]);
+ const auto r_sample = ClampToS16(mix_buffers[1][i]);
+ if (stream_channel_count == 1) {
+ buffer[i * stream_channel_count + 0] = l_sample;
+ } else if (stream_channel_count == 2) {
+ buffer[i * stream_channel_count + 0] = l_sample;
+ buffer[i * stream_channel_count + 1] = r_sample;
+ } else if (stream_channel_count == 6) {
+ buffer[i * stream_channel_count + 0] = l_sample;
+ buffer[i * stream_channel_count + 1] = r_sample;
+
+ buffer[i * stream_channel_count + 2] =
+ ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2);
+
+ buffer[i * stream_channel_count + 4] = l_sample;
+ buffer[i * stream_channel_count + 5] = r_sample;
+ }
+
+ } else if (channel_count == 6) {
+ const auto fl_sample = ClampToS16(mix_buffers[0][i]);
+ const auto fr_sample = ClampToS16(mix_buffers[1][i]);
+ const auto fc_sample = ClampToS16(mix_buffers[2][i]);
+ const auto lf_sample = ClampToS16(mix_buffers[3][i]);
+ const auto bl_sample = ClampToS16(mix_buffers[4][i]);
+ const auto br_sample = ClampToS16(mix_buffers[5][i]);
+
+ if (stream_channel_count == 1) {
+ buffer[i * stream_channel_count + 0] = fc_sample;
+ } else if (stream_channel_count == 2) {
+ buffer[i * stream_channel_count + 0] =
+ static_cast<s16>(0.3694f * static_cast<float>(fl_sample) +
+ 0.2612f * static_cast<float>(fc_sample) +
+ 0.3694f * static_cast<float>(bl_sample));
+ buffer[i * stream_channel_count + 1] =
+ static_cast<s16>(0.3694f * static_cast<float>(fr_sample) +
+ 0.2612f * static_cast<float>(fc_sample) +
+ 0.3694f * static_cast<float>(br_sample));
+ } else if (stream_channel_count == 6) {
+ buffer[i * stream_channel_count + 0] = fl_sample;
+ buffer[i * stream_channel_count + 1] = fr_sample;
+ buffer[i * stream_channel_count + 2] = fc_sample;
+ buffer[i * stream_channel_count + 3] = lf_sample;
+ buffer[i * stream_channel_count + 4] = bl_sample;
+ buffer[i * stream_channel_count + 5] = br_sample;
+ }
}
}
}
+
audio_out->QueueBuffer(stream, tag, std::move(buffer));
elapsed_frame_count++;
+ voice_context.UpdateStateByDspShared();
}
void AudioRenderer::ReleaseAndQueueBuffers() {
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index f0b691a86..2fd93e058 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -9,12 +9,18 @@
#include <vector>
#include "audio_core/behavior_info.h"
+#include "audio_core/command_generator.h"
#include "audio_core/common.h"
+#include "audio_core/effect_context.h"
+#include "audio_core/memory_pool.h"
+#include "audio_core/mix_context.h"
+#include "audio_core/sink_context.h"
+#include "audio_core/splitter_context.h"
#include "audio_core/stream.h"
+#include "audio_core/voice_context.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
-#include "core/hle/kernel/object.h"
#include "core/hle/result.h"
namespace Core::Timing {
@@ -30,220 +36,25 @@ class Memory;
}
namespace AudioCore {
+using DSPStateHolder = std::array<VoiceState*, 6>;
class AudioOut;
-enum class PlayState : u8 {
- Started = 0,
- Stopped = 1,
- Paused = 2,
-};
-
-enum class Effect : u8 {
- None = 0,
- Aux = 2,
-};
-
-enum class EffectStatus : u8 {
- None = 0,
- New = 1,
-};
-
-struct AudioRendererParameter {
- u32_le sample_rate;
- u32_le sample_count;
- u32_le mix_buffer_count;
- u32_le submix_count;
- u32_le voice_count;
- u32_le sink_count;
- u32_le effect_count;
- u32_le performance_frame_count;
- u8 is_voice_drop_enabled;
- u8 unknown_21;
- u8 unknown_22;
- u8 execution_mode;
- u32_le splitter_count;
- u32_le num_splitter_send_channels;
- u32_le unknown_30;
- u32_le revision;
-};
-static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size");
-
-enum class MemoryPoolStates : u32 { // Should be LE
- Invalid = 0x0,
- Unknown = 0x1,
- RequestDetach = 0x2,
- Detached = 0x3,
- RequestAttach = 0x4,
- Attached = 0x5,
- Released = 0x6,
-};
-
-struct MemoryPoolEntry {
- MemoryPoolStates state;
- u32_le unknown_4;
- u32_le unknown_8;
- u32_le unknown_c;
-};
-static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
-
-struct MemoryPoolInfo {
- u64_le pool_address;
- u64_le pool_size;
- MemoryPoolStates pool_state;
- INSERT_PADDING_WORDS(3); // Unknown
-};
-static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
-struct BiquadFilter {
- u8 enable;
- INSERT_PADDING_BYTES(1);
- std::array<s16_le, 3> numerator;
- std::array<s16_le, 2> denominator;
-};
-static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");
-
-struct WaveBuffer {
- u64_le buffer_addr;
- u64_le buffer_sz;
- s32_le start_sample_offset;
- s32_le end_sample_offset;
- u8 is_looping;
- u8 end_of_stream;
- u8 sent_to_server;
- INSERT_PADDING_BYTES(5);
- u64 context_addr;
- u64 context_sz;
- INSERT_PADDING_BYTES(8);
-};
-static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
-
-struct VoiceResourceInformation {
- s32_le id{};
- std::array<float_le, MAX_MIX_BUFFERS> mix_volumes{};
- bool in_use{};
- INSERT_PADDING_BYTES(11);
-};
-static_assert(sizeof(VoiceResourceInformation) == 0x70, "VoiceResourceInformation has wrong size");
-
-struct VoiceInfo {
- u32_le id;
- u32_le node_id;
- u8 is_new;
- u8 is_in_use;
- PlayState play_state;
- u8 sample_format;
- u32_le sample_rate;
- u32_le priority;
- u32_le sorting_order;
- u32_le channel_count;
- float_le pitch;
- float_le volume;
- std::array<BiquadFilter, 2> biquad_filter;
- u32_le wave_buffer_count;
- u32_le wave_buffer_head;
- INSERT_PADDING_WORDS(1);
- u64_le additional_params_addr;
- u64_le additional_params_sz;
- u32_le mix_id;
- u32_le splitter_info_id;
- std::array<WaveBuffer, 4> wave_buffer;
- std::array<u32_le, 6> voice_channel_resource_ids;
- INSERT_PADDING_BYTES(24);
-};
-static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");
-
-struct VoiceOutStatus {
- u64_le played_sample_count;
- u32_le wave_buffer_consumed;
- u32_le voice_drops_count;
-};
-static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
-
-struct AuxInfo {
- std::array<u8, 24> input_mix_buffers;
- std::array<u8, 24> output_mix_buffers;
- u32_le mix_buffer_count;
- u32_le sample_rate; // Stored in the aux buffer currently
- u32_le sample_count;
- u64_le send_buffer_info;
- u64_le send_buffer_base;
-
- u64_le return_buffer_info;
- u64_le return_buffer_base;
-};
-static_assert(sizeof(AuxInfo) == 0x60, "AuxInfo is an invalid size");
-
-struct EffectInStatus {
- Effect type;
- u8 is_new;
- u8 is_enabled;
- INSERT_PADDING_BYTES(1);
- u32_le mix_id;
- u64_le buffer_base;
- u64_le buffer_sz;
- s32_le priority;
- INSERT_PADDING_BYTES(4);
- union {
- std::array<u8, 0xa0> raw;
- AuxInfo aux_info;
- };
-};
-static_assert(sizeof(EffectInStatus) == 0xc0, "EffectInStatus is an invalid size");
-
-struct EffectOutStatus {
- EffectStatus state;
- INSERT_PADDING_BYTES(0xf);
-};
-static_assert(sizeof(EffectOutStatus) == 0x10, "EffectOutStatus is an invalid size");
-
struct RendererInfo {
u64_le elasped_frame_count{};
INSERT_PADDING_WORDS(2);
};
static_assert(sizeof(RendererInfo) == 0x10, "RendererInfo is an invalid size");
-struct UpdateDataHeader {
- UpdateDataHeader() {}
-
- explicit UpdateDataHeader(const AudioRendererParameter& config) {
- revision = Common::MakeMagic('R', 'E', 'V', '8'); // 9.2.0 Revision
- behavior_size = 0xb0;
- memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
- voices_size = config.voice_count * 0x10;
- voice_resource_size = 0x0;
- effects_size = config.effect_count * 0x10;
- mixes_size = 0x0;
- sinks_size = config.sink_count * 0x20;
- performance_manager_size = 0x10;
- render_info = 0;
- total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size + voices_size +
- effects_size + sinks_size + performance_manager_size;
- }
-
- u32_le revision{};
- u32_le behavior_size{};
- u32_le memory_pools_size{};
- u32_le voices_size{};
- u32_le voice_resource_size{};
- u32_le effects_size{};
- u32_le mixes_size{};
- u32_le sinks_size{};
- u32_le performance_manager_size{};
- u32_le splitter_size{};
- u32_le render_info{};
- INSERT_PADDING_WORDS(4);
- u32_le total_size{};
-};
-static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");
-
class AudioRenderer {
public:
AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
- AudioRendererParameter params,
+ AudioCommon::AudioRendererParameter params,
std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
~AudioRenderer();
- ResultVal<std::vector<u8>> UpdateAudioRenderer(const std::vector<u8>& input_params);
+ ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
+ std::vector<u8>& output_params);
void QueueMixedBuffer(Buffer::Tag tag);
void ReleaseAndQueueBuffers();
u32 GetSampleRate() const;
@@ -252,19 +63,23 @@ public:
Stream::State GetStreamState() const;
private:
- class EffectState;
- class VoiceState;
BehaviorInfo behavior_info{};
- AudioRendererParameter worker_params;
+ AudioCommon::AudioRendererParameter worker_params;
std::shared_ptr<Kernel::WritableEvent> buffer_event;
+ std::vector<ServerMemoryPoolInfo> memory_pool_info;
+ VoiceContext voice_context;
+ EffectContext effect_context;
+ MixContext mix_context;
+ SinkContext sink_context;
+ SplitterContext splitter_context;
std::vector<VoiceState> voices;
- std::vector<VoiceResourceInformation> voice_resources;
- std::vector<EffectState> effects;
std::unique_ptr<AudioOut> audio_out;
StreamPtr stream;
Core::Memory::Memory& memory;
+ CommandGenerator command_generator;
std::size_t elapsed_frame_count{};
+ std::vector<s32> temp_mix_buffer{};
};
} // namespace AudioCore
diff --git a/src/audio_core/behavior_info.cpp b/src/audio_core/behavior_info.cpp
index 94b7a3bf1..3c2e3e6f1 100644
--- a/src/audio_core/behavior_info.cpp
+++ b/src/audio_core/behavior_info.cpp
@@ -9,39 +9,11 @@
namespace AudioCore {
-BehaviorInfo::BehaviorInfo() : process_revision(CURRENT_PROCESS_REVISION) {}
+BehaviorInfo::BehaviorInfo() : process_revision(AudioCommon::CURRENT_PROCESS_REVISION) {}
BehaviorInfo::~BehaviorInfo() = default;
-bool BehaviorInfo::UpdateInput(const std::vector<u8>& buffer, std::size_t offset) {
- if (!CanConsumeBuffer(buffer.size(), offset, sizeof(InParams))) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
- InParams params{};
- std::memcpy(&params, buffer.data() + offset, sizeof(InParams));
-
- if (!IsValidRevision(params.revision)) {
- LOG_ERROR(Audio, "Invalid input revision, revision=0x{:08X}", params.revision);
- return false;
- }
-
- if (user_revision != params.revision) {
- LOG_ERROR(Audio,
- "User revision differs from input revision, expecting 0x{:08X} but got 0x{:08X}",
- user_revision, params.revision);
- return false;
- }
-
- ClearError();
- UpdateFlags(params.flags);
-
- // TODO(ogniK): Check input params size when InfoUpdater is used
-
- return true;
-}
-
bool BehaviorInfo::UpdateOutput(std::vector<u8>& buffer, std::size_t offset) {
- if (!CanConsumeBuffer(buffer.size(), offset, sizeof(OutParams))) {
+ if (!AudioCommon::CanConsumeBuffer(buffer.size(), offset, sizeof(OutParams))) {
LOG_ERROR(Audio, "Buffer is an invalid size!");
return false;
}
@@ -65,36 +37,69 @@ void BehaviorInfo::SetUserRevision(u32_le revision) {
user_revision = revision;
}
+u32_le BehaviorInfo::GetUserRevision() const {
+ return user_revision;
+}
+
+u32_le BehaviorInfo::GetProcessRevision() const {
+ return process_revision;
+}
+
bool BehaviorInfo::IsAdpcmLoopContextBugFixed() const {
- return IsRevisionSupported(2, user_revision);
+ return AudioCommon::IsRevisionSupported(2, user_revision);
}
bool BehaviorInfo::IsSplitterSupported() const {
- return IsRevisionSupported(2, user_revision);
+ return AudioCommon::IsRevisionSupported(2, user_revision);
}
bool BehaviorInfo::IsLongSizePreDelaySupported() const {
- return IsRevisionSupported(3, user_revision);
+ return AudioCommon::IsRevisionSupported(3, user_revision);
}
-bool BehaviorInfo::IsAudioRenererProcessingTimeLimit80PercentSupported() const {
- return IsRevisionSupported(5, user_revision);
+bool BehaviorInfo::IsAudioRendererProcessingTimeLimit80PercentSupported() const {
+ return AudioCommon::IsRevisionSupported(5, user_revision);
}
-bool BehaviorInfo::IsAudioRenererProcessingTimeLimit75PercentSupported() const {
- return IsRevisionSupported(4, user_revision);
+bool BehaviorInfo::IsAudioRendererProcessingTimeLimit75PercentSupported() const {
+ return AudioCommon::IsRevisionSupported(4, user_revision);
}
-bool BehaviorInfo::IsAudioRenererProcessingTimeLimit70PercentSupported() const {
- return IsRevisionSupported(1, user_revision);
+bool BehaviorInfo::IsAudioRendererProcessingTimeLimit70PercentSupported() const {
+ return AudioCommon::IsRevisionSupported(1, user_revision);
}
bool BehaviorInfo::IsElapsedFrameCountSupported() const {
- return IsRevisionSupported(5, user_revision);
+ return AudioCommon::IsRevisionSupported(5, user_revision);
}
bool BehaviorInfo::IsMemoryPoolForceMappingEnabled() const {
return (flags & 1) != 0;
}
+bool BehaviorInfo::IsFlushVoiceWaveBuffersSupported() const {
+ return AudioCommon::IsRevisionSupported(5, user_revision);
+}
+
+bool BehaviorInfo::IsVoicePlayedSampleCountResetAtLoopPointSupported() const {
+ return AudioCommon::IsRevisionSupported(5, user_revision);
+}
+
+bool BehaviorInfo::IsVoicePitchAndSrcSkippedSupported() const {
+ return AudioCommon::IsRevisionSupported(5, user_revision);
+}
+
+bool BehaviorInfo::IsMixInParameterDirtyOnlyUpdateSupported() const {
+ return AudioCommon::IsRevisionSupported(7, user_revision);
+}
+
+bool BehaviorInfo::IsSplitterBugFixed() const {
+ return AudioCommon::IsRevisionSupported(5, user_revision);
+}
+
+void BehaviorInfo::CopyErrorInfo(BehaviorInfo::OutParams& dst) {
+ dst.error_count = static_cast<u32>(error_count);
+ std::copy(errors.begin(), errors.begin() + error_count, dst.errors.begin());
+}
+
} // namespace AudioCore
diff --git a/src/audio_core/behavior_info.h b/src/audio_core/behavior_info.h
index c5e91ab39..512a4ebe3 100644
--- a/src/audio_core/behavior_info.h
+++ b/src/audio_core/behavior_info.h
@@ -14,53 +14,59 @@
namespace AudioCore {
class BehaviorInfo {
public:
+ struct ErrorInfo {
+ u32_le result{};
+ INSERT_PADDING_WORDS(1);
+ u64_le result_info{};
+ };
+ static_assert(sizeof(ErrorInfo) == 0x10, "ErrorInfo is an invalid size");
+
+ struct InParams {
+ u32_le revision{};
+ u32_le padding{};
+ u64_le flags{};
+ };
+ static_assert(sizeof(InParams) == 0x10, "InParams is an invalid size");
+
+ struct OutParams {
+ std::array<ErrorInfo, 10> errors{};
+ u32_le error_count{};
+ INSERT_PADDING_BYTES(12);
+ };
+ static_assert(sizeof(OutParams) == 0xb0, "OutParams is an invalid size");
+
explicit BehaviorInfo();
~BehaviorInfo();
- bool UpdateInput(const std::vector<u8>& buffer, std::size_t offset);
bool UpdateOutput(std::vector<u8>& buffer, std::size_t offset);
void ClearError();
void UpdateFlags(u64_le dest_flags);
void SetUserRevision(u32_le revision);
+ u32_le GetUserRevision() const;
+ u32_le GetProcessRevision() const;
bool IsAdpcmLoopContextBugFixed() const;
bool IsSplitterSupported() const;
bool IsLongSizePreDelaySupported() const;
- bool IsAudioRenererProcessingTimeLimit80PercentSupported() const;
- bool IsAudioRenererProcessingTimeLimit75PercentSupported() const;
- bool IsAudioRenererProcessingTimeLimit70PercentSupported() const;
+ bool IsAudioRendererProcessingTimeLimit80PercentSupported() const;
+ bool IsAudioRendererProcessingTimeLimit75PercentSupported() const;
+ bool IsAudioRendererProcessingTimeLimit70PercentSupported() const;
bool IsElapsedFrameCountSupported() const;
bool IsMemoryPoolForceMappingEnabled() const;
+ bool IsFlushVoiceWaveBuffersSupported() const;
+ bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const;
+ bool IsVoicePitchAndSrcSkippedSupported() const;
+ bool IsMixInParameterDirtyOnlyUpdateSupported() const;
+ bool IsSplitterBugFixed() const;
+ void CopyErrorInfo(OutParams& dst);
private:
u32_le process_revision{};
u32_le user_revision{};
u64_le flags{};
-
- struct ErrorInfo {
- u32_le result{};
- INSERT_PADDING_WORDS(1);
- u64_le result_info{};
- };
- static_assert(sizeof(ErrorInfo) == 0x10, "ErrorInfo is an invalid size");
-
std::array<ErrorInfo, 10> errors{};
std::size_t error_count{};
-
- struct InParams {
- u32_le revision{};
- u32_le padding{};
- u64_le flags{};
- };
- static_assert(sizeof(InParams) == 0x10, "InParams is an invalid size");
-
- struct OutParams {
- std::array<ErrorInfo, 10> errors{};
- u32_le error_count{};
- INSERT_PADDING_BYTES(12);
- };
- static_assert(sizeof(OutParams) == 0xb0, "OutParams is an invalid size");
};
} // namespace AudioCore
diff --git a/src/audio_core/codec.cpp b/src/audio_core/codec.cpp
index c5a0d98ce..2fb91c13a 100644
--- a/src/audio_core/codec.cpp
+++ b/src/audio_core/codec.cpp
@@ -16,8 +16,9 @@ std::vector<s16> DecodeADPCM(const u8* const data, std::size_t size, const ADPCM
constexpr std::size_t FRAME_LEN = 8;
constexpr std::size_t SAMPLES_PER_FRAME = 14;
- constexpr std::array<int, 16> SIGNED_NIBBLES = {
- {0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}};
+ static constexpr std::array<int, 16> SIGNED_NIBBLES{
+ 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1,
+ };
const std::size_t sample_count = (size / FRAME_LEN) * SAMPLES_PER_FRAME;
const std::size_t ret_size =
diff --git a/src/audio_core/codec.h b/src/audio_core/codec.h
index ef2ce01a8..9507abb1b 100644
--- a/src/audio_core/codec.h
+++ b/src/audio_core/codec.h
@@ -38,7 +38,7 @@ using ADPCM_Coeff = std::array<s16, 16>;
* @param state ADPCM state, this is updated with new state
* @return Decoded stereo signed PCM16 data, sample_count in length
*/
-std::vector<s16> DecodeADPCM(const u8* const data, std::size_t size, const ADPCM_Coeff& coeff,
+std::vector<s16> DecodeADPCM(const u8* data, std::size_t size, const ADPCM_Coeff& coeff,
ADPCMState& state);
}; // namespace AudioCore::Codec
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp
new file mode 100644
index 000000000..fb8700ccf
--- /dev/null
+++ b/src/audio_core/command_generator.cpp
@@ -0,0 +1,977 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/algorithm/interpolate.h"
+#include "audio_core/command_generator.h"
+#include "audio_core/effect_context.h"
+#include "audio_core/mix_context.h"
+#include "audio_core/voice_context.h"
+#include "core/memory.h"
+
+namespace AudioCore {
+namespace {
+constexpr std::size_t MIX_BUFFER_SIZE = 0x3f00;
+constexpr std::size_t SCALED_MIX_BUFFER_SIZE = MIX_BUFFER_SIZE << 15ULL;
+
+template <std::size_t N>
+void ApplyMix(s32* output, const s32* input, s32 gain, s32 sample_count) {
+ for (std::size_t i = 0; i < static_cast<std::size_t>(sample_count); i += N) {
+ for (std::size_t j = 0; j < N; j++) {
+ output[i + j] +=
+ static_cast<s32>((static_cast<s64>(input[i + j]) * gain + 0x4000) >> 15);
+ }
+ }
+}
+
+s32 ApplyMixRamp(s32* output, const s32* input, float gain, float delta, s32 sample_count) {
+ s32 x = 0;
+ for (s32 i = 0; i < sample_count; i++) {
+ x = static_cast<s32>(static_cast<float>(input[i]) * gain);
+ output[i] += x;
+ gain += delta;
+ }
+ return x;
+}
+
+void ApplyGain(s32* output, const s32* input, s32 gain, s32 delta, s32 sample_count) {
+ for (s32 i = 0; i < sample_count; i++) {
+ output[i] = static_cast<s32>((static_cast<s64>(input[i]) * gain + 0x4000) >> 15);
+ gain += delta;
+ }
+}
+
+void ApplyGainWithoutDelta(s32* output, const s32* input, s32 gain, s32 sample_count) {
+ for (s32 i = 0; i < sample_count; i++) {
+ output[i] = static_cast<s32>((static_cast<s64>(input[i]) * gain + 0x4000) >> 15);
+ }
+}
+
+s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) {
+ const bool positive = first_sample > 0;
+ auto final_sample = std::abs(first_sample);
+ for (s32 i = 0; i < sample_count; i++) {
+ final_sample = static_cast<s32>((static_cast<s64>(final_sample) * delta) >> 15);
+ if (positive) {
+ output[i] += final_sample;
+ } else {
+ output[i] -= final_sample;
+ }
+ }
+ if (positive) {
+ return final_sample;
+ } else {
+ return -final_sample;
+ }
+}
+
+} // namespace
+
+CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params,
+ VoiceContext& voice_context, MixContext& mix_context,
+ SplitterContext& splitter_context, EffectContext& effect_context,
+ Core::Memory::Memory& memory)
+ : worker_params(worker_params), voice_context(voice_context), mix_context(mix_context),
+ splitter_context(splitter_context), effect_context(effect_context), memory(memory),
+ mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) *
+ worker_params.sample_count),
+ sample_buffer(MIX_BUFFER_SIZE),
+ depop_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) *
+ worker_params.sample_count) {}
+CommandGenerator::~CommandGenerator() = default;
+
+void CommandGenerator::ClearMixBuffers() {
+ std::fill(mix_buffer.begin(), mix_buffer.end(), 0);
+ std::fill(sample_buffer.begin(), sample_buffer.end(), 0);
+ // std::fill(depop_buffer.begin(), depop_buffer.end(), 0);
+}
+
+void CommandGenerator::GenerateVoiceCommands() {
+ if (dumping_frame) {
+ LOG_DEBUG(Audio, "(DSP_TRACE) GenerateVoiceCommands");
+ }
+ // Grab all our voices
+ const auto voice_count = voice_context.GetVoiceCount();
+ for (std::size_t i = 0; i < voice_count; i++) {
+ auto& voice_info = voice_context.GetSortedInfo(i);
+ // Update voices and check if we should queue them
+ if (voice_info.ShouldSkip() || !voice_info.UpdateForCommandGeneration(voice_context)) {
+ continue;
+ }
+
+ // Queue our voice
+ GenerateVoiceCommand(voice_info);
+ }
+ // Update our splitters
+ splitter_context.UpdateInternalState();
+}
+
+void CommandGenerator::GenerateVoiceCommand(ServerVoiceInfo& voice_info) {
+ auto& in_params = voice_info.GetInParams();
+ const auto channel_count = in_params.channel_count;
+
+ for (s32 channel = 0; channel < channel_count; channel++) {
+ const auto resource_id = in_params.voice_channel_resource_id[channel];
+ auto& dsp_state = voice_context.GetDspSharedState(resource_id);
+ auto& channel_resource = voice_context.GetChannelResource(resource_id);
+
+ // Decode our samples for our channel
+ GenerateDataSourceCommand(voice_info, dsp_state, channel);
+
+ if (in_params.should_depop) {
+ in_params.last_volume = 0.0f;
+ } else if (in_params.splitter_info_id != AudioCommon::NO_SPLITTER ||
+ in_params.mix_id != AudioCommon::NO_MIX) {
+ // Apply a biquad filter if needed
+ GenerateBiquadFilterCommandForVoice(voice_info, dsp_state,
+ worker_params.mix_buffer_count, channel);
+ // Base voice volume ramping
+ GenerateVolumeRampCommand(in_params.last_volume, in_params.volume, channel,
+ in_params.node_id);
+ in_params.last_volume = in_params.volume;
+
+ if (in_params.mix_id != AudioCommon::NO_MIX) {
+ // If we're using a mix id
+ auto& mix_info = mix_context.GetInfo(in_params.mix_id);
+ const auto& dest_mix_params = mix_info.GetInParams();
+
+ // Voice Mixing
+ GenerateVoiceMixCommand(
+ channel_resource.GetCurrentMixVolume(), channel_resource.GetLastMixVolume(),
+ dsp_state, dest_mix_params.buffer_offset, dest_mix_params.buffer_count,
+ worker_params.mix_buffer_count + channel, in_params.node_id);
+
+ // Update last mix volumes
+ channel_resource.UpdateLastMixVolumes();
+ } else if (in_params.splitter_info_id != AudioCommon::NO_SPLITTER) {
+ s32 base = channel;
+ while (auto* destination_data =
+ GetDestinationData(in_params.splitter_info_id, base)) {
+ base += channel_count;
+
+ if (!destination_data->IsConfigured()) {
+ continue;
+ }
+ if (destination_data->GetMixId() >= static_cast<int>(mix_context.GetCount())) {
+ continue;
+ }
+
+ const auto& mix_info = mix_context.GetInfo(destination_data->GetMixId());
+ const auto& dest_mix_params = mix_info.GetInParams();
+ GenerateVoiceMixCommand(
+ destination_data->CurrentMixVolumes(), destination_data->LastMixVolumes(),
+ dsp_state, dest_mix_params.buffer_offset, dest_mix_params.buffer_count,
+ worker_params.mix_buffer_count + channel, in_params.node_id);
+ destination_data->MarkDirty();
+ }
+ }
+ // Update biquad filter enabled states
+ for (std::size_t i = 0; i < AudioCommon::MAX_BIQUAD_FILTERS; i++) {
+ in_params.was_biquad_filter_enabled[i] = in_params.biquad_filter[i].enabled;
+ }
+ }
+ }
+}
+
+void CommandGenerator::GenerateSubMixCommands() {
+ const auto mix_count = mix_context.GetCount();
+ for (std::size_t i = 0; i < mix_count; i++) {
+ auto& mix_info = mix_context.GetSortedInfo(i);
+ const auto& in_params = mix_info.GetInParams();
+ if (!in_params.in_use || in_params.mix_id == AudioCommon::FINAL_MIX) {
+ continue;
+ }
+ GenerateSubMixCommand(mix_info);
+ }
+}
+
+void CommandGenerator::GenerateFinalMixCommands() {
+ GenerateFinalMixCommand();
+}
+
+void CommandGenerator::PreCommand() {
+ if (!dumping_frame) {
+ return;
+ }
+ for (std::size_t i = 0; i < splitter_context.GetInfoCount(); i++) {
+ const auto& base = splitter_context.GetInfo(i);
+ std::string graph = fmt::format("b[{}]", i);
+ const auto* head = base.GetHead();
+ while (head != nullptr) {
+ graph += fmt::format("->{}", head->GetMixId());
+ head = head->GetNextDestination();
+ }
+ LOG_DEBUG(Audio, "(DSP_TRACE) SplitterGraph splitter_info={}, {}", i, graph);
+ }
+}
+
+void CommandGenerator::PostCommand() {
+ if (!dumping_frame) {
+ return;
+ }
+ dumping_frame = false;
+}
+
+void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
+ s32 channel) {
+ const auto& in_params = voice_info.GetInParams();
+ const auto depop = in_params.should_depop;
+
+ if (depop) {
+ if (in_params.mix_id != AudioCommon::NO_MIX) {
+ auto& mix_info = mix_context.GetInfo(in_params.mix_id);
+ const auto& mix_in = mix_info.GetInParams();
+ GenerateDepopPrepareCommand(dsp_state, mix_in.buffer_count, mix_in.buffer_offset);
+ } else if (in_params.splitter_info_id != AudioCommon::NO_SPLITTER) {
+ s32 index{};
+ while (const auto* destination =
+ GetDestinationData(in_params.splitter_info_id, index++)) {
+ if (!destination->IsConfigured()) {
+ continue;
+ }
+ auto& mix_info = mix_context.GetInfo(destination->GetMixId());
+ const auto& mix_in = mix_info.GetInParams();
+ GenerateDepopPrepareCommand(dsp_state, mix_in.buffer_count, mix_in.buffer_offset);
+ }
+ }
+ } else {
+ switch (in_params.sample_format) {
+ case SampleFormat::Pcm16:
+ DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(channel), dsp_state, channel,
+ worker_params.sample_rate, worker_params.sample_count,
+ in_params.node_id);
+ break;
+ case SampleFormat::Adpcm:
+ ASSERT(channel == 0 && in_params.channel_count == 1);
+ DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(0), dsp_state, 0,
+ worker_params.sample_rate, worker_params.sample_count,
+ in_params.node_id);
+ break;
+ default:
+ UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format);
+ }
+ }
+}
+
+void CommandGenerator::GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info,
+ VoiceState& dsp_state,
+ s32 mix_buffer_count, s32 channel) {
+ for (std::size_t i = 0; i < AudioCommon::MAX_BIQUAD_FILTERS; i++) {
+ const auto& in_params = voice_info.GetInParams();
+ auto& biquad_filter = in_params.biquad_filter[i];
+ // Check if biquad filter is actually used
+ if (!biquad_filter.enabled) {
+ continue;
+ }
+
+ // Reinitialize our biquad filter state if it was enabled previously
+ if (!in_params.was_biquad_filter_enabled[i]) {
+ dsp_state.biquad_filter_state.fill(0);
+ }
+
+ // Generate biquad filter
+ // GenerateBiquadFilterCommand(mix_buffer_count, biquad_filter,
+ // dsp_state.biquad_filter_state,
+ // mix_buffer_count + channel, mix_buffer_count +
+ // channel, worker_params.sample_count,
+ // voice_info.GetInParams().node_id);
+ }
+}
+
+void AudioCore::CommandGenerator::GenerateBiquadFilterCommand(
+ s32 mix_buffer, const BiquadFilterParameter& params, std::array<s64, 2>& state,
+ std::size_t input_offset, std::size_t output_offset, s32 sample_count, s32 node_id) {
+ if (dumping_frame) {
+ LOG_DEBUG(Audio,
+ "(DSP_TRACE) GenerateBiquadFilterCommand node_id={}, "
+ "input_mix_buffer={}, output_mix_buffer={}",
+ node_id, input_offset, output_offset);
+ }
+ const auto* input = GetMixBuffer(input_offset);
+ auto* output = GetMixBuffer(output_offset);
+
+ // Biquad filter parameters
+ const auto [n0, n1, n2] = params.numerator;
+ const auto [d0, d1] = params.denominator;
+
+ // Biquad filter states
+ auto [s0, s1] = state;
+
+ constexpr s64 int32_min = std::numeric_limits<s32>::min();
+ constexpr s64 int32_max = std::numeric_limits<s32>::max();
+
+ for (int i = 0; i < sample_count; ++i) {
+ const auto sample = static_cast<s64>(input[i]);
+ const auto f = (sample * n0 + s0 + 0x4000) >> 15;
+ const auto y = std::clamp(f, int32_min, int32_max);
+ s0 = sample * n1 + y * d0 + s1;
+ s1 = sample * n2 + y * d1;
+ output[i] = static_cast<s32>(y);
+ }
+
+ state = {s0, s1};
+}
+
+void CommandGenerator::GenerateDepopPrepareCommand(VoiceState& dsp_state,
+ std::size_t mix_buffer_count,
+ std::size_t mix_buffer_offset) {
+ for (std::size_t i = 0; i < mix_buffer_count; i++) {
+ auto& sample = dsp_state.previous_samples[i];
+ if (sample != 0) {
+ depop_buffer[mix_buffer_offset + i] += sample;
+ sample = 0;
+ }
+ }
+}
+
+void CommandGenerator::GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_count,
+ std::size_t mix_buffer_offset,
+ s32 sample_rate) {
+ const std::size_t end_offset =
+ std::min(mix_buffer_offset + mix_buffer_count, GetTotalMixBufferCount());
+ const s32 delta = sample_rate == 48000 ? 0x7B29 : 0x78CB;
+ for (std::size_t i = mix_buffer_offset; i < end_offset; i++) {
+ if (depop_buffer[i] == 0) {
+ continue;
+ }
+
+ depop_buffer[i] =
+ ApplyMixDepop(GetMixBuffer(i), depop_buffer[i], delta, worker_params.sample_count);
+ }
+}
+
+void CommandGenerator::GenerateEffectCommand(ServerMixInfo& mix_info) {
+ const std::size_t effect_count = effect_context.GetCount();
+ const auto buffer_offset = mix_info.GetInParams().buffer_offset;
+ for (std::size_t i = 0; i < effect_count; i++) {
+ const auto index = mix_info.GetEffectOrder(i);
+ if (index == AudioCommon::NO_EFFECT_ORDER) {
+ break;
+ }
+ auto* info = effect_context.GetInfo(index);
+ const auto type = info->GetType();
+
+ // TODO(ogniK): Finish remaining effects
+ switch (type) {
+ case EffectType::Aux:
+ GenerateAuxCommand(buffer_offset, info, info->IsEnabled());
+ break;
+ case EffectType::I3dl2Reverb:
+ GenerateI3dl2ReverbEffectCommand(buffer_offset, info, info->IsEnabled());
+ break;
+ case EffectType::BiquadFilter:
+ GenerateBiquadFilterEffectCommand(buffer_offset, info, info->IsEnabled());
+ break;
+ default:
+ break;
+ }
+
+ info->UpdateForCommandGeneration();
+ }
+}
+
+void CommandGenerator::GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info,
+ bool enabled) {
+ if (!enabled) {
+ return;
+ }
+ const auto& params = dynamic_cast<EffectI3dl2Reverb*>(info)->GetParams();
+ const auto channel_count = params.channel_count;
+ for (s32 i = 0; i < channel_count; i++) {
+ // TODO(ogniK): Actually implement reverb
+ if (params.input[i] != params.output[i]) {
+ const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]);
+ auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]);
+ ApplyMix<1>(output, input, 32768, worker_params.sample_count);
+ }
+ }
+}
+
+void CommandGenerator::GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info,
+ bool enabled) {
+ if (!enabled) {
+ return;
+ }
+ const auto& params = dynamic_cast<EffectBiquadFilter*>(info)->GetParams();
+ const auto channel_count = params.channel_count;
+ for (s32 i = 0; i < channel_count; i++) {
+ // TODO(ogniK): Actually implement biquad filter
+ if (params.input[i] != params.output[i]) {
+ const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]);
+ auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]);
+ ApplyMix<1>(output, input, 32768, worker_params.sample_count);
+ }
+ }
+}
+
+void CommandGenerator::GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled) {
+ auto* aux = dynamic_cast<EffectAuxInfo*>(info);
+ const auto& params = aux->GetParams();
+ if (aux->GetSendBuffer() != 0 && aux->GetRecvBuffer() != 0) {
+ const auto max_channels = params.count;
+ u32 offset{};
+ for (u32 channel = 0; channel < max_channels; channel++) {
+ u32 write_count = 0;
+ if (channel == (max_channels - 1)) {
+ write_count = offset + worker_params.sample_count;
+ }
+
+ const auto input_index = params.input_mix_buffers[channel] + mix_buffer_offset;
+ const auto output_index = params.output_mix_buffers[channel] + mix_buffer_offset;
+
+ if (enabled) {
+ AuxInfoDSP send_info{};
+ AuxInfoDSP recv_info{};
+ memory.ReadBlock(aux->GetSendInfo(), &send_info, sizeof(AuxInfoDSP));
+ memory.ReadBlock(aux->GetRecvInfo(), &recv_info, sizeof(AuxInfoDSP));
+
+ WriteAuxBuffer(send_info, aux->GetSendBuffer(), params.sample_count,
+ GetMixBuffer(input_index), worker_params.sample_count, offset,
+ write_count);
+ memory.WriteBlock(aux->GetSendInfo(), &send_info, sizeof(AuxInfoDSP));
+
+ const auto samples_read = ReadAuxBuffer(
+ recv_info, aux->GetRecvBuffer(), params.sample_count,
+ GetMixBuffer(output_index), worker_params.sample_count, offset, write_count);
+ memory.WriteBlock(aux->GetRecvInfo(), &recv_info, sizeof(AuxInfoDSP));
+
+ if (samples_read != static_cast<int>(worker_params.sample_count) &&
+ samples_read <= params.sample_count) {
+ std::memset(GetMixBuffer(output_index), 0, params.sample_count - samples_read);
+ }
+ } else {
+ AuxInfoDSP empty{};
+ memory.WriteBlock(aux->GetSendInfo(), &empty, sizeof(AuxInfoDSP));
+ memory.WriteBlock(aux->GetRecvInfo(), &empty, sizeof(AuxInfoDSP));
+ if (output_index != input_index) {
+ std::memcpy(GetMixBuffer(output_index), GetMixBuffer(input_index),
+ worker_params.sample_count * sizeof(s32));
+ }
+ }
+
+ offset += worker_params.sample_count;
+ }
+ }
+}
+
+ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter_id, s32 index) {
+ if (splitter_id == AudioCommon::NO_SPLITTER) {
+ return nullptr;
+ }
+ return splitter_context.GetDestinationData(splitter_id, index);
+}
+
+s32 CommandGenerator::WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples,
+ const s32* data, u32 sample_count, u32 write_offset,
+ u32 write_count) {
+ if (max_samples == 0) {
+ return 0;
+ }
+ u32 offset = dsp_info.write_offset + write_offset;
+ if (send_buffer == 0 || offset > max_samples) {
+ return 0;
+ }
+
+ std::size_t data_offset{};
+ u32 remaining = sample_count;
+ while (remaining > 0) {
+ // Get position in buffer
+ const auto base = send_buffer + (offset * sizeof(u32));
+ const auto samples_to_grab = std::min(max_samples - offset, remaining);
+ // Write to output
+ memory.WriteBlock(base, (data + data_offset), samples_to_grab * sizeof(u32));
+ offset = (offset + samples_to_grab) % max_samples;
+ remaining -= samples_to_grab;
+ data_offset += samples_to_grab;
+ }
+
+ if (write_count != 0) {
+ dsp_info.write_offset = (dsp_info.write_offset + write_count) % max_samples;
+ }
+ return sample_count;
+}
+
+s32 CommandGenerator::ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples,
+ s32* out_data, u32 sample_count, u32 read_offset,
+ u32 read_count) {
+ if (max_samples == 0) {
+ return 0;
+ }
+
+ u32 offset = recv_info.read_offset + read_offset;
+ if (recv_buffer == 0 || offset > max_samples) {
+ return 0;
+ }
+
+ u32 remaining = sample_count;
+ while (remaining > 0) {
+ const auto base = recv_buffer + (offset * sizeof(u32));
+ const auto samples_to_grab = std::min(max_samples - offset, remaining);
+ std::vector<s32> buffer(samples_to_grab);
+ memory.ReadBlock(base, buffer.data(), buffer.size() * sizeof(u32));
+ std::memcpy(out_data, buffer.data(), buffer.size() * sizeof(u32));
+ out_data += samples_to_grab;
+ offset = (offset + samples_to_grab) % max_samples;
+ remaining -= samples_to_grab;
+ }
+
+ if (read_count != 0) {
+ recv_info.read_offset = (recv_info.read_offset + read_count) % max_samples;
+ }
+ return sample_count;
+}
+
+void CommandGenerator::GenerateVolumeRampCommand(float last_volume, float current_volume,
+ s32 channel, s32 node_id) {
+ const auto last = static_cast<s32>(last_volume * 32768.0f);
+ const auto current = static_cast<s32>(current_volume * 32768.0f);
+ const auto delta = static_cast<s32>((static_cast<float>(current) - static_cast<float>(last)) /
+ static_cast<float>(worker_params.sample_count));
+
+ if (dumping_frame) {
+ LOG_DEBUG(Audio,
+ "(DSP_TRACE) GenerateVolumeRampCommand node_id={}, input={}, output={}, "
+ "last_volume={}, current_volume={}",
+ node_id, GetMixChannelBufferOffset(channel), GetMixChannelBufferOffset(channel),
+ last_volume, current_volume);
+ }
+ // Apply generic gain on samples
+ ApplyGain(GetChannelMixBuffer(channel), GetChannelMixBuffer(channel), last, delta,
+ worker_params.sample_count);
+}
+
+void CommandGenerator::GenerateVoiceMixCommand(const MixVolumeBuffer& mix_volumes,
+ const MixVolumeBuffer& last_mix_volumes,
+ VoiceState& dsp_state, s32 mix_buffer_offset,
+ s32 mix_buffer_count, s32 voice_index, s32 node_id) {
+ // Loop all our mix buffers
+ for (s32 i = 0; i < mix_buffer_count; i++) {
+ if (last_mix_volumes[i] != 0.0f || mix_volumes[i] != 0.0f) {
+ const auto delta = static_cast<float>((mix_volumes[i] - last_mix_volumes[i])) /
+ static_cast<float>(worker_params.sample_count);
+
+ if (dumping_frame) {
+ LOG_DEBUG(Audio,
+ "(DSP_TRACE) GenerateVoiceMixCommand node_id={}, input={}, "
+ "output={}, last_volume={}, current_volume={}",
+ node_id, voice_index, mix_buffer_offset + i, last_mix_volumes[i],
+ mix_volumes[i]);
+ }
+
+ dsp_state.previous_samples[i] =
+ ApplyMixRamp(GetMixBuffer(mix_buffer_offset + i), GetMixBuffer(voice_index),
+ last_mix_volumes[i], delta, worker_params.sample_count);
+ } else {
+ dsp_state.previous_samples[i] = 0;
+ }
+ }
+}
+
+void CommandGenerator::GenerateSubMixCommand(ServerMixInfo& mix_info) {
+ if (dumping_frame) {
+ LOG_DEBUG(Audio, "(DSP_TRACE) GenerateSubMixCommand");
+ }
+ const auto& in_params = mix_info.GetInParams();
+ GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
+ in_params.sample_rate);
+
+ GenerateEffectCommand(mix_info);
+
+ GenerateMixCommands(mix_info);
+}
+
+void CommandGenerator::GenerateMixCommands(ServerMixInfo& mix_info) {
+ if (!mix_info.HasAnyConnection()) {
+ return;
+ }
+ const auto& in_params = mix_info.GetInParams();
+ if (in_params.dest_mix_id != AudioCommon::NO_MIX) {
+ const auto& dest_mix = mix_context.GetInfo(in_params.dest_mix_id);
+ const auto& dest_in_params = dest_mix.GetInParams();
+
+ const auto buffer_count = in_params.buffer_count;
+
+ for (s32 i = 0; i < buffer_count; i++) {
+ for (s32 j = 0; j < dest_in_params.buffer_count; j++) {
+ const auto mixed_volume = in_params.volume * in_params.mix_volume[i][j];
+ if (mixed_volume != 0.0f) {
+ GenerateMixCommand(dest_in_params.buffer_offset + j,
+ in_params.buffer_offset + i, mixed_volume,
+ in_params.node_id);
+ }
+ }
+ }
+ } else if (in_params.splitter_id != AudioCommon::NO_SPLITTER) {
+ s32 base{};
+ while (const auto* destination_data = GetDestinationData(in_params.splitter_id, base++)) {
+ if (!destination_data->IsConfigured()) {
+ continue;
+ }
+
+ const auto& dest_mix = mix_context.GetInfo(destination_data->GetMixId());
+ const auto& dest_in_params = dest_mix.GetInParams();
+ const auto mix_index = (base - 1) % in_params.buffer_count + in_params.buffer_offset;
+ for (std::size_t i = 0; i < static_cast<std::size_t>(dest_in_params.buffer_count);
+ i++) {
+ const auto mixed_volume = in_params.volume * destination_data->GetMixVolume(i);
+ if (mixed_volume != 0.0f) {
+ GenerateMixCommand(dest_in_params.buffer_offset + i, mix_index, mixed_volume,
+ in_params.node_id);
+ }
+ }
+ }
+ }
+}
+
+void CommandGenerator::GenerateMixCommand(std::size_t output_offset, std::size_t input_offset,
+ float volume, s32 node_id) {
+
+ if (dumping_frame) {
+ LOG_DEBUG(Audio,
+ "(DSP_TRACE) GenerateMixCommand node_id={}, input={}, output={}, volume={}",
+ node_id, input_offset, output_offset, volume);
+ }
+
+ auto* output = GetMixBuffer(output_offset);
+ const auto* input = GetMixBuffer(input_offset);
+
+ const s32 gain = static_cast<s32>(volume * 32768.0f);
+ // Mix with loop unrolling
+ if (worker_params.sample_count % 4 == 0) {
+ ApplyMix<4>(output, input, gain, worker_params.sample_count);
+ } else if (worker_params.sample_count % 2 == 0) {
+ ApplyMix<2>(output, input, gain, worker_params.sample_count);
+ } else {
+ ApplyMix<1>(output, input, gain, worker_params.sample_count);
+ }
+}
+
+void CommandGenerator::GenerateFinalMixCommand() {
+ if (dumping_frame) {
+ LOG_DEBUG(Audio, "(DSP_TRACE) GenerateFinalMixCommand");
+ }
+ auto& mix_info = mix_context.GetFinalMixInfo();
+ const auto& in_params = mix_info.GetInParams();
+
+ GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
+ in_params.sample_rate);
+
+ GenerateEffectCommand(mix_info);
+
+ for (s32 i = 0; i < in_params.buffer_count; i++) {
+ const s32 gain = static_cast<s32>(in_params.volume * 32768.0f);
+ if (dumping_frame) {
+ LOG_DEBUG(
+ Audio,
+ "(DSP_TRACE) ApplyGainWithoutDelta node_id={}, input={}, output={}, volume={}",
+ in_params.node_id, in_params.buffer_offset + i, in_params.buffer_offset + i,
+ in_params.volume);
+ }
+ ApplyGainWithoutDelta(GetMixBuffer(in_params.buffer_offset + i),
+ GetMixBuffer(in_params.buffer_offset + i), gain,
+ worker_params.sample_count);
+ }
+}
+
+s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
+ s32 sample_count, s32 channel, std::size_t mix_offset) {
+ const auto& in_params = voice_info.GetInParams();
+ const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
+ if (wave_buffer.buffer_address == 0) {
+ return 0;
+ }
+ if (wave_buffer.buffer_size == 0) {
+ return 0;
+ }
+ if (wave_buffer.end_sample_offset < wave_buffer.start_sample_offset) {
+ return 0;
+ }
+ const auto samples_remaining =
+ (wave_buffer.end_sample_offset - wave_buffer.start_sample_offset) - dsp_state.offset;
+ const auto start_offset =
+ ((wave_buffer.start_sample_offset + dsp_state.offset) * in_params.channel_count) *
+ sizeof(s16);
+ const auto buffer_pos = wave_buffer.buffer_address + start_offset;
+ const auto samples_processed = std::min(sample_count, samples_remaining);
+
+ if (in_params.channel_count == 1) {
+ std::vector<s16> buffer(samples_processed);
+ memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(s16));
+ for (std::size_t i = 0; i < buffer.size(); i++) {
+ sample_buffer[mix_offset + i] = buffer[i];
+ }
+ } else {
+ const auto channel_count = in_params.channel_count;
+ std::vector<s16> buffer(samples_processed * channel_count);
+ memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(s16));
+
+ for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
+ sample_buffer[mix_offset + i] = buffer[i * channel_count + channel];
+ }
+ }
+
+ return samples_processed;
+}
+
+s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
+ s32 sample_count, s32 channel, std::size_t mix_offset) {
+ const auto& in_params = voice_info.GetInParams();
+ const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
+ if (wave_buffer.buffer_address == 0) {
+ return 0;
+ }
+ if (wave_buffer.buffer_size == 0) {
+ return 0;
+ }
+ if (wave_buffer.end_sample_offset < wave_buffer.start_sample_offset) {
+ return 0;
+ }
+
+ static constexpr std::array<int, 16> SIGNED_NIBBLES{
+ 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1,
+ };
+
+ constexpr std::size_t FRAME_LEN = 8;
+ constexpr std::size_t NIBBLES_PER_SAMPLE = 16;
+ constexpr std::size_t SAMPLES_PER_FRAME = 14;
+
+ auto frame_header = dsp_state.context.header;
+ s32 idx = (frame_header >> 4) & 0xf;
+ s32 scale = frame_header & 0xf;
+ s16 yn1 = dsp_state.context.yn1;
+ s16 yn2 = dsp_state.context.yn2;
+
+ Codec::ADPCM_Coeff coeffs;
+ memory.ReadBlock(in_params.additional_params_address, coeffs.data(),
+ sizeof(Codec::ADPCM_Coeff));
+
+ s32 coef1 = coeffs[idx * 2];
+ s32 coef2 = coeffs[idx * 2 + 1];
+
+ const auto samples_remaining =
+ (wave_buffer.end_sample_offset - wave_buffer.start_sample_offset) - dsp_state.offset;
+ const auto samples_processed = std::min(sample_count, samples_remaining);
+ const auto sample_pos = wave_buffer.start_sample_offset + dsp_state.offset;
+
+ const auto samples_remaining_in_frame = sample_pos % SAMPLES_PER_FRAME;
+ auto position_in_frame = ((sample_pos / SAMPLES_PER_FRAME) * NIBBLES_PER_SAMPLE) +
+ samples_remaining_in_frame + (samples_remaining_in_frame != 0 ? 2 : 0);
+
+ const auto decode_sample = [&](const int nibble) -> s16 {
+ const int xn = nibble * (1 << scale);
+ // We first transform everything into 11 bit fixed point, perform the second order
+ // digital filter, then transform back.
+ // 0x400 == 0.5 in 11 bit fixed point.
+ // Filter: y[n] = x[n] + 0.5 + c1 * y[n-1] + c2 * y[n-2]
+ int val = ((xn << 11) + 0x400 + coef1 * yn1 + coef2 * yn2) >> 11;
+ // Clamp to output range.
+ val = std::clamp<s32>(val, -32768, 32767);
+ // Advance output feedback.
+ yn2 = yn1;
+ yn1 = static_cast<s16>(val);
+ return yn1;
+ };
+
+ std::size_t buffer_offset{};
+ std::vector<u8> buffer(
+ std::max((samples_processed / FRAME_LEN) * SAMPLES_PER_FRAME, FRAME_LEN));
+ memory.ReadBlock(wave_buffer.buffer_address + (position_in_frame / 2), buffer.data(),
+ buffer.size());
+ std::size_t cur_mix_offset = mix_offset;
+
+ auto remaining_samples = samples_processed;
+ while (remaining_samples > 0) {
+ if (position_in_frame % NIBBLES_PER_SAMPLE == 0) {
+ // Read header
+ frame_header = buffer[buffer_offset++];
+ idx = (frame_header >> 4) & 0xf;
+ scale = frame_header & 0xf;
+ coef1 = coeffs[idx * 2];
+ coef2 = coeffs[idx * 2 + 1];
+ position_in_frame += 2;
+
+ // Decode entire frame
+ if (remaining_samples >= static_cast<int>(SAMPLES_PER_FRAME)) {
+ for (std::size_t i = 0; i < SAMPLES_PER_FRAME / 2; i++) {
+ // Sample 1
+ const s32 s0 = SIGNED_NIBBLES[buffer[buffer_offset] >> 4];
+ const s32 s1 = SIGNED_NIBBLES[buffer[buffer_offset++] & 0xf];
+ const s16 sample_1 = decode_sample(s0);
+ const s16 sample_2 = decode_sample(s1);
+ sample_buffer[cur_mix_offset++] = sample_1;
+ sample_buffer[cur_mix_offset++] = sample_2;
+ }
+ remaining_samples -= static_cast<int>(SAMPLES_PER_FRAME);
+ position_in_frame += SAMPLES_PER_FRAME;
+ continue;
+ }
+ }
+ // Decode mid frame
+ s32 current_nibble = buffer[buffer_offset];
+ if (position_in_frame++ & 0x1) {
+ current_nibble &= 0xf;
+ buffer_offset++;
+ } else {
+ current_nibble >>= 4;
+ }
+ const s16 sample = decode_sample(SIGNED_NIBBLES[current_nibble]);
+ sample_buffer[cur_mix_offset++] = sample;
+ remaining_samples--;
+ }
+
+ dsp_state.context.header = frame_header;
+ dsp_state.context.yn1 = yn1;
+ dsp_state.context.yn2 = yn2;
+
+ return samples_processed;
+}
+
+s32* CommandGenerator::GetMixBuffer(std::size_t index) {
+ return mix_buffer.data() + (index * worker_params.sample_count);
+}
+
+const s32* CommandGenerator::GetMixBuffer(std::size_t index) const {
+ return mix_buffer.data() + (index * worker_params.sample_count);
+}
+
+std::size_t CommandGenerator::GetMixChannelBufferOffset(s32 channel) const {
+ return worker_params.mix_buffer_count + channel;
+}
+
+std::size_t CommandGenerator::GetTotalMixBufferCount() const {
+ return worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT;
+}
+
+s32* CommandGenerator::GetChannelMixBuffer(s32 channel) {
+ return GetMixBuffer(worker_params.mix_buffer_count + channel);
+}
+
+const s32* CommandGenerator::GetChannelMixBuffer(s32 channel) const {
+ return GetMixBuffer(worker_params.mix_buffer_count + channel);
+}
+
+void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* output,
+ VoiceState& dsp_state, s32 channel,
+ s32 target_sample_rate, s32 sample_count,
+ s32 node_id) {
+ const auto& in_params = voice_info.GetInParams();
+ if (dumping_frame) {
+ LOG_DEBUG(Audio,
+ "(DSP_TRACE) DecodeFromWaveBuffers, node_id={}, channel={}, "
+ "format={}, sample_count={}, sample_rate={}, mix_id={}, splitter_id={}",
+ node_id, channel, in_params.sample_format, sample_count, in_params.sample_rate,
+ in_params.mix_id, in_params.splitter_info_id);
+ }
+ ASSERT_OR_EXECUTE(output != nullptr, { return; });
+
+ const auto resample_rate = static_cast<s32>(
+ static_cast<float>(in_params.sample_rate) / static_cast<float>(target_sample_rate) *
+ static_cast<float>(static_cast<s32>(in_params.pitch * 32768.0f)));
+ if (dsp_state.fraction + sample_count * resample_rate >
+ static_cast<s32>(SCALED_MIX_BUFFER_SIZE - 4ULL)) {
+ return;
+ }
+
+ auto min_required_samples =
+ std::min(static_cast<s32>(SCALED_MIX_BUFFER_SIZE) - dsp_state.fraction, resample_rate);
+ if (min_required_samples >= sample_count) {
+ min_required_samples = sample_count;
+ }
+
+ std::size_t temp_mix_offset{};
+ bool is_buffer_completed{false};
+ auto samples_remaining = sample_count;
+ while (samples_remaining > 0 && !is_buffer_completed) {
+ const auto samples_to_output = std::min(samples_remaining, min_required_samples);
+ const auto samples_to_read = (samples_to_output * resample_rate + dsp_state.fraction) >> 15;
+
+ if (!in_params.behavior_flags.is_pitch_and_src_skipped) {
+ // Append sample histtory for resampler
+ for (std::size_t i = 0; i < AudioCommon::MAX_SAMPLE_HISTORY; i++) {
+ sample_buffer[temp_mix_offset + i] = dsp_state.sample_history[i];
+ }
+ temp_mix_offset += 4;
+ }
+
+ s32 samples_read{};
+ while (samples_read < samples_to_read) {
+ const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
+ // No more data can be read
+ if (!dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index]) {
+ is_buffer_completed = true;
+ break;
+ }
+
+ if (in_params.sample_format == SampleFormat::Adpcm && dsp_state.offset == 0 &&
+ wave_buffer.context_address != 0 && wave_buffer.context_size != 0) {
+ // TODO(ogniK): ADPCM loop context
+ }
+
+ s32 samples_decoded{0};
+ switch (in_params.sample_format) {
+ case SampleFormat::Pcm16:
+ samples_decoded = DecodePcm16(voice_info, dsp_state, samples_to_read - samples_read,
+ channel, temp_mix_offset);
+ break;
+ case SampleFormat::Adpcm:
+ samples_decoded = DecodeAdpcm(voice_info, dsp_state, samples_to_read - samples_read,
+ channel, temp_mix_offset);
+ break;
+ default:
+ UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format);
+ }
+
+ temp_mix_offset += samples_decoded;
+ samples_read += samples_decoded;
+ dsp_state.offset += samples_decoded;
+ dsp_state.played_sample_count += samples_decoded;
+
+ if (dsp_state.offset >=
+ (wave_buffer.end_sample_offset - wave_buffer.start_sample_offset) ||
+ samples_decoded == 0) {
+ // Reset our sample offset
+ dsp_state.offset = 0;
+ if (wave_buffer.is_looping) {
+ if (samples_decoded == 0) {
+ // End of our buffer
+ is_buffer_completed = true;
+ break;
+ }
+
+ if (in_params.behavior_flags.is_played_samples_reset_at_loop_point.Value()) {
+ dsp_state.played_sample_count = 0;
+ }
+ } else {
+
+ // Update our wave buffer states
+ dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index] = false;
+ dsp_state.wave_buffer_consumed++;
+ dsp_state.wave_buffer_index =
+ (dsp_state.wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS;
+ if (wave_buffer.end_of_stream) {
+ dsp_state.played_sample_count = 0;
+ }
+ }
+ }
+ }
+
+ if (in_params.behavior_flags.is_pitch_and_src_skipped.Value()) {
+ // No need to resample
+ std::memcpy(output, sample_buffer.data(), samples_read * sizeof(s32));
+ } else {
+ std::fill(sample_buffer.begin() + temp_mix_offset,
+ sample_buffer.begin() + temp_mix_offset + (samples_to_read - samples_read),
+ 0);
+ AudioCore::Resample(output, sample_buffer.data(), resample_rate, dsp_state.fraction,
+ samples_to_output);
+ // Resample
+ for (std::size_t i = 0; i < AudioCommon::MAX_SAMPLE_HISTORY; i++) {
+ dsp_state.sample_history[i] = sample_buffer[samples_to_read + i];
+ }
+ }
+ output += samples_to_output;
+ samples_remaining -= samples_to_output;
+ }
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h
new file mode 100644
index 000000000..53e57748b
--- /dev/null
+++ b/src/audio_core/command_generator.h
@@ -0,0 +1,102 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include "audio_core/common.h"
+#include "audio_core/voice_context.h"
+#include "common/common_types.h"
+
+namespace Core::Memory {
+class Memory;
+}
+
+namespace AudioCore {
+class MixContext;
+class SplitterContext;
+class ServerSplitterDestinationData;
+class ServerMixInfo;
+class EffectContext;
+class EffectBase;
+struct AuxInfoDSP;
+using MixVolumeBuffer = std::array<float, AudioCommon::MAX_MIX_BUFFERS>;
+
+class CommandGenerator {
+public:
+ explicit CommandGenerator(AudioCommon::AudioRendererParameter& worker_params,
+ VoiceContext& voice_context, MixContext& mix_context,
+ SplitterContext& splitter_context, EffectContext& effect_context,
+ Core::Memory::Memory& memory);
+ ~CommandGenerator();
+
+ void ClearMixBuffers();
+ void GenerateVoiceCommands();
+ void GenerateVoiceCommand(ServerVoiceInfo& voice_info);
+ void GenerateSubMixCommands();
+ void GenerateFinalMixCommands();
+ void PreCommand();
+ void PostCommand();
+
+ s32* GetChannelMixBuffer(s32 channel);
+ const s32* GetChannelMixBuffer(s32 channel) const;
+ s32* GetMixBuffer(std::size_t index);
+ const s32* GetMixBuffer(std::size_t index) const;
+ std::size_t GetMixChannelBufferOffset(s32 channel) const;
+
+ std::size_t GetTotalMixBufferCount() const;
+
+private:
+ void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel);
+ void GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
+ s32 mix_buffer_count, s32 channel);
+ void GenerateVolumeRampCommand(float last_volume, float current_volume, s32 channel,
+ s32 node_id);
+ void GenerateVoiceMixCommand(const MixVolumeBuffer& mix_volumes,
+ const MixVolumeBuffer& last_mix_volumes, VoiceState& dsp_state,
+ s32 mix_buffer_offset, s32 mix_buffer_count, s32 voice_index,
+ s32 node_id);
+ void GenerateSubMixCommand(ServerMixInfo& mix_info);
+ void GenerateMixCommands(ServerMixInfo& mix_info);
+ void GenerateMixCommand(std::size_t output_offset, std::size_t input_offset, float volume,
+ s32 node_id);
+ void GenerateFinalMixCommand();
+ void GenerateBiquadFilterCommand(s32 mix_buffer, const BiquadFilterParameter& params,
+ std::array<s64, 2>& state, std::size_t input_offset,
+ std::size_t output_offset, s32 sample_count, s32 node_id);
+ void GenerateDepopPrepareCommand(VoiceState& dsp_state, std::size_t mix_buffer_count,
+ std::size_t mix_buffer_offset);
+ void GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_count,
+ std::size_t mix_buffer_offset, s32 sample_rate);
+ void GenerateEffectCommand(ServerMixInfo& mix_info);
+ void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
+ void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
+ void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
+ ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index);
+
+ s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data,
+ u32 sample_count, u32 write_offset, u32 write_count);
+ s32 ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples, s32* out_data,
+ u32 sample_count, u32 read_offset, u32 read_count);
+
+ // DSP Code
+ s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_count,
+ s32 channel, std::size_t mix_offset);
+ s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_count,
+ s32 channel, std::size_t mix_offset);
+ void DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* output, VoiceState& dsp_state,
+ s32 channel, s32 target_sample_rate, s32 sample_count, s32 node_id);
+
+ AudioCommon::AudioRendererParameter& worker_params;
+ VoiceContext& voice_context;
+ MixContext& mix_context;
+ SplitterContext& splitter_context;
+ EffectContext& effect_context;
+ Core::Memory::Memory& memory;
+ std::vector<s32> mix_buffer{};
+ std::vector<s32> sample_buffer{};
+ std::vector<s32> depop_buffer{};
+ bool dumping_frame{false};
+};
+} // namespace AudioCore
diff --git a/src/audio_core/common.h b/src/audio_core/common.h
index 7bb145c53..7b4a1e9e8 100644
--- a/src/audio_core/common.h
+++ b/src/audio_core/common.h
@@ -3,18 +3,36 @@
// Refer to the license.txt file included.
#pragma once
+
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/result.h"
-namespace AudioCore {
+namespace AudioCommon {
namespace Audren {
constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
-}
+constexpr ResultCode ERR_SPLITTER_SORT_FAILED{ErrorModule::Audio, 43};
+} // namespace Audren
constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8');
constexpr std::size_t MAX_MIX_BUFFERS = 24;
+constexpr std::size_t MAX_BIQUAD_FILTERS = 2;
+constexpr std::size_t MAX_CHANNEL_COUNT = 6;
+constexpr std::size_t MAX_WAVE_BUFFERS = 4;
+constexpr std::size_t MAX_SAMPLE_HISTORY = 4;
+constexpr u32 STREAM_SAMPLE_RATE = 48000;
+constexpr u32 STREAM_NUM_CHANNELS = 6;
+constexpr s32 NO_SPLITTER = -1;
+constexpr s32 NO_MIX = 0x7fffffff;
+constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min();
+constexpr s32 FINAL_MIX = 0;
+constexpr s32 NO_EFFECT_ORDER = -1;
+constexpr std::size_t TEMP_MIX_BASE_SIZE = 0x3f00; // TODO(ogniK): Work out this constant
+// Any size checks seem to take the sample history into account
+// and our const ends up being 0x3f04, the 4 bytes are most
+// likely the sample history
+constexpr std::size_t TOTAL_TEMP_MIX_SIZE = TEMP_MIX_BASE_SIZE + AudioCommon::MAX_SAMPLE_HISTORY;
static constexpr u32 VersionFromRevision(u32_le rev) {
// "REV7" -> 7
@@ -45,4 +63,46 @@ static constexpr bool CanConsumeBuffer(std::size_t size, std::size_t offset, std
return true;
}
-} // namespace AudioCore
+struct UpdateDataSizes {
+ u32_le behavior{};
+ u32_le memory_pool{};
+ u32_le voice{};
+ u32_le voice_channel_resource{};
+ u32_le effect{};
+ u32_le mixer{};
+ u32_le sink{};
+ u32_le performance{};
+ u32_le splitter{};
+ u32_le render_info{};
+ INSERT_PADDING_WORDS(4);
+};
+static_assert(sizeof(UpdateDataSizes) == 0x38, "UpdateDataSizes is an invalid size");
+
+struct UpdateDataHeader {
+ u32_le revision{};
+ UpdateDataSizes size{};
+ u32_le total_size{};
+};
+static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader is an invalid size");
+
+struct AudioRendererParameter {
+ u32_le sample_rate;
+ u32_le sample_count;
+ u32_le mix_buffer_count;
+ u32_le submix_count;
+ u32_le voice_count;
+ u32_le sink_count;
+ u32_le effect_count;
+ u32_le performance_frame_count;
+ u8 is_voice_drop_enabled;
+ u8 unknown_21;
+ u8 unknown_22;
+ u8 execution_mode;
+ u32_le splitter_count;
+ u32_le num_splitter_send_channels;
+ u32_le unknown_30;
+ u32_le revision;
+};
+static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size");
+
+} // namespace AudioCommon
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index c27df946c..6eaa60815 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -23,14 +23,24 @@ class CubebSinkStream final : public SinkStream {
public:
CubebSinkStream(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
const std::string& name)
- : ctx{ctx}, num_channels{std::min(num_channels_, 2u)}, time_stretch{sample_rate,
+ : ctx{ctx}, num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate,
num_channels} {
cubeb_stream_params params{};
params.rate = sample_rate;
params.channels = num_channels;
params.format = CUBEB_SAMPLE_S16NE;
- params.layout = num_channels == 1 ? CUBEB_LAYOUT_MONO : CUBEB_LAYOUT_STEREO;
+ switch (num_channels) {
+ case 1:
+ params.layout = CUBEB_LAYOUT_MONO;
+ break;
+ case 2:
+ params.layout = CUBEB_LAYOUT_STEREO;
+ break;
+ case 6:
+ params.layout = CUBEB_LAYOUT_3F2_LFE;
+ break;
+ }
u32 minimum_latency{};
if (cubeb_get_min_latency(ctx, &params, &minimum_latency) != CUBEB_OK) {
@@ -83,8 +93,10 @@ public:
constexpr s32 clev{707}; // center mixing level coefficient
constexpr s32 slev{707}; // surround mixing level coefficient
- buf.push_back(left + (clev * center / 1000) + (slev * surround_left / 1000));
- buf.push_back(right + (clev * center / 1000) + (slev * surround_right / 1000));
+ buf.push_back(static_cast<s16>(left + (clev * center / 1000) +
+ (slev * surround_left / 1000)));
+ buf.push_back(static_cast<s16>(right + (clev * center / 1000) +
+ (slev * surround_right / 1000)));
}
queue.Push(buf);
return;
@@ -182,8 +194,8 @@ SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels,
long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
void* output_buffer, long num_frames) {
- CubebSinkStream* impl = static_cast<CubebSinkStream*>(user_data);
- u8* buffer = reinterpret_cast<u8*>(output_buffer);
+ auto* impl = static_cast<CubebSinkStream*>(user_data);
+ auto* buffer = static_cast<u8*>(output_buffer);
if (!impl) {
return {};
@@ -193,6 +205,7 @@ long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const
const std::size_t samples_to_write = num_channels * num_frames;
std::size_t samples_written;
+ /*
if (Settings::values.enable_audio_stretching.GetValue()) {
const std::vector<s16> in{impl->queue.Pop()};
const std::size_t num_in{in.size() / num_channels};
@@ -207,7 +220,8 @@ long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const
}
} else {
samples_written = impl->queue.Pop(buffer, samples_to_write);
- }
+ }*/
+ samples_written = impl->queue.Pop(buffer, samples_to_write);
if (samples_written >= num_channels) {
std::memcpy(&impl->last_frame[0], buffer + (samples_written - num_channels) * sizeof(s16),
diff --git a/src/audio_core/effect_context.cpp b/src/audio_core/effect_context.cpp
new file mode 100644
index 000000000..4d9cdf524
--- /dev/null
+++ b/src/audio_core/effect_context.cpp
@@ -0,0 +1,299 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include "audio_core/effect_context.h"
+
+namespace AudioCore {
+namespace {
+bool ValidChannelCountForEffect(s32 channel_count) {
+ return channel_count == 1 || channel_count == 2 || channel_count == 4 || channel_count == 6;
+}
+} // namespace
+
+EffectContext::EffectContext(std::size_t effect_count) : effect_count(effect_count) {
+ effects.reserve(effect_count);
+ std::generate_n(std::back_inserter(effects), effect_count,
+ [] { return std::make_unique<EffectStubbed>(); });
+}
+EffectContext::~EffectContext() = default;
+
+std::size_t EffectContext::GetCount() const {
+ return effect_count;
+}
+
+EffectBase* EffectContext::GetInfo(std::size_t i) {
+ return effects.at(i).get();
+}
+
+EffectBase* EffectContext::RetargetEffect(std::size_t i, EffectType effect) {
+ switch (effect) {
+ case EffectType::Invalid:
+ effects[i] = std::make_unique<EffectStubbed>();
+ break;
+ case EffectType::BufferMixer:
+ effects[i] = std::make_unique<EffectBufferMixer>();
+ break;
+ case EffectType::Aux:
+ effects[i] = std::make_unique<EffectAuxInfo>();
+ break;
+ case EffectType::Delay:
+ effects[i] = std::make_unique<EffectDelay>();
+ break;
+ case EffectType::Reverb:
+ effects[i] = std::make_unique<EffectReverb>();
+ break;
+ case EffectType::I3dl2Reverb:
+ effects[i] = std::make_unique<EffectI3dl2Reverb>();
+ break;
+ case EffectType::BiquadFilter:
+ effects[i] = std::make_unique<EffectBiquadFilter>();
+ break;
+ default:
+ UNREACHABLE_MSG("Unimplemented effect {}", effect);
+ effects[i] = std::make_unique<EffectStubbed>();
+ }
+ return GetInfo(i);
+}
+
+const EffectBase* EffectContext::GetInfo(std::size_t i) const {
+ return effects.at(i).get();
+}
+
+EffectStubbed::EffectStubbed() : EffectBase::EffectBase(EffectType::Invalid) {}
+EffectStubbed::~EffectStubbed() = default;
+
+void EffectStubbed::Update(EffectInfo::InParams& in_params) {}
+void EffectStubbed::UpdateForCommandGeneration() {}
+
+EffectBase::EffectBase(EffectType effect_type) : effect_type(effect_type) {}
+EffectBase::~EffectBase() = default;
+
+UsageState EffectBase::GetUsage() const {
+ return usage;
+}
+
+EffectType EffectBase::GetType() const {
+ return effect_type;
+}
+
+bool EffectBase::IsEnabled() const {
+ return enabled;
+}
+
+s32 EffectBase::GetMixID() const {
+ return mix_id;
+}
+
+s32 EffectBase::GetProcessingOrder() const {
+ return processing_order;
+}
+
+EffectI3dl2Reverb::EffectI3dl2Reverb() : EffectGeneric::EffectGeneric(EffectType::I3dl2Reverb) {}
+EffectI3dl2Reverb::~EffectI3dl2Reverb() = default;
+
+void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) {
+ auto& internal_params = GetParams();
+ const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data());
+ if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
+ UNREACHABLE_MSG("Invalid reverb max channel count {}", reverb_params->max_channels);
+ return;
+ }
+
+ const auto last_status = internal_params.status;
+ mix_id = in_params.mix_id;
+ processing_order = in_params.processing_order;
+ internal_params = *reverb_params;
+ if (!ValidChannelCountForEffect(reverb_params->channel_count)) {
+ internal_params.channel_count = internal_params.max_channels;
+ }
+ enabled = in_params.is_enabled;
+ if (last_status != ParameterStatus::Updated) {
+ internal_params.status = last_status;
+ }
+
+ if (in_params.is_new || skipped) {
+ usage = UsageState::Initialized;
+ internal_params.status = ParameterStatus::Initialized;
+ skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
+ }
+}
+
+void EffectI3dl2Reverb::UpdateForCommandGeneration() {
+ if (enabled) {
+ usage = UsageState::Running;
+ } else {
+ usage = UsageState::Stopped;
+ }
+ GetParams().status = ParameterStatus::Updated;
+}
+
+EffectBiquadFilter::EffectBiquadFilter() : EffectGeneric::EffectGeneric(EffectType::BiquadFilter) {}
+EffectBiquadFilter::~EffectBiquadFilter() = default;
+
+void EffectBiquadFilter::Update(EffectInfo::InParams& in_params) {
+ auto& internal_params = GetParams();
+ const auto* biquad_params = reinterpret_cast<BiquadFilterParams*>(in_params.raw.data());
+ mix_id = in_params.mix_id;
+ processing_order = in_params.processing_order;
+ internal_params = *biquad_params;
+ enabled = in_params.is_enabled;
+}
+
+void EffectBiquadFilter::UpdateForCommandGeneration() {
+ if (enabled) {
+ usage = UsageState::Running;
+ } else {
+ usage = UsageState::Stopped;
+ }
+ GetParams().status = ParameterStatus::Updated;
+}
+
+EffectAuxInfo::EffectAuxInfo() : EffectGeneric::EffectGeneric(EffectType::Aux) {}
+EffectAuxInfo::~EffectAuxInfo() = default;
+
+void EffectAuxInfo::Update(EffectInfo::InParams& in_params) {
+ const auto* aux_params = reinterpret_cast<AuxInfo*>(in_params.raw.data());
+ mix_id = in_params.mix_id;
+ processing_order = in_params.processing_order;
+ GetParams() = *aux_params;
+ enabled = in_params.is_enabled;
+
+ if (in_params.is_new || skipped) {
+ skipped = aux_params->send_buffer_info == 0 || aux_params->return_buffer_info == 0;
+ if (skipped) {
+ return;
+ }
+
+ // There's two AuxInfos which are an identical size, the first one is managed by the cpu,
+ // the second is managed by the dsp. All we care about is managing the DSP one
+ send_info = aux_params->send_buffer_info + sizeof(AuxInfoDSP);
+ send_buffer = aux_params->send_buffer_info + (sizeof(AuxInfoDSP) * 2);
+
+ recv_info = aux_params->return_buffer_info + sizeof(AuxInfoDSP);
+ recv_buffer = aux_params->return_buffer_info + (sizeof(AuxInfoDSP) * 2);
+ }
+}
+
+void EffectAuxInfo::UpdateForCommandGeneration() {
+ if (enabled) {
+ usage = UsageState::Running;
+ } else {
+ usage = UsageState::Stopped;
+ }
+}
+
+VAddr EffectAuxInfo::GetSendInfo() const {
+ return send_info;
+}
+
+VAddr EffectAuxInfo::GetSendBuffer() const {
+ return send_buffer;
+}
+
+VAddr EffectAuxInfo::GetRecvInfo() const {
+ return recv_info;
+}
+
+VAddr EffectAuxInfo::GetRecvBuffer() const {
+ return recv_buffer;
+}
+
+EffectDelay::EffectDelay() : EffectGeneric::EffectGeneric(EffectType::Delay) {}
+EffectDelay::~EffectDelay() = default;
+
+void EffectDelay::Update(EffectInfo::InParams& in_params) {
+ const auto* delay_params = reinterpret_cast<DelayParams*>(in_params.raw.data());
+ auto& internal_params = GetParams();
+ if (!ValidChannelCountForEffect(delay_params->max_channels)) {
+ return;
+ }
+
+ const auto last_status = internal_params.status;
+ mix_id = in_params.mix_id;
+ processing_order = in_params.processing_order;
+ internal_params = *delay_params;
+ if (!ValidChannelCountForEffect(delay_params->channels)) {
+ internal_params.channels = internal_params.max_channels;
+ }
+ enabled = in_params.is_enabled;
+
+ if (last_status != ParameterStatus::Updated) {
+ internal_params.status = last_status;
+ }
+
+ if (in_params.is_new || skipped) {
+ usage = UsageState::Initialized;
+ internal_params.status = ParameterStatus::Initialized;
+ skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
+ }
+}
+
+void EffectDelay::UpdateForCommandGeneration() {
+ if (enabled) {
+ usage = UsageState::Running;
+ } else {
+ usage = UsageState::Stopped;
+ }
+ GetParams().status = ParameterStatus::Updated;
+}
+
+EffectBufferMixer::EffectBufferMixer() : EffectGeneric::EffectGeneric(EffectType::BufferMixer) {}
+EffectBufferMixer::~EffectBufferMixer() = default;
+
+void EffectBufferMixer::Update(EffectInfo::InParams& in_params) {
+ mix_id = in_params.mix_id;
+ processing_order = in_params.processing_order;
+ GetParams() = *reinterpret_cast<BufferMixerParams*>(in_params.raw.data());
+ enabled = in_params.is_enabled;
+}
+
+void EffectBufferMixer::UpdateForCommandGeneration() {
+ if (enabled) {
+ usage = UsageState::Running;
+ } else {
+ usage = UsageState::Stopped;
+ }
+}
+
+EffectReverb::EffectReverb() : EffectGeneric::EffectGeneric(EffectType::Reverb) {}
+EffectReverb::~EffectReverb() = default;
+
+void EffectReverb::Update(EffectInfo::InParams& in_params) {
+ const auto* reverb_params = reinterpret_cast<ReverbParams*>(in_params.raw.data());
+ auto& internal_params = GetParams();
+ if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
+ return;
+ }
+
+ const auto last_status = internal_params.status;
+ mix_id = in_params.mix_id;
+ processing_order = in_params.processing_order;
+ internal_params = *reverb_params;
+ if (!ValidChannelCountForEffect(reverb_params->channels)) {
+ internal_params.channels = internal_params.max_channels;
+ }
+ enabled = in_params.is_enabled;
+
+ if (last_status != ParameterStatus::Updated) {
+ internal_params.status = last_status;
+ }
+
+ if (in_params.is_new || skipped) {
+ usage = UsageState::Initialized;
+ internal_params.status = ParameterStatus::Initialized;
+ skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
+ }
+}
+
+void EffectReverb::UpdateForCommandGeneration() {
+ if (enabled) {
+ usage = UsageState::Running;
+ } else {
+ usage = UsageState::Stopped;
+ }
+ GetParams().status = ParameterStatus::Updated;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/effect_context.h b/src/audio_core/effect_context.h
new file mode 100644
index 000000000..2c4ce53ef
--- /dev/null
+++ b/src/audio_core/effect_context.h
@@ -0,0 +1,321 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <vector>
+#include "audio_core/common.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+
+namespace AudioCore {
+enum class EffectType : u8 {
+ Invalid = 0,
+ BufferMixer = 1,
+ Aux = 2,
+ Delay = 3,
+ Reverb = 4,
+ I3dl2Reverb = 5,
+ BiquadFilter = 6,
+};
+
+enum class UsageStatus : u8 {
+ Invalid = 0,
+ New = 1,
+ Initialized = 2,
+ Used = 3,
+ Removed = 4,
+};
+
+enum class UsageState {
+ Invalid = 0,
+ Initialized = 1,
+ Running = 2,
+ Stopped = 3,
+};
+
+enum class ParameterStatus : u8 {
+ Initialized = 0,
+ Updating = 1,
+ Updated = 2,
+};
+
+struct BufferMixerParams {
+ std::array<s8, AudioCommon::MAX_MIX_BUFFERS> input{};
+ std::array<s8, AudioCommon::MAX_MIX_BUFFERS> output{};
+ std::array<float_le, AudioCommon::MAX_MIX_BUFFERS> volume{};
+ s32_le count{};
+};
+static_assert(sizeof(BufferMixerParams) == 0x94, "BufferMixerParams is an invalid size");
+
+struct AuxInfoDSP {
+ u32_le read_offset{};
+ u32_le write_offset{};
+ u32_le remaining{};
+ INSERT_PADDING_WORDS(13);
+};
+static_assert(sizeof(AuxInfoDSP) == 0x40, "AuxInfoDSP is an invalid size");
+
+struct AuxInfo {
+ std::array<s8, AudioCommon::MAX_MIX_BUFFERS> input_mix_buffers{};
+ std::array<s8, AudioCommon::MAX_MIX_BUFFERS> output_mix_buffers{};
+ u32_le count{};
+ s32_le sample_rate{};
+ s32_le sample_count{};
+ s32_le mix_buffer_count{};
+ u64_le send_buffer_info{};
+ u64_le send_buffer_base{};
+
+ u64_le return_buffer_info{};
+ u64_le return_buffer_base{};
+};
+static_assert(sizeof(AuxInfo) == 0x60, "AuxInfo is an invalid size");
+
+struct I3dl2ReverbParams {
+ std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
+ std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
+ u16_le max_channels{};
+ u16_le channel_count{};
+ INSERT_PADDING_BYTES(1);
+ u32_le sample_rate{};
+ f32 room_hf{};
+ f32 hf_reference{};
+ f32 decay_time{};
+ f32 hf_decay_ratio{};
+ f32 room{};
+ f32 reflection{};
+ f32 reverb{};
+ f32 diffusion{};
+ f32 reflection_delay{};
+ f32 reverb_delay{};
+ f32 density{};
+ f32 dry_gain{};
+ ParameterStatus status{};
+ INSERT_PADDING_BYTES(3);
+};
+static_assert(sizeof(I3dl2ReverbParams) == 0x4c, "I3dl2ReverbParams is an invalid size");
+
+struct BiquadFilterParams {
+ std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
+ std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
+ std::array<s16_le, 3> numerator;
+ std::array<s16_le, 2> denominator;
+ s8 channel_count{};
+ ParameterStatus status{};
+};
+static_assert(sizeof(BiquadFilterParams) == 0x18, "BiquadFilterParams is an invalid size");
+
+struct DelayParams {
+ std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
+ std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
+ u16_le max_channels{};
+ u16_le channels{};
+ s32_le max_delay{};
+ s32_le delay{};
+ s32_le sample_rate{};
+ s32_le gain{};
+ s32_le feedback_gain{};
+ s32_le out_gain{};
+ s32_le dry_gain{};
+ s32_le channel_spread{};
+ s32_le low_pass{};
+ ParameterStatus status{};
+ INSERT_PADDING_BYTES(3);
+};
+static_assert(sizeof(DelayParams) == 0x38, "DelayParams is an invalid size");
+
+struct ReverbParams {
+ std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
+ std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
+ u16_le max_channels{};
+ u16_le channels{};
+ s32_le sample_rate{};
+ s32_le mode0{};
+ s32_le mode0_gain{};
+ s32_le pre_delay{};
+ s32_le mode1{};
+ s32_le mode1_gain{};
+ s32_le decay{};
+ s32_le hf_decay_ratio{};
+ s32_le coloration{};
+ s32_le reverb_gain{};
+ s32_le out_gain{};
+ s32_le dry_gain{};
+ ParameterStatus status{};
+ INSERT_PADDING_BYTES(3);
+};
+static_assert(sizeof(ReverbParams) == 0x44, "ReverbParams is an invalid size");
+
+class EffectInfo {
+public:
+ struct InParams {
+ EffectType type{};
+ u8 is_new{};
+ u8 is_enabled{};
+ INSERT_PADDING_BYTES(1);
+ s32_le mix_id{};
+ u64_le buffer_address{};
+ u64_le buffer_size{};
+ s32_le processing_order{};
+ INSERT_PADDING_BYTES(4);
+ union {
+ std::array<u8, 0xa0> raw;
+ };
+ };
+ static_assert(sizeof(InParams) == 0xc0, "InParams is an invalid size");
+
+ struct OutParams {
+ UsageStatus status{};
+ INSERT_PADDING_BYTES(15);
+ };
+ static_assert(sizeof(OutParams) == 0x10, "OutParams is an invalid size");
+};
+
+struct AuxAddress {
+ VAddr send_dsp_info{};
+ VAddr send_buffer_base{};
+ VAddr return_dsp_info{};
+ VAddr return_buffer_base{};
+};
+
+class EffectBase {
+public:
+ explicit EffectBase(EffectType effect_type);
+ virtual ~EffectBase();
+
+ virtual void Update(EffectInfo::InParams& in_params) = 0;
+ virtual void UpdateForCommandGeneration() = 0;
+ UsageState GetUsage() const;
+ EffectType GetType() const;
+ bool IsEnabled() const;
+ s32 GetMixID() const;
+ s32 GetProcessingOrder() const;
+
+protected:
+ UsageState usage{UsageState::Invalid};
+ EffectType effect_type{};
+ s32 mix_id{};
+ s32 processing_order{};
+ bool enabled = false;
+};
+
+template <typename T>
+class EffectGeneric : public EffectBase {
+public:
+ explicit EffectGeneric(EffectType effect_type) : EffectBase(effect_type) {}
+
+ T& GetParams() {
+ return internal_params;
+ }
+
+ const I3dl2ReverbParams& GetParams() const {
+ return internal_params;
+ }
+
+private:
+ T internal_params{};
+};
+
+class EffectStubbed : public EffectBase {
+public:
+ explicit EffectStubbed();
+ ~EffectStubbed() override;
+
+ void Update(EffectInfo::InParams& in_params) override;
+ void UpdateForCommandGeneration() override;
+};
+
+class EffectI3dl2Reverb : public EffectGeneric<I3dl2ReverbParams> {
+public:
+ explicit EffectI3dl2Reverb();
+ ~EffectI3dl2Reverb() override;
+
+ void Update(EffectInfo::InParams& in_params) override;
+ void UpdateForCommandGeneration() override;
+
+private:
+ bool skipped = false;
+};
+
+class EffectBiquadFilter : public EffectGeneric<BiquadFilterParams> {
+public:
+ explicit EffectBiquadFilter();
+ ~EffectBiquadFilter() override;
+
+ void Update(EffectInfo::InParams& in_params) override;
+ void UpdateForCommandGeneration() override;
+};
+
+class EffectAuxInfo : public EffectGeneric<AuxInfo> {
+public:
+ explicit EffectAuxInfo();
+ ~EffectAuxInfo() override;
+
+ void Update(EffectInfo::InParams& in_params) override;
+ void UpdateForCommandGeneration() override;
+ VAddr GetSendInfo() const;
+ VAddr GetSendBuffer() const;
+ VAddr GetRecvInfo() const;
+ VAddr GetRecvBuffer() const;
+
+private:
+ VAddr send_info{};
+ VAddr send_buffer{};
+ VAddr recv_info{};
+ VAddr recv_buffer{};
+ bool skipped = false;
+ AuxAddress addresses{};
+};
+
+class EffectDelay : public EffectGeneric<DelayParams> {
+public:
+ explicit EffectDelay();
+ ~EffectDelay() override;
+
+ void Update(EffectInfo::InParams& in_params) override;
+ void UpdateForCommandGeneration() override;
+
+private:
+ bool skipped = false;
+};
+
+class EffectBufferMixer : public EffectGeneric<BufferMixerParams> {
+public:
+ explicit EffectBufferMixer();
+ ~EffectBufferMixer() override;
+
+ void Update(EffectInfo::InParams& in_params) override;
+ void UpdateForCommandGeneration() override;
+};
+
+class EffectReverb : public EffectGeneric<ReverbParams> {
+public:
+ explicit EffectReverb();
+ ~EffectReverb() override;
+
+ void Update(EffectInfo::InParams& in_params) override;
+ void UpdateForCommandGeneration() override;
+
+private:
+ bool skipped = false;
+};
+
+class EffectContext {
+public:
+ explicit EffectContext(std::size_t effect_count);
+ ~EffectContext();
+
+ std::size_t GetCount() const;
+ EffectBase* GetInfo(std::size_t i);
+ EffectBase* RetargetEffect(std::size_t i, EffectType effect);
+ const EffectBase* GetInfo(std::size_t i) const;
+
+private:
+ std::size_t effect_count{};
+ std::vector<std::unique_ptr<EffectBase>> effects;
+};
+} // namespace AudioCore
diff --git a/src/audio_core/info_updater.cpp b/src/audio_core/info_updater.cpp
new file mode 100644
index 000000000..2940e53a9
--- /dev/null
+++ b/src/audio_core/info_updater.cpp
@@ -0,0 +1,516 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/behavior_info.h"
+#include "audio_core/effect_context.h"
+#include "audio_core/info_updater.h"
+#include "audio_core/memory_pool.h"
+#include "audio_core/mix_context.h"
+#include "audio_core/sink_context.h"
+#include "audio_core/splitter_context.h"
+#include "audio_core/voice_context.h"
+#include "common/logging/log.h"
+
+namespace AudioCore {
+
+InfoUpdater::InfoUpdater(const std::vector<u8>& in_params, std::vector<u8>& out_params,
+ BehaviorInfo& behavior_info)
+ : in_params(in_params), out_params(out_params), behavior_info(behavior_info) {
+ ASSERT(
+ AudioCommon::CanConsumeBuffer(in_params.size(), 0, sizeof(AudioCommon::UpdateDataHeader)));
+ std::memcpy(&input_header, in_params.data(), sizeof(AudioCommon::UpdateDataHeader));
+ output_header.total_size = sizeof(AudioCommon::UpdateDataHeader);
+}
+
+InfoUpdater::~InfoUpdater() = default;
+
+bool InfoUpdater::UpdateBehaviorInfo(BehaviorInfo& in_behavior_info) {
+ if (input_header.size.behavior != sizeof(BehaviorInfo::InParams)) {
+ LOG_ERROR(Audio, "Behavior info is an invalid size, expecting 0x{:X} but got 0x{:X}",
+ sizeof(BehaviorInfo::InParams), input_header.size.behavior);
+ return false;
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset,
+ sizeof(BehaviorInfo::InParams))) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+
+ BehaviorInfo::InParams behavior_in{};
+ std::memcpy(&behavior_in, in_params.data() + input_offset, sizeof(BehaviorInfo::InParams));
+ input_offset += sizeof(BehaviorInfo::InParams);
+
+ // Make sure it's an audio revision we can actually support
+ if (!AudioCommon::IsValidRevision(behavior_in.revision)) {
+ LOG_ERROR(Audio, "Invalid input revision, revision=0x{:08X}", behavior_in.revision);
+ return false;
+ }
+
+ // Make sure that our behavior info revision matches the input
+ if (in_behavior_info.GetUserRevision() != behavior_in.revision) {
+ LOG_ERROR(Audio,
+ "User revision differs from input revision, expecting 0x{:08X} but got 0x{:08X}",
+ in_behavior_info.GetUserRevision(), behavior_in.revision);
+ return false;
+ }
+
+ // Update behavior info flags
+ in_behavior_info.ClearError();
+ in_behavior_info.UpdateFlags(behavior_in.flags);
+
+ return true;
+}
+
+bool InfoUpdater::UpdateMemoryPools(std::vector<ServerMemoryPoolInfo>& memory_pool_info) {
+ const auto memory_pool_count = memory_pool_info.size();
+ const auto total_memory_pool_in = sizeof(ServerMemoryPoolInfo::InParams) * memory_pool_count;
+ const auto total_memory_pool_out = sizeof(ServerMemoryPoolInfo::OutParams) * memory_pool_count;
+
+ if (input_header.size.memory_pool != total_memory_pool_in) {
+ LOG_ERROR(Audio, "Memory pools are an invalid size, expecting 0x{:X} but got 0x{:X}",
+ total_memory_pool_in, input_header.size.memory_pool);
+ return false;
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, total_memory_pool_in)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+
+ std::vector<ServerMemoryPoolInfo::InParams> mempool_in(memory_pool_count);
+ std::vector<ServerMemoryPoolInfo::OutParams> mempool_out(memory_pool_count);
+
+ std::memcpy(mempool_in.data(), in_params.data() + input_offset, total_memory_pool_in);
+ input_offset += total_memory_pool_in;
+
+ // Update our memory pools
+ for (std::size_t i = 0; i < memory_pool_count; i++) {
+ if (!memory_pool_info[i].Update(mempool_in[i], mempool_out[i])) {
+ LOG_ERROR(Audio, "Failed to update memory pool {}!", i);
+ return false;
+ }
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset,
+ sizeof(BehaviorInfo::InParams))) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+
+ std::memcpy(out_params.data() + output_offset, mempool_out.data(), total_memory_pool_out);
+ output_offset += total_memory_pool_out;
+ output_header.size.memory_pool = static_cast<u32>(total_memory_pool_out);
+ return true;
+}
+
+bool InfoUpdater::UpdateVoiceChannelResources(VoiceContext& voice_context) {
+ const auto voice_count = voice_context.GetVoiceCount();
+ const auto voice_size = voice_count * sizeof(VoiceChannelResource::InParams);
+ std::vector<VoiceChannelResource::InParams> resources_in(voice_count);
+
+ if (input_header.size.voice_channel_resource != voice_size) {
+ LOG_ERROR(Audio, "VoiceChannelResource is an invalid size, expecting 0x{:X} but got 0x{:X}",
+ voice_size, input_header.size.voice_channel_resource);
+ return false;
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, voice_size)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+
+ std::memcpy(resources_in.data(), in_params.data() + input_offset, voice_size);
+ input_offset += voice_size;
+
+ // Update our channel resources
+ for (std::size_t i = 0; i < voice_count; i++) {
+ // Grab our channel resource
+ auto& resource = voice_context.GetChannelResource(i);
+ resource.Update(resources_in[i]);
+ }
+
+ return true;
+}
+
+bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
+ std::vector<ServerMemoryPoolInfo>& memory_pool_info,
+ VAddr audio_codec_dsp_addr) {
+ const auto voice_count = voice_context.GetVoiceCount();
+ std::vector<VoiceInfo::InParams> voice_in(voice_count);
+ std::vector<VoiceInfo::OutParams> voice_out(voice_count);
+
+ const auto voice_in_size = voice_count * sizeof(VoiceInfo::InParams);
+ const auto voice_out_size = voice_count * sizeof(VoiceInfo::OutParams);
+
+ if (input_header.size.voice != voice_in_size) {
+ LOG_ERROR(Audio, "Voices are an invalid size, expecting 0x{:X} but got 0x{:X}",
+ voice_in_size, input_header.size.voice);
+ return false;
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, voice_in_size)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+
+ std::memcpy(voice_in.data(), in_params.data() + input_offset, voice_in_size);
+ input_offset += voice_in_size;
+
+ // Set all voices to not be in use
+ for (std::size_t i = 0; i < voice_count; i++) {
+ voice_context.GetInfo(i).GetInParams().in_use = false;
+ }
+
+ // Update our voices
+ for (std::size_t i = 0; i < voice_count; i++) {
+ auto& in_params = voice_in[i];
+ const auto channel_count = static_cast<std::size_t>(in_params.channel_count);
+ // Skip if it's not currently in use
+ if (!in_params.is_in_use) {
+ continue;
+ }
+ // Voice states for each channel
+ std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT> voice_states{};
+ ASSERT(static_cast<std::size_t>(in_params.id) < voice_count);
+
+ // Grab our current voice info
+ auto& voice_info = voice_context.GetInfo(static_cast<std::size_t>(in_params.id));
+
+ ASSERT(channel_count <= AudioCommon::MAX_CHANNEL_COUNT);
+
+ // Get all our channel voice states
+ for (std::size_t channel = 0; channel < channel_count; channel++) {
+ voice_states[channel] =
+ &voice_context.GetState(in_params.voice_channel_resource_ids[channel]);
+ }
+
+ if (in_params.is_new) {
+ // Default our values for our voice
+ voice_info.Initialize();
+ if (channel_count == 0 || channel_count > AudioCommon::MAX_CHANNEL_COUNT) {
+ continue;
+ }
+
+ // Zero out our voice states
+ for (std::size_t channel = 0; channel < channel_count; channel++) {
+ std::memset(voice_states[channel], 0, sizeof(VoiceState));
+ }
+ }
+
+ // Update our voice
+ voice_info.UpdateParameters(in_params, behavior_info);
+ // TODO(ogniK): Handle mapping errors with behavior info based on in params response
+
+ // Update our wave buffers
+ voice_info.UpdateWaveBuffers(in_params, voice_states, behavior_info);
+ voice_info.WriteOutStatus(voice_out[i], in_params, voice_states);
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, voice_out_size)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+ std::memcpy(out_params.data() + output_offset, voice_out.data(), voice_out_size);
+ output_offset += voice_out_size;
+ output_header.size.voice = static_cast<u32>(voice_out_size);
+ return true;
+}
+
+bool InfoUpdater::UpdateEffects(EffectContext& effect_context, bool is_active) {
+ const auto effect_count = effect_context.GetCount();
+ std::vector<EffectInfo::InParams> effect_in(effect_count);
+ std::vector<EffectInfo::OutParams> effect_out(effect_count);
+
+ const auto total_effect_in = effect_count * sizeof(EffectInfo::InParams);
+ const auto total_effect_out = effect_count * sizeof(EffectInfo::OutParams);
+
+ if (input_header.size.effect != total_effect_in) {
+ LOG_ERROR(Audio, "Effects are an invalid size, expecting 0x{:X} but got 0x{:X}",
+ total_effect_in, input_header.size.effect);
+ return false;
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, total_effect_in)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+
+ std::memcpy(effect_in.data(), in_params.data() + input_offset, total_effect_in);
+ input_offset += total_effect_in;
+
+ // Update effects
+ for (std::size_t i = 0; i < effect_count; i++) {
+ auto* info = effect_context.GetInfo(i);
+ if (effect_in[i].type != info->GetType()) {
+ info = effect_context.RetargetEffect(i, effect_in[i].type);
+ }
+
+ info->Update(effect_in[i]);
+
+ if ((!is_active && info->GetUsage() != UsageState::Initialized) ||
+ info->GetUsage() == UsageState::Stopped) {
+ effect_out[i].status = UsageStatus::Removed;
+ } else {
+ effect_out[i].status = UsageStatus::Used;
+ }
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, total_effect_out)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+
+ std::memcpy(out_params.data() + output_offset, effect_out.data(), total_effect_out);
+ output_offset += total_effect_out;
+ output_header.size.effect = static_cast<u32>(total_effect_out);
+
+ return true;
+}
+
+bool InfoUpdater::UpdateSplitterInfo(SplitterContext& splitter_context) {
+ std::size_t start_offset = input_offset;
+ std::size_t bytes_read{};
+ // Update splitter context
+ if (!splitter_context.Update(in_params, input_offset, bytes_read)) {
+ LOG_ERROR(Audio, "Failed to update splitter context!");
+ return false;
+ }
+
+ const auto consumed = input_offset - start_offset;
+
+ if (input_header.size.splitter != consumed) {
+ LOG_ERROR(Audio, "Splitters is an invalid size, expecting 0x{:X} but got 0x{:X}",
+ bytes_read, input_header.size.splitter);
+ return false;
+ }
+
+ return true;
+}
+
+ResultCode InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
+ SplitterContext& splitter_context,
+ EffectContext& effect_context) {
+ std::vector<MixInfo::InParams> mix_in_params;
+
+ if (!behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) {
+ // If we're not dirty, get ALL mix in parameters
+ const auto context_mix_count = mix_context.GetCount();
+ const auto total_mix_in = context_mix_count * sizeof(MixInfo::InParams);
+ if (input_header.size.mixer != total_mix_in) {
+ LOG_ERROR(Audio, "Mixer is an invalid size, expecting 0x{:X} but got 0x{:X}",
+ total_mix_in, input_header.size.mixer);
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, total_mix_in)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+
+ mix_in_params.resize(context_mix_count);
+ std::memcpy(mix_in_params.data(), in_params.data() + input_offset, total_mix_in);
+
+ input_offset += total_mix_in;
+ } else {
+ // Only update the "dirty" mixes
+ MixInfo::DirtyHeader dirty_header{};
+ if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset,
+ sizeof(MixInfo::DirtyHeader))) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+
+ std::memcpy(&dirty_header, in_params.data() + input_offset, sizeof(MixInfo::DirtyHeader));
+ input_offset += sizeof(MixInfo::DirtyHeader);
+
+ const auto total_mix_in =
+ dirty_header.mixer_count * sizeof(MixInfo::InParams) + sizeof(MixInfo::DirtyHeader);
+
+ if (input_header.size.mixer != total_mix_in) {
+ LOG_ERROR(Audio, "Mixer is an invalid size, expecting 0x{:X} but got 0x{:X}",
+ total_mix_in, input_header.size.mixer);
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+
+ if (dirty_header.mixer_count != 0) {
+ mix_in_params.resize(dirty_header.mixer_count);
+ std::memcpy(mix_in_params.data(), in_params.data() + input_offset,
+ mix_in_params.size() * sizeof(MixInfo::InParams));
+ input_offset += mix_in_params.size() * sizeof(MixInfo::InParams);
+ }
+ }
+
+ // Get our total input count
+ const auto mix_count = mix_in_params.size();
+
+ if (!behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) {
+ // Only verify our buffer count if we're not dirty
+ std::size_t total_buffer_count{};
+ for (std::size_t i = 0; i < mix_count; i++) {
+ const auto& in = mix_in_params[i];
+ total_buffer_count += in.buffer_count;
+ if (static_cast<std::size_t>(in.dest_mix_id) > mix_count &&
+ in.dest_mix_id != AudioCommon::NO_MIX && in.mix_id != AudioCommon::FINAL_MIX) {
+ LOG_ERROR(
+ Audio,
+ "Invalid mix destination, mix_id={:X}, dest_mix_id={:X}, mix_buffer_count={:X}",
+ in.mix_id, in.dest_mix_id, mix_buffer_count);
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+ }
+
+ if (total_buffer_count > mix_buffer_count) {
+ LOG_ERROR(Audio,
+ "Too many mix buffers used! mix_buffer_count={:X}, requesting_buffers={:X}",
+ mix_buffer_count, total_buffer_count);
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+ }
+
+ if (mix_buffer_count == 0) {
+ LOG_ERROR(Audio, "No mix buffers!");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+
+ bool should_sort = false;
+ for (std::size_t i = 0; i < mix_count; i++) {
+ const auto& mix_in = mix_in_params[i];
+ std::size_t target_mix{};
+ if (behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) {
+ target_mix = mix_in.mix_id;
+ } else {
+ // Non dirty supported games just use i instead of the actual mix_id
+ target_mix = i;
+ }
+ auto& mix_info = mix_context.GetInfo(target_mix);
+ auto& mix_info_params = mix_info.GetInParams();
+ if (mix_info_params.in_use != mix_in.in_use) {
+ mix_info_params.in_use = mix_in.in_use;
+ mix_info.ResetEffectProcessingOrder();
+ should_sort = true;
+ }
+
+ if (mix_in.in_use) {
+ should_sort |= mix_info.Update(mix_context.GetEdgeMatrix(), mix_in, behavior_info,
+ splitter_context, effect_context);
+ }
+ }
+
+ if (should_sort && behavior_info.IsSplitterSupported()) {
+ // Sort our splitter data
+ if (!mix_context.TsortInfo(splitter_context)) {
+ return AudioCommon::Audren::ERR_SPLITTER_SORT_FAILED;
+ }
+ }
+
+ // TODO(ogniK): Sort when splitter is suppoorted
+
+ return RESULT_SUCCESS;
+}
+
+bool InfoUpdater::UpdateSinks(SinkContext& sink_context) {
+ const auto sink_count = sink_context.GetCount();
+ std::vector<SinkInfo::InParams> sink_in_params(sink_count);
+ const auto total_sink_in = sink_count * sizeof(SinkInfo::InParams);
+
+ if (input_header.size.sink != total_sink_in) {
+ LOG_ERROR(Audio, "Sinks are an invalid size, expecting 0x{:X} but got 0x{:X}",
+ total_sink_in, input_header.size.effect);
+ return false;
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, total_sink_in)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+
+ std::memcpy(sink_in_params.data(), in_params.data() + input_offset, total_sink_in);
+ input_offset += total_sink_in;
+
+ // TODO(ogniK): Properly update sinks
+ if (!sink_in_params.empty()) {
+ sink_context.UpdateMainSink(sink_in_params[0]);
+ }
+
+ output_header.size.sink = static_cast<u32>(0x20 * sink_count);
+ output_offset += 0x20 * sink_count;
+ return true;
+}
+
+bool InfoUpdater::UpdatePerformanceBuffer() {
+ output_header.size.performance = 0x10;
+ output_offset += 0x10;
+ return true;
+}
+
+bool InfoUpdater::UpdateErrorInfo(BehaviorInfo& in_behavior_info) {
+ const auto total_beahvior_info_out = sizeof(BehaviorInfo::OutParams);
+
+ if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, total_beahvior_info_out)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+
+ BehaviorInfo::OutParams behavior_info_out{};
+ behavior_info.CopyErrorInfo(behavior_info_out);
+
+ std::memcpy(out_params.data() + output_offset, &behavior_info_out, total_beahvior_info_out);
+ output_offset += total_beahvior_info_out;
+ output_header.size.behavior = total_beahvior_info_out;
+
+ return true;
+}
+
+struct RendererInfo {
+ u64_le elasped_frame_count{};
+ INSERT_PADDING_WORDS(2);
+};
+static_assert(sizeof(RendererInfo) == 0x10, "RendererInfo is an invalid size");
+
+bool InfoUpdater::UpdateRendererInfo(std::size_t elapsed_frame_count) {
+ const auto total_renderer_info_out = sizeof(RendererInfo);
+ if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, total_renderer_info_out)) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+ RendererInfo out{};
+ out.elasped_frame_count = elapsed_frame_count;
+ std::memcpy(out_params.data() + output_offset, &out, total_renderer_info_out);
+ output_offset += total_renderer_info_out;
+ output_header.size.render_info = total_renderer_info_out;
+
+ return true;
+}
+
+bool InfoUpdater::CheckConsumedSize() const {
+ if (output_offset != out_params.size()) {
+ LOG_ERROR(Audio, "Output is not consumed! Consumed {}, but requires {}. {} bytes remaining",
+ output_offset, out_params.size(), out_params.size() - output_offset);
+ return false;
+ }
+ /*if (input_offset != in_params.size()) {
+ LOG_ERROR(Audio, "Input is not consumed!");
+ return false;
+ }*/
+ return true;
+}
+
+bool InfoUpdater::WriteOutputHeader() {
+ if (!AudioCommon::CanConsumeBuffer(out_params.size(), 0,
+ sizeof(AudioCommon::UpdateDataHeader))) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+ output_header.revision = AudioCommon::CURRENT_PROCESS_REVISION;
+ const auto& sz = output_header.size;
+ output_header.total_size += sz.behavior + sz.memory_pool + sz.voice +
+ sz.voice_channel_resource + sz.effect + sz.mixer + sz.sink +
+ sz.performance + sz.splitter + sz.render_info;
+
+ std::memcpy(out_params.data(), &output_header, sizeof(AudioCommon::UpdateDataHeader));
+ return true;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/info_updater.h b/src/audio_core/info_updater.h
new file mode 100644
index 000000000..06f9d770f
--- /dev/null
+++ b/src/audio_core/info_updater.h
@@ -0,0 +1,58 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include "audio_core/common.h"
+#include "common/common_types.h"
+
+namespace AudioCore {
+
+class BehaviorInfo;
+class ServerMemoryPoolInfo;
+class VoiceContext;
+class EffectContext;
+class MixContext;
+class SinkContext;
+class SplitterContext;
+
+class InfoUpdater {
+public:
+ // TODO(ogniK): Pass process handle when we support it
+ InfoUpdater(const std::vector<u8>& in_params, std::vector<u8>& out_params,
+ BehaviorInfo& behavior_info);
+ ~InfoUpdater();
+
+ bool UpdateBehaviorInfo(BehaviorInfo& in_behavior_info);
+ bool UpdateMemoryPools(std::vector<ServerMemoryPoolInfo>& memory_pool_info);
+ bool UpdateVoiceChannelResources(VoiceContext& voice_context);
+ bool UpdateVoices(VoiceContext& voice_context,
+ std::vector<ServerMemoryPoolInfo>& memory_pool_info,
+ VAddr audio_codec_dsp_addr);
+ bool UpdateEffects(EffectContext& effect_context, bool is_active);
+ bool UpdateSplitterInfo(SplitterContext& splitter_context);
+ ResultCode UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
+ SplitterContext& splitter_context, EffectContext& effect_context);
+ bool UpdateSinks(SinkContext& sink_context);
+ bool UpdatePerformanceBuffer();
+ bool UpdateErrorInfo(BehaviorInfo& in_behavior_info);
+ bool UpdateRendererInfo(std::size_t elapsed_frame_count);
+ bool CheckConsumedSize() const;
+
+ bool WriteOutputHeader();
+
+private:
+ const std::vector<u8>& in_params;
+ std::vector<u8>& out_params;
+ BehaviorInfo& behavior_info;
+
+ AudioCommon::UpdateDataHeader input_header{};
+ AudioCommon::UpdateDataHeader output_header{};
+
+ std::size_t input_offset{sizeof(AudioCommon::UpdateDataHeader)};
+ std::size_t output_offset{sizeof(AudioCommon::UpdateDataHeader)};
+};
+
+} // namespace AudioCore
diff --git a/src/audio_core/memory_pool.cpp b/src/audio_core/memory_pool.cpp
new file mode 100644
index 000000000..5a3453063
--- /dev/null
+++ b/src/audio_core/memory_pool.cpp
@@ -0,0 +1,62 @@
+
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/memory_pool.h"
+#include "common/logging/log.h"
+
+namespace AudioCore {
+
+ServerMemoryPoolInfo::ServerMemoryPoolInfo() = default;
+ServerMemoryPoolInfo::~ServerMemoryPoolInfo() = default;
+bool ServerMemoryPoolInfo::Update(const ServerMemoryPoolInfo::InParams& in_params,
+ ServerMemoryPoolInfo::OutParams& out_params) {
+ // Our state does not need to be changed
+ if (in_params.state != ServerMemoryPoolInfo::State::RequestAttach &&
+ in_params.state != ServerMemoryPoolInfo::State::RequestDetach) {
+ return true;
+ }
+
+ // Address or size is null
+ if (in_params.address == 0 || in_params.size == 0) {
+ LOG_ERROR(Audio, "Memory pool address or size is zero! address={:X}, size={:X}",
+ in_params.address, in_params.size);
+ return false;
+ }
+
+ // Address or size is not aligned
+ if ((in_params.address % 0x1000) != 0 || (in_params.size % 0x1000) != 0) {
+ LOG_ERROR(Audio, "Memory pool address or size is not aligned! address={:X}, size={:X}",
+ in_params.address, in_params.size);
+ return false;
+ }
+
+ if (in_params.state == ServerMemoryPoolInfo::State::RequestAttach) {
+ cpu_address = in_params.address;
+ size = in_params.size;
+ used = true;
+ out_params.state = ServerMemoryPoolInfo::State::Attached;
+ } else {
+ // Unexpected address
+ if (cpu_address != in_params.address) {
+ LOG_ERROR(Audio, "Memory pool address differs! Expecting {:X} but address is {:X}",
+ cpu_address, in_params.address);
+ return false;
+ }
+
+ if (size != in_params.size) {
+ LOG_ERROR(Audio, "Memory pool size differs! Expecting {:X} but size is {:X}", size,
+ in_params.size);
+ return false;
+ }
+
+ cpu_address = 0;
+ size = 0;
+ used = false;
+ out_params.state = ServerMemoryPoolInfo::State::Detached;
+ }
+ return true;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/memory_pool.h b/src/audio_core/memory_pool.h
new file mode 100644
index 000000000..8ac503f1c
--- /dev/null
+++ b/src/audio_core/memory_pool.h
@@ -0,0 +1,53 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+
+namespace AudioCore {
+
+class ServerMemoryPoolInfo {
+public:
+ ServerMemoryPoolInfo();
+ ~ServerMemoryPoolInfo();
+
+ enum class State : u32_le {
+ Invalid = 0x0,
+ Aquired = 0x1,
+ RequestDetach = 0x2,
+ Detached = 0x3,
+ RequestAttach = 0x4,
+ Attached = 0x5,
+ Released = 0x6,
+ };
+
+ struct InParams {
+ u64_le address{};
+ u64_le size{};
+ ServerMemoryPoolInfo::State state{};
+ INSERT_PADDING_WORDS(3);
+ };
+ static_assert(sizeof(ServerMemoryPoolInfo::InParams) == 0x20, "InParams are an invalid size");
+
+ struct OutParams {
+ ServerMemoryPoolInfo::State state{};
+ INSERT_PADDING_WORDS(3);
+ };
+ static_assert(sizeof(ServerMemoryPoolInfo::OutParams) == 0x10, "OutParams are an invalid size");
+
+ bool Update(const ServerMemoryPoolInfo::InParams& in_params,
+ ServerMemoryPoolInfo::OutParams& out_params);
+
+private:
+ // There's another entry here which is the DSP address, however since we're not talking to the
+ // DSP we can just use the same address provided by the guest without needing to remap
+ u64_le cpu_address{};
+ u64_le size{};
+ bool used{};
+};
+
+} // namespace AudioCore
diff --git a/src/audio_core/mix_context.cpp b/src/audio_core/mix_context.cpp
new file mode 100644
index 000000000..4bca72eb0
--- /dev/null
+++ b/src/audio_core/mix_context.cpp
@@ -0,0 +1,296 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/behavior_info.h"
+#include "audio_core/common.h"
+#include "audio_core/effect_context.h"
+#include "audio_core/mix_context.h"
+#include "audio_core/splitter_context.h"
+
+namespace AudioCore {
+MixContext::MixContext() = default;
+MixContext::~MixContext() = default;
+
+void MixContext::Initialize(const BehaviorInfo& behavior_info, std::size_t mix_count,
+ std::size_t effect_count) {
+ info_count = mix_count;
+ infos.resize(info_count);
+ auto& final_mix = GetInfo(AudioCommon::FINAL_MIX);
+ final_mix.GetInParams().mix_id = AudioCommon::FINAL_MIX;
+ sorted_info.reserve(infos.size());
+ for (auto& info : infos) {
+ sorted_info.push_back(&info);
+ }
+
+ for (auto& info : infos) {
+ info.SetEffectCount(effect_count);
+ }
+
+ // Only initialize our edge matrix and node states if splitters are supported
+ if (behavior_info.IsSplitterSupported()) {
+ node_states.Initialize(mix_count);
+ edge_matrix.Initialize(mix_count);
+ }
+}
+
+void MixContext::UpdateDistancesFromFinalMix() {
+ // Set all distances to be invalid
+ for (std::size_t i = 0; i < info_count; i++) {
+ GetInfo(i).GetInParams().final_mix_distance = AudioCommon::NO_FINAL_MIX;
+ }
+
+ for (std::size_t i = 0; i < info_count; i++) {
+ auto& info = GetInfo(i);
+ auto& in_params = info.GetInParams();
+ // Populate our sorted info
+ sorted_info[i] = &info;
+
+ if (!in_params.in_use) {
+ continue;
+ }
+
+ auto mix_id = in_params.mix_id;
+ // Needs to be referenced out of scope
+ s32 distance_to_final_mix{AudioCommon::FINAL_MIX};
+ for (; distance_to_final_mix < static_cast<s32>(info_count); distance_to_final_mix++) {
+ if (mix_id == AudioCommon::FINAL_MIX) {
+ // If we're at the final mix, we're done
+ break;
+ } else if (mix_id == AudioCommon::NO_MIX) {
+ // If we have no more mix ids, we're done
+ distance_to_final_mix = AudioCommon::NO_FINAL_MIX;
+ break;
+ } else {
+ const auto& dest_mix = GetInfo(mix_id);
+ const auto dest_mix_distance = dest_mix.GetInParams().final_mix_distance;
+
+ if (dest_mix_distance == AudioCommon::NO_FINAL_MIX) {
+ // If our current mix isn't pointing to a final mix, follow through
+ mix_id = dest_mix.GetInParams().dest_mix_id;
+ } else {
+ // Our current mix + 1 = final distance
+ distance_to_final_mix = dest_mix_distance + 1;
+ break;
+ }
+ }
+ }
+
+ // If we're out of range for our distance, mark it as no final mix
+ if (distance_to_final_mix >= static_cast<s32>(info_count)) {
+ distance_to_final_mix = AudioCommon::NO_FINAL_MIX;
+ }
+
+ in_params.final_mix_distance = distance_to_final_mix;
+ }
+}
+
+void MixContext::CalcMixBufferOffset() {
+ s32 offset{};
+ for (std::size_t i = 0; i < info_count; i++) {
+ auto& info = GetSortedInfo(i);
+ auto& in_params = info.GetInParams();
+ if (in_params.in_use) {
+ // Only update if in use
+ in_params.buffer_offset = offset;
+ offset += in_params.buffer_count;
+ }
+ }
+}
+
+void MixContext::SortInfo() {
+ // Get the distance to the final mix
+ UpdateDistancesFromFinalMix();
+
+ // Sort based on the distance to the final mix
+ std::sort(sorted_info.begin(), sorted_info.end(),
+ [](const ServerMixInfo* lhs, const ServerMixInfo* rhs) {
+ return lhs->GetInParams().final_mix_distance >
+ rhs->GetInParams().final_mix_distance;
+ });
+
+ // Calculate the mix buffer offset
+ CalcMixBufferOffset();
+}
+
+bool MixContext::TsortInfo(SplitterContext& splitter_context) {
+ // If we're not using mixes, just calculate the mix buffer offset
+ if (!splitter_context.UsingSplitter()) {
+ CalcMixBufferOffset();
+ return true;
+ }
+ // Sort our node states
+ if (!node_states.Tsort(edge_matrix)) {
+ return false;
+ }
+
+ // Get our sorted list
+ const auto sorted_list = node_states.GetIndexList();
+ std::size_t info_id{};
+ for (auto itr = sorted_list.rbegin(); itr != sorted_list.rend(); ++itr) {
+ // Set our sorted info
+ sorted_info[info_id++] = &GetInfo(*itr);
+ }
+
+ // Calculate the mix buffer offset
+ CalcMixBufferOffset();
+ return true;
+}
+
+std::size_t MixContext::GetCount() const {
+ return info_count;
+}
+
+ServerMixInfo& MixContext::GetInfo(std::size_t i) {
+ ASSERT(i < info_count);
+ return infos.at(i);
+}
+
+const ServerMixInfo& MixContext::GetInfo(std::size_t i) const {
+ ASSERT(i < info_count);
+ return infos.at(i);
+}
+
+ServerMixInfo& MixContext::GetSortedInfo(std::size_t i) {
+ ASSERT(i < info_count);
+ return *sorted_info.at(i);
+}
+
+const ServerMixInfo& MixContext::GetSortedInfo(std::size_t i) const {
+ ASSERT(i < info_count);
+ return *sorted_info.at(i);
+}
+
+ServerMixInfo& MixContext::GetFinalMixInfo() {
+ return infos.at(AudioCommon::FINAL_MIX);
+}
+
+const ServerMixInfo& MixContext::GetFinalMixInfo() const {
+ return infos.at(AudioCommon::FINAL_MIX);
+}
+
+EdgeMatrix& MixContext::GetEdgeMatrix() {
+ return edge_matrix;
+}
+
+const EdgeMatrix& MixContext::GetEdgeMatrix() const {
+ return edge_matrix;
+}
+
+ServerMixInfo::ServerMixInfo() {
+ Cleanup();
+}
+ServerMixInfo::~ServerMixInfo() = default;
+
+const ServerMixInfo::InParams& ServerMixInfo::GetInParams() const {
+ return in_params;
+}
+
+ServerMixInfo::InParams& ServerMixInfo::GetInParams() {
+ return in_params;
+}
+
+bool ServerMixInfo::Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
+ BehaviorInfo& behavior_info, SplitterContext& splitter_context,
+ EffectContext& effect_context) {
+ in_params.volume = mix_in.volume;
+ in_params.sample_rate = mix_in.sample_rate;
+ in_params.buffer_count = mix_in.buffer_count;
+ in_params.in_use = mix_in.in_use;
+ in_params.mix_id = mix_in.mix_id;
+ in_params.node_id = mix_in.node_id;
+ for (std::size_t i = 0; i < mix_in.mix_volume.size(); i++) {
+ std::copy(mix_in.mix_volume[i].begin(), mix_in.mix_volume[i].end(),
+ in_params.mix_volume[i].begin());
+ }
+
+ bool require_sort = false;
+
+ if (behavior_info.IsSplitterSupported()) {
+ require_sort = UpdateConnection(edge_matrix, mix_in, splitter_context);
+ } else {
+ in_params.dest_mix_id = mix_in.dest_mix_id;
+ in_params.splitter_id = AudioCommon::NO_SPLITTER;
+ }
+
+ ResetEffectProcessingOrder();
+ const auto effect_count = effect_context.GetCount();
+ for (std::size_t i = 0; i < effect_count; i++) {
+ auto* effect_info = effect_context.GetInfo(i);
+ if (effect_info->GetMixID() == in_params.mix_id) {
+ effect_processing_order[effect_info->GetProcessingOrder()] = static_cast<s32>(i);
+ }
+ }
+
+ // TODO(ogniK): Update effect processing order
+ return require_sort;
+}
+
+bool ServerMixInfo::HasAnyConnection() const {
+ return in_params.splitter_id != AudioCommon::NO_SPLITTER ||
+ in_params.mix_id != AudioCommon::NO_MIX;
+}
+
+void ServerMixInfo::Cleanup() {
+ in_params.volume = 0.0f;
+ in_params.sample_rate = 0;
+ in_params.buffer_count = 0;
+ in_params.in_use = false;
+ in_params.mix_id = AudioCommon::NO_MIX;
+ in_params.node_id = 0;
+ in_params.buffer_offset = 0;
+ in_params.dest_mix_id = AudioCommon::NO_MIX;
+ in_params.splitter_id = AudioCommon::NO_SPLITTER;
+ std::memset(in_params.mix_volume.data(), 0, sizeof(float) * in_params.mix_volume.size());
+}
+
+void ServerMixInfo::SetEffectCount(std::size_t count) {
+ effect_processing_order.resize(count);
+ ResetEffectProcessingOrder();
+}
+
+void ServerMixInfo::ResetEffectProcessingOrder() {
+ for (auto& order : effect_processing_order) {
+ order = AudioCommon::NO_EFFECT_ORDER;
+ }
+}
+
+s32 ServerMixInfo::GetEffectOrder(std::size_t i) const {
+ return effect_processing_order.at(i);
+}
+
+bool ServerMixInfo::UpdateConnection(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
+ SplitterContext& splitter_context) {
+ // Mixes are identical
+ if (in_params.dest_mix_id == mix_in.dest_mix_id &&
+ in_params.splitter_id == mix_in.splitter_id &&
+ ((in_params.splitter_id == AudioCommon::NO_SPLITTER) ||
+ !splitter_context.GetInfo(in_params.splitter_id).HasNewConnection())) {
+ return false;
+ }
+ // Remove current edges for mix id
+ edge_matrix.RemoveEdges(in_params.mix_id);
+ if (mix_in.dest_mix_id != AudioCommon::NO_MIX) {
+ // If we have a valid destination mix id, set our edge matrix
+ edge_matrix.Connect(in_params.mix_id, mix_in.dest_mix_id);
+ } else if (mix_in.splitter_id != AudioCommon::NO_SPLITTER) {
+ // Recurse our splitter linked and set our edges
+ auto& splitter_info = splitter_context.GetInfo(mix_in.splitter_id);
+ const auto length = splitter_info.GetLength();
+ for (s32 i = 0; i < length; i++) {
+ const auto* splitter_destination =
+ splitter_context.GetDestinationData(mix_in.splitter_id, i);
+ if (splitter_destination == nullptr) {
+ continue;
+ }
+ if (splitter_destination->ValidMixId()) {
+ edge_matrix.Connect(in_params.mix_id, splitter_destination->GetMixId());
+ }
+ }
+ }
+ in_params.dest_mix_id = mix_in.dest_mix_id;
+ in_params.splitter_id = mix_in.splitter_id;
+ return true;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/mix_context.h b/src/audio_core/mix_context.h
new file mode 100644
index 000000000..6a588eeb4
--- /dev/null
+++ b/src/audio_core/mix_context.h
@@ -0,0 +1,114 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <vector>
+#include "audio_core/common.h"
+#include "audio_core/splitter_context.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace AudioCore {
+class BehaviorInfo;
+class EffectContext;
+
+class MixInfo {
+public:
+ struct DirtyHeader {
+ u32_le magic{};
+ u32_le mixer_count{};
+ INSERT_PADDING_BYTES(0x18);
+ };
+ static_assert(sizeof(DirtyHeader) == 0x20, "MixInfo::DirtyHeader is an invalid size");
+
+ struct InParams {
+ float_le volume{};
+ s32_le sample_rate{};
+ s32_le buffer_count{};
+ bool in_use{};
+ INSERT_PADDING_BYTES(3);
+ s32_le mix_id{};
+ s32_le effect_count{};
+ u32_le node_id{};
+ INSERT_PADDING_WORDS(2);
+ std::array<std::array<float_le, AudioCommon::MAX_MIX_BUFFERS>, AudioCommon::MAX_MIX_BUFFERS>
+ mix_volume{};
+ s32_le dest_mix_id{};
+ s32_le splitter_id{};
+ INSERT_PADDING_WORDS(1);
+ };
+ static_assert(sizeof(MixInfo::InParams) == 0x930, "MixInfo::InParams is an invalid size");
+};
+
+class ServerMixInfo {
+public:
+ struct InParams {
+ float volume{};
+ s32 sample_rate{};
+ s32 buffer_count{};
+ bool in_use{};
+ s32 mix_id{};
+ u32 node_id{};
+ std::array<std::array<float_le, AudioCommon::MAX_MIX_BUFFERS>, AudioCommon::MAX_MIX_BUFFERS>
+ mix_volume{};
+ s32 dest_mix_id{};
+ s32 splitter_id{};
+ s32 buffer_offset{};
+ s32 final_mix_distance{};
+ };
+ ServerMixInfo();
+ ~ServerMixInfo();
+
+ const ServerMixInfo::InParams& GetInParams() const;
+ ServerMixInfo::InParams& GetInParams();
+
+ bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
+ BehaviorInfo& behavior_info, SplitterContext& splitter_context,
+ EffectContext& effect_context);
+ bool HasAnyConnection() const;
+ void Cleanup();
+ void SetEffectCount(std::size_t count);
+ void ResetEffectProcessingOrder();
+ s32 GetEffectOrder(std::size_t i) const;
+
+private:
+ std::vector<s32> effect_processing_order;
+ InParams in_params{};
+ bool UpdateConnection(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
+ SplitterContext& splitter_context);
+};
+
+class MixContext {
+public:
+ MixContext();
+ ~MixContext();
+
+ void Initialize(const BehaviorInfo& behavior_info, std::size_t mix_count,
+ std::size_t effect_count);
+ void SortInfo();
+ bool TsortInfo(SplitterContext& splitter_context);
+
+ std::size_t GetCount() const;
+ ServerMixInfo& GetInfo(std::size_t i);
+ const ServerMixInfo& GetInfo(std::size_t i) const;
+ ServerMixInfo& GetSortedInfo(std::size_t i);
+ const ServerMixInfo& GetSortedInfo(std::size_t i) const;
+ ServerMixInfo& GetFinalMixInfo();
+ const ServerMixInfo& GetFinalMixInfo() const;
+ EdgeMatrix& GetEdgeMatrix();
+ const EdgeMatrix& GetEdgeMatrix() const;
+
+private:
+ void CalcMixBufferOffset();
+ void UpdateDistancesFromFinalMix();
+
+ NodeStates node_states{};
+ EdgeMatrix edge_matrix{};
+ std::size_t info_count{};
+ std::vector<ServerMixInfo> infos{};
+ std::vector<ServerMixInfo*> sorted_info{};
+};
+} // namespace AudioCore
diff --git a/src/audio_core/sink_context.cpp b/src/audio_core/sink_context.cpp
new file mode 100644
index 000000000..0882b411a
--- /dev/null
+++ b/src/audio_core/sink_context.cpp
@@ -0,0 +1,31 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/sink_context.h"
+
+namespace AudioCore {
+SinkContext::SinkContext(std::size_t sink_count) : sink_count(sink_count) {}
+SinkContext::~SinkContext() = default;
+
+std::size_t SinkContext::GetCount() const {
+ return sink_count;
+}
+
+void SinkContext::UpdateMainSink(SinkInfo::InParams& in) {
+ in_use = in.in_use;
+ use_count = in.device.input_count;
+ std::memcpy(buffers.data(), in.device.input.data(), AudioCommon::MAX_CHANNEL_COUNT);
+}
+
+bool SinkContext::InUse() const {
+ return in_use;
+}
+
+std::vector<u8> SinkContext::OutputBuffers() const {
+ std::vector<u8> buffer_ret(use_count);
+ std::memcpy(buffer_ret.data(), buffers.data(), use_count);
+ return buffer_ret;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/sink_context.h b/src/audio_core/sink_context.h
new file mode 100644
index 000000000..d7aa72ba7
--- /dev/null
+++ b/src/audio_core/sink_context.h
@@ -0,0 +1,89 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "audio_core/common.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+
+namespace AudioCore {
+
+enum class SinkTypes : u8 {
+ Invalid = 0,
+ Device = 1,
+ Circular = 2,
+};
+
+enum class SinkSampleFormat : u32_le {
+ None = 0,
+ Pcm8 = 1,
+ Pcm16 = 2,
+ Pcm24 = 3,
+ Pcm32 = 4,
+ PcmFloat = 5,
+ Adpcm = 6,
+};
+
+class SinkInfo {
+public:
+ struct CircularBufferIn {
+ u64_le address;
+ u32_le size;
+ u32_le input_count;
+ u32_le sample_count;
+ u32_le previous_position;
+ SinkSampleFormat sample_format;
+ std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input;
+ bool in_use;
+ INSERT_UNION_PADDING_BYTES(5);
+ };
+ static_assert(sizeof(SinkInfo::CircularBufferIn) == 0x28,
+ "SinkInfo::CircularBufferIn is in invalid size");
+
+ struct DeviceIn {
+ std::array<u8, 255> device_name;
+ INSERT_UNION_PADDING_BYTES(1);
+ s32_le input_count;
+ std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input;
+ INSERT_UNION_PADDING_BYTES(1);
+ bool down_matrix_enabled;
+ std::array<float_le, 4> down_matrix_coef;
+ };
+ static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size");
+
+ struct InParams {
+ SinkTypes type{};
+ bool in_use{};
+ INSERT_PADDING_BYTES(2);
+ u32_le node_id{};
+ INSERT_PADDING_WORDS(6);
+ union {
+ // std::array<u8, 0x120> raw{};
+ SinkInfo::DeviceIn device;
+ SinkInfo::CircularBufferIn circular_buffer;
+ };
+ };
+ static_assert(sizeof(SinkInfo::InParams) == 0x140, "SinkInfo::InParams are an invalid size!");
+};
+
+class SinkContext {
+public:
+ explicit SinkContext(std::size_t sink_count);
+ ~SinkContext();
+
+ std::size_t GetCount() const;
+
+ void UpdateMainSink(SinkInfo::InParams& in);
+ bool InUse() const;
+ std::vector<u8> OutputBuffers() const;
+
+private:
+ bool in_use{false};
+ s32 use_count{};
+ std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{};
+ std::size_t sink_count{};
+};
+} // namespace AudioCore
diff --git a/src/audio_core/splitter_context.cpp b/src/audio_core/splitter_context.cpp
new file mode 100644
index 000000000..f21b53147
--- /dev/null
+++ b/src/audio_core/splitter_context.cpp
@@ -0,0 +1,617 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/behavior_info.h"
+#include "audio_core/splitter_context.h"
+#include "common/alignment.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
+
+namespace AudioCore {
+
+ServerSplitterDestinationData::ServerSplitterDestinationData(s32 id) : id(id) {}
+ServerSplitterDestinationData::~ServerSplitterDestinationData() = default;
+
+void ServerSplitterDestinationData::Update(SplitterInfo::InDestinationParams& header) {
+ // Log error as these are not actually failure states
+ if (header.magic != SplitterMagic::DataHeader) {
+ LOG_ERROR(Audio, "Splitter destination header is invalid!");
+ return;
+ }
+
+ // Incorrect splitter id
+ if (header.splitter_id != id) {
+ LOG_ERROR(Audio, "Splitter destination ids do not match!");
+ return;
+ }
+
+ mix_id = header.mix_id;
+ // Copy our mix volumes
+ std::copy(header.mix_volumes.begin(), header.mix_volumes.end(), current_mix_volumes.begin());
+ if (!in_use && header.in_use) {
+ // Update mix volumes
+ std::copy(current_mix_volumes.begin(), current_mix_volumes.end(), last_mix_volumes.begin());
+ needs_update = false;
+ }
+ in_use = header.in_use;
+}
+
+ServerSplitterDestinationData* ServerSplitterDestinationData::GetNextDestination() {
+ return next;
+}
+
+const ServerSplitterDestinationData* ServerSplitterDestinationData::GetNextDestination() const {
+ return next;
+}
+
+void ServerSplitterDestinationData::SetNextDestination(ServerSplitterDestinationData* dest) {
+ next = dest;
+}
+
+bool ServerSplitterDestinationData::ValidMixId() const {
+ return GetMixId() != AudioCommon::NO_MIX;
+}
+
+s32 ServerSplitterDestinationData::GetMixId() const {
+ return mix_id;
+}
+
+bool ServerSplitterDestinationData::IsConfigured() const {
+ return in_use && ValidMixId();
+}
+
+float ServerSplitterDestinationData::GetMixVolume(std::size_t i) const {
+ ASSERT(i < AudioCommon::MAX_MIX_BUFFERS);
+ return current_mix_volumes.at(i);
+}
+
+const std::array<float, AudioCommon::MAX_MIX_BUFFERS>&
+ServerSplitterDestinationData::CurrentMixVolumes() const {
+ return current_mix_volumes;
+}
+
+const std::array<float, AudioCommon::MAX_MIX_BUFFERS>&
+ServerSplitterDestinationData::LastMixVolumes() const {
+ return last_mix_volumes;
+}
+
+void ServerSplitterDestinationData::MarkDirty() {
+ needs_update = true;
+}
+
+void ServerSplitterDestinationData::UpdateInternalState() {
+ if (in_use && needs_update) {
+ std::copy(current_mix_volumes.begin(), current_mix_volumes.end(), last_mix_volumes.begin());
+ }
+ needs_update = false;
+}
+
+ServerSplitterInfo::ServerSplitterInfo(s32 id) : id(id) {}
+ServerSplitterInfo::~ServerSplitterInfo() = default;
+
+void ServerSplitterInfo::InitializeInfos() {
+ send_length = 0;
+ head = nullptr;
+ new_connection = true;
+}
+
+void ServerSplitterInfo::ClearNewConnectionFlag() {
+ new_connection = false;
+}
+
+std::size_t ServerSplitterInfo::Update(SplitterInfo::InInfoPrams& header) {
+ if (header.send_id != id) {
+ return 0;
+ }
+
+ sample_rate = header.sample_rate;
+ new_connection = true;
+ // We need to update the size here due to the splitter bug being present and providing an
+ // incorrect size. We're suppose to also update the header here but we just ignore and continue
+ return (sizeof(s32_le) * (header.length - 1)) + (sizeof(s32_le) * 3);
+}
+
+ServerSplitterDestinationData* ServerSplitterInfo::GetHead() {
+ return head;
+}
+
+const ServerSplitterDestinationData* ServerSplitterInfo::GetHead() const {
+ return head;
+}
+
+ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) {
+ auto current_head = head;
+ for (std::size_t i = 0; i < depth; i++) {
+ if (current_head == nullptr) {
+ return nullptr;
+ }
+ current_head = current_head->GetNextDestination();
+ }
+ return current_head;
+}
+
+const ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) const {
+ auto current_head = head;
+ for (std::size_t i = 0; i < depth; i++) {
+ if (current_head == nullptr) {
+ return nullptr;
+ }
+ current_head = current_head->GetNextDestination();
+ }
+ return current_head;
+}
+
+bool ServerSplitterInfo::HasNewConnection() const {
+ return new_connection;
+}
+
+s32 ServerSplitterInfo::GetLength() const {
+ return send_length;
+}
+
+void ServerSplitterInfo::SetHead(ServerSplitterDestinationData* new_head) {
+ head = new_head;
+}
+
+void ServerSplitterInfo::SetHeadDepth(s32 length) {
+ send_length = length;
+}
+
+SplitterContext::SplitterContext() = default;
+SplitterContext::~SplitterContext() = default;
+
+void SplitterContext::Initialize(BehaviorInfo& behavior_info, std::size_t _info_count,
+ std::size_t _data_count) {
+ if (!behavior_info.IsSplitterSupported() || _data_count == 0 || _info_count == 0) {
+ Setup(0, 0, false);
+ return;
+ }
+ // Only initialize if we're using splitters
+ Setup(_info_count, _data_count, behavior_info.IsSplitterBugFixed());
+}
+
+bool SplitterContext::Update(const std::vector<u8>& input, std::size_t& input_offset,
+ std::size_t& bytes_read) {
+ const auto UpdateOffsets = [&](std::size_t read) {
+ input_offset += read;
+ bytes_read += read;
+ };
+
+ if (info_count == 0 || data_count == 0) {
+ bytes_read = 0;
+ return true;
+ }
+
+ if (!AudioCommon::CanConsumeBuffer(input.size(), input_offset,
+ sizeof(SplitterInfo::InHeader))) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+ SplitterInfo::InHeader header{};
+ std::memcpy(&header, input.data() + input_offset, sizeof(SplitterInfo::InHeader));
+ UpdateOffsets(sizeof(SplitterInfo::InHeader));
+
+ if (header.magic != SplitterMagic::SplitterHeader) {
+ LOG_ERROR(Audio, "Invalid header magic! Expecting {:X} but got {:X}",
+ SplitterMagic::SplitterHeader, header.magic);
+ return false;
+ }
+
+ // Clear all connections
+ for (auto& info : infos) {
+ info.ClearNewConnectionFlag();
+ }
+
+ UpdateInfo(input, input_offset, bytes_read, header.info_count);
+ UpdateData(input, input_offset, bytes_read, header.data_count);
+ const auto aligned_bytes_read = Common::AlignUp(bytes_read, 16);
+ input_offset += aligned_bytes_read - bytes_read;
+ bytes_read = aligned_bytes_read;
+ return true;
+}
+
+bool SplitterContext::UsingSplitter() const {
+ return info_count > 0 && data_count > 0;
+}
+
+ServerSplitterInfo& SplitterContext::GetInfo(std::size_t i) {
+ ASSERT(i < info_count);
+ return infos.at(i);
+}
+
+const ServerSplitterInfo& SplitterContext::GetInfo(std::size_t i) const {
+ ASSERT(i < info_count);
+ return infos.at(i);
+}
+
+ServerSplitterDestinationData& SplitterContext::GetData(std::size_t i) {
+ ASSERT(i < data_count);
+ return datas.at(i);
+}
+
+const ServerSplitterDestinationData& SplitterContext::GetData(std::size_t i) const {
+ ASSERT(i < data_count);
+ return datas.at(i);
+}
+
+ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t info,
+ std::size_t data) {
+ ASSERT(info < info_count);
+ auto& cur_info = GetInfo(info);
+ return cur_info.GetData(data);
+}
+
+const ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t info,
+ std::size_t data) const {
+ ASSERT(info < info_count);
+ auto& cur_info = GetInfo(info);
+ return cur_info.GetData(data);
+}
+
+void SplitterContext::UpdateInternalState() {
+ if (data_count == 0) {
+ return;
+ }
+
+ for (auto& data : datas) {
+ data.UpdateInternalState();
+ }
+}
+
+std::size_t SplitterContext::GetInfoCount() const {
+ return info_count;
+}
+
+std::size_t SplitterContext::GetDataCount() const {
+ return data_count;
+}
+
+void SplitterContext::Setup(std::size_t _info_count, std::size_t _data_count,
+ bool is_splitter_bug_fixed) {
+
+ info_count = _info_count;
+ data_count = _data_count;
+
+ for (std::size_t i = 0; i < info_count; i++) {
+ auto& splitter = infos.emplace_back(static_cast<s32>(i));
+ splitter.InitializeInfos();
+ }
+ for (std::size_t i = 0; i < data_count; i++) {
+ datas.emplace_back(static_cast<s32>(i));
+ }
+
+ bug_fixed = is_splitter_bug_fixed;
+}
+
+bool SplitterContext::UpdateInfo(const std::vector<u8>& input, std::size_t& input_offset,
+ std::size_t& bytes_read, s32 in_splitter_count) {
+ const auto UpdateOffsets = [&](std::size_t read) {
+ input_offset += read;
+ bytes_read += read;
+ };
+
+ for (s32 i = 0; i < in_splitter_count; i++) {
+ if (!AudioCommon::CanConsumeBuffer(input.size(), input_offset,
+ sizeof(SplitterInfo::InInfoPrams))) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+ SplitterInfo::InInfoPrams header{};
+ std::memcpy(&header, input.data() + input_offset, sizeof(SplitterInfo::InInfoPrams));
+
+ // Logged as warning as these don't actually cause a bailout for some reason
+ if (header.magic != SplitterMagic::InfoHeader) {
+ LOG_ERROR(Audio, "Bad splitter data header");
+ break;
+ }
+
+ if (header.send_id < 0 || static_cast<std::size_t>(header.send_id) > info_count) {
+ LOG_ERROR(Audio, "Bad splitter data id");
+ break;
+ }
+
+ UpdateOffsets(sizeof(SplitterInfo::InInfoPrams));
+ auto& info = GetInfo(header.send_id);
+ if (!RecomposeDestination(info, header, input, input_offset)) {
+ LOG_ERROR(Audio, "Failed to recompose destination for splitter!");
+ return false;
+ }
+ const std::size_t read = info.Update(header);
+ bytes_read += read;
+ input_offset += read;
+ }
+ return true;
+}
+
+bool SplitterContext::UpdateData(const std::vector<u8>& input, std::size_t& input_offset,
+ std::size_t& bytes_read, s32 in_data_count) {
+ const auto UpdateOffsets = [&](std::size_t read) {
+ input_offset += read;
+ bytes_read += read;
+ };
+
+ for (s32 i = 0; i < in_data_count; i++) {
+ if (!AudioCommon::CanConsumeBuffer(input.size(), input_offset,
+ sizeof(SplitterInfo::InDestinationParams))) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+ SplitterInfo::InDestinationParams header{};
+ std::memcpy(&header, input.data() + input_offset,
+ sizeof(SplitterInfo::InDestinationParams));
+ UpdateOffsets(sizeof(SplitterInfo::InDestinationParams));
+
+ // Logged as warning as these don't actually cause a bailout for some reason
+ if (header.magic != SplitterMagic::DataHeader) {
+ LOG_ERROR(Audio, "Bad splitter data header");
+ break;
+ }
+
+ if (header.splitter_id < 0 || static_cast<std::size_t>(header.splitter_id) > data_count) {
+ LOG_ERROR(Audio, "Bad splitter data id");
+ break;
+ }
+ GetData(header.splitter_id).Update(header);
+ }
+ return true;
+}
+
+bool SplitterContext::RecomposeDestination(ServerSplitterInfo& info,
+ SplitterInfo::InInfoPrams& header,
+ const std::vector<u8>& input,
+ const std::size_t& input_offset) {
+ // Clear our current destinations
+ auto* current_head = info.GetHead();
+ while (current_head != nullptr) {
+ auto next_head = current_head->GetNextDestination();
+ current_head->SetNextDestination(nullptr);
+ current_head = next_head;
+ }
+ info.SetHead(nullptr);
+
+ s32 size = header.length;
+ // If the splitter bug is present, calculate fixed size
+ if (!bug_fixed) {
+ if (info_count > 0) {
+ const auto factor = data_count / info_count;
+ size = std::min(header.length, static_cast<s32>(factor));
+ } else {
+ size = 0;
+ }
+ }
+
+ if (size < 1) {
+ LOG_ERROR(Audio, "Invalid splitter info size! size={:X}", size);
+ return true;
+ }
+
+ auto* start_head = &GetData(header.resource_id_base);
+ current_head = start_head;
+ std::vector<s32_le> resource_ids(size - 1);
+ if (!AudioCommon::CanConsumeBuffer(input.size(), input_offset,
+ resource_ids.size() * sizeof(s32_le))) {
+ LOG_ERROR(Audio, "Buffer is an invalid size!");
+ return false;
+ }
+ std::memcpy(resource_ids.data(), input.data() + input_offset,
+ resource_ids.size() * sizeof(s32_le));
+
+ for (auto resource_id : resource_ids) {
+ auto* head = &GetData(resource_id);
+ current_head->SetNextDestination(head);
+ current_head = head;
+ }
+
+ info.SetHead(start_head);
+ info.SetHeadDepth(size);
+
+ return true;
+}
+
+NodeStates::NodeStates() = default;
+NodeStates::~NodeStates() = default;
+
+void NodeStates::Initialize(std::size_t node_count_) {
+ // Setup our work parameters
+ node_count = node_count_;
+ was_node_found.resize(node_count);
+ was_node_completed.resize(node_count);
+ index_list.resize(node_count);
+ index_stack.Reset(node_count * node_count);
+}
+
+bool NodeStates::Tsort(EdgeMatrix& edge_matrix) {
+ return DepthFirstSearch(edge_matrix);
+}
+
+std::size_t NodeStates::GetIndexPos() const {
+ return index_pos;
+}
+
+const std::vector<s32>& NodeStates::GetIndexList() const {
+ return index_list;
+}
+
+void NodeStates::PushTsortResult(s32 index) {
+ ASSERT(index < static_cast<s32>(node_count));
+ index_list[index_pos++] = index;
+}
+
+bool NodeStates::DepthFirstSearch(EdgeMatrix& edge_matrix) {
+ ResetState();
+ for (std::size_t i = 0; i < node_count; i++) {
+ const auto node_id = static_cast<s32>(i);
+
+ // If we don't have a state, send to our index stack for work
+ if (GetState(i) == NodeStates::State::NoState) {
+ index_stack.push(node_id);
+ }
+
+ // While we have work to do in our stack
+ while (index_stack.Count() > 0) {
+ // Get the current node
+ const auto current_stack_index = index_stack.top();
+ // Check if we've seen the node yet
+ const auto index_state = GetState(current_stack_index);
+ if (index_state == NodeStates::State::NoState) {
+ // Mark the node as seen
+ UpdateState(NodeStates::State::InFound, current_stack_index);
+ } else if (index_state == NodeStates::State::InFound) {
+ // We've seen this node before, mark it as completed
+ UpdateState(NodeStates::State::InCompleted, current_stack_index);
+ // Update our index list
+ PushTsortResult(current_stack_index);
+ // Pop the stack
+ index_stack.pop();
+ continue;
+ } else if (index_state == NodeStates::State::InCompleted) {
+ // If our node is already sorted, clear it
+ index_stack.pop();
+ continue;
+ }
+
+ const auto node_count = edge_matrix.GetNodeCount();
+ for (s32 j = 0; j < static_cast<s32>(node_count); j++) {
+ // Check if our node is connected to our edge matrix
+ if (!edge_matrix.Connected(current_stack_index, j)) {
+ continue;
+ }
+
+ // Check if our node exists
+ const auto node_state = GetState(j);
+ if (node_state == NodeStates::State::NoState) {
+ // Add more work
+ index_stack.push(j);
+ } else if (node_state == NodeStates::State::InFound) {
+ UNREACHABLE_MSG("Node start marked as found");
+ ResetState();
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void NodeStates::ResetState() {
+ // Reset to the start of our index stack
+ index_pos = 0;
+ for (std::size_t i = 0; i < node_count; i++) {
+ // Mark all nodes as not found
+ was_node_found[i] = false;
+ // Mark all nodes as uncompleted
+ was_node_completed[i] = false;
+ // Mark all indexes as invalid
+ index_list[i] = -1;
+ }
+}
+
+void NodeStates::UpdateState(NodeStates::State state, std::size_t i) {
+ switch (state) {
+ case NodeStates::State::NoState:
+ was_node_found[i] = false;
+ was_node_completed[i] = false;
+ break;
+ case NodeStates::State::InFound:
+ was_node_found[i] = true;
+ was_node_completed[i] = false;
+ break;
+ case NodeStates::State::InCompleted:
+ was_node_found[i] = false;
+ was_node_completed[i] = true;
+ break;
+ }
+}
+
+NodeStates::State NodeStates::GetState(std::size_t i) {
+ ASSERT(i < node_count);
+ if (was_node_found[i]) {
+ // If our node exists in our found list
+ return NodeStates::State::InFound;
+ } else if (was_node_completed[i]) {
+ // If node is in the completed list
+ return NodeStates::State::InCompleted;
+ } else {
+ // If in neither
+ return NodeStates::State::NoState;
+ }
+}
+
+NodeStates::Stack::Stack() = default;
+NodeStates::Stack::~Stack() = default;
+
+void NodeStates::Stack::Reset(std::size_t size) {
+ // Mark our stack as empty
+ stack.resize(size);
+ stack_size = size;
+ stack_pos = 0;
+ std::fill(stack.begin(), stack.end(), 0);
+}
+
+void NodeStates::Stack::push(s32 val) {
+ ASSERT(stack_pos < stack_size);
+ stack[stack_pos++] = val;
+}
+
+std::size_t NodeStates::Stack::Count() const {
+ return stack_pos;
+}
+
+s32 NodeStates::Stack::top() const {
+ ASSERT(stack_pos > 0);
+ return stack[stack_pos - 1];
+}
+
+s32 NodeStates::Stack::pop() {
+ ASSERT(stack_pos > 0);
+ stack_pos--;
+ return stack[stack_pos];
+}
+
+EdgeMatrix::EdgeMatrix() = default;
+EdgeMatrix::~EdgeMatrix() = default;
+
+void EdgeMatrix::Initialize(std::size_t _node_count) {
+ node_count = _node_count;
+ edge_matrix.resize(node_count * node_count);
+}
+
+bool EdgeMatrix::Connected(s32 a, s32 b) {
+ return GetState(a, b);
+}
+
+void EdgeMatrix::Connect(s32 a, s32 b) {
+ SetState(a, b, true);
+}
+
+void EdgeMatrix::Disconnect(s32 a, s32 b) {
+ SetState(a, b, false);
+}
+
+void EdgeMatrix::RemoveEdges(s32 edge) {
+ for (std::size_t i = 0; i < node_count; i++) {
+ SetState(edge, static_cast<s32>(i), false);
+ }
+}
+
+std::size_t EdgeMatrix::GetNodeCount() const {
+ return node_count;
+}
+
+void EdgeMatrix::SetState(s32 a, s32 b, bool state) {
+ ASSERT(InRange(a, b));
+ edge_matrix.at(a * node_count + b) = state;
+}
+
+bool EdgeMatrix::GetState(s32 a, s32 b) {
+ ASSERT(InRange(a, b));
+ return edge_matrix.at(a * node_count + b);
+}
+
+bool EdgeMatrix::InRange(s32 a, s32 b) const {
+ const std::size_t pos = a * node_count + b;
+ return pos < (node_count * node_count);
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/splitter_context.h b/src/audio_core/splitter_context.h
new file mode 100644
index 000000000..ea6239fdb
--- /dev/null
+++ b/src/audio_core/splitter_context.h
@@ -0,0 +1,221 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <stack>
+#include <vector>
+#include "audio_core/common.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+
+namespace AudioCore {
+class BehaviorInfo;
+
+class EdgeMatrix {
+public:
+ EdgeMatrix();
+ ~EdgeMatrix();
+
+ void Initialize(std::size_t _node_count);
+ bool Connected(s32 a, s32 b);
+ void Connect(s32 a, s32 b);
+ void Disconnect(s32 a, s32 b);
+ void RemoveEdges(s32 edge);
+ std::size_t GetNodeCount() const;
+
+private:
+ void SetState(s32 a, s32 b, bool state);
+ bool GetState(s32 a, s32 b);
+
+ bool InRange(s32 a, s32 b) const;
+ std::vector<bool> edge_matrix{};
+ std::size_t node_count{};
+};
+
+class NodeStates {
+public:
+ enum class State {
+ NoState = 0,
+ InFound = 1,
+ InCompleted = 2,
+ };
+
+ // Looks to be a fixed size stack. Placed within the NodeStates class based on symbols
+ class Stack {
+ public:
+ Stack();
+ ~Stack();
+
+ void Reset(std::size_t size);
+ void push(s32 val);
+ std::size_t Count() const;
+ s32 top() const;
+ s32 pop();
+
+ private:
+ std::vector<s32> stack{};
+ std::size_t stack_size{};
+ std::size_t stack_pos{};
+ };
+ NodeStates();
+ ~NodeStates();
+
+ void Initialize(std::size_t _node_count);
+ bool Tsort(EdgeMatrix& edge_matrix);
+ std::size_t GetIndexPos() const;
+ const std::vector<s32>& GetIndexList() const;
+
+private:
+ void PushTsortResult(s32 index);
+ bool DepthFirstSearch(EdgeMatrix& edge_matrix);
+ void ResetState();
+ void UpdateState(NodeStates::State state, std::size_t i);
+ NodeStates::State GetState(std::size_t i);
+
+ std::size_t node_count{};
+ std::vector<bool> was_node_found{};
+ std::vector<bool> was_node_completed{};
+ std::size_t index_pos{};
+ std::vector<s32> index_list{};
+ NodeStates::Stack index_stack{};
+};
+
+enum class SplitterMagic : u32_le {
+ SplitterHeader = Common::MakeMagic('S', 'N', 'D', 'H'),
+ DataHeader = Common::MakeMagic('S', 'N', 'D', 'D'),
+ InfoHeader = Common::MakeMagic('S', 'N', 'D', 'I'),
+};
+
+class SplitterInfo {
+public:
+ struct InHeader {
+ SplitterMagic magic{};
+ s32_le info_count{};
+ s32_le data_count{};
+ INSERT_PADDING_WORDS(5);
+ };
+ static_assert(sizeof(SplitterInfo::InHeader) == 0x20,
+ "SplitterInfo::InHeader is an invalid size");
+
+ struct InInfoPrams {
+ SplitterMagic magic{};
+ s32_le send_id{};
+ s32_le sample_rate{};
+ s32_le length{};
+ s32_le resource_id_base{};
+ };
+ static_assert(sizeof(SplitterInfo::InInfoPrams) == 0x14,
+ "SplitterInfo::InInfoPrams is an invalid size");
+
+ struct InDestinationParams {
+ SplitterMagic magic{};
+ s32_le splitter_id{};
+ std::array<float_le, AudioCommon::MAX_MIX_BUFFERS> mix_volumes{};
+ s32_le mix_id{};
+ bool in_use{};
+ INSERT_PADDING_BYTES(3);
+ };
+ static_assert(sizeof(SplitterInfo::InDestinationParams) == 0x70,
+ "SplitterInfo::InDestinationParams is an invalid size");
+};
+
+class ServerSplitterDestinationData {
+public:
+ explicit ServerSplitterDestinationData(s32 id);
+ ~ServerSplitterDestinationData();
+
+ void Update(SplitterInfo::InDestinationParams& header);
+
+ ServerSplitterDestinationData* GetNextDestination();
+ const ServerSplitterDestinationData* GetNextDestination() const;
+ void SetNextDestination(ServerSplitterDestinationData* dest);
+ bool ValidMixId() const;
+ s32 GetMixId() const;
+ bool IsConfigured() const;
+ float GetMixVolume(std::size_t i) const;
+ const std::array<float, AudioCommon::MAX_MIX_BUFFERS>& CurrentMixVolumes() const;
+ const std::array<float, AudioCommon::MAX_MIX_BUFFERS>& LastMixVolumes() const;
+ void MarkDirty();
+ void UpdateInternalState();
+
+private:
+ bool needs_update{};
+ bool in_use{};
+ s32 id{};
+ s32 mix_id{};
+ std::array<float, AudioCommon::MAX_MIX_BUFFERS> current_mix_volumes{};
+ std::array<float, AudioCommon::MAX_MIX_BUFFERS> last_mix_volumes{};
+ ServerSplitterDestinationData* next = nullptr;
+};
+
+class ServerSplitterInfo {
+public:
+ explicit ServerSplitterInfo(s32 id);
+ ~ServerSplitterInfo();
+
+ void InitializeInfos();
+ void ClearNewConnectionFlag();
+ std::size_t Update(SplitterInfo::InInfoPrams& header);
+
+ ServerSplitterDestinationData* GetHead();
+ const ServerSplitterDestinationData* GetHead() const;
+ ServerSplitterDestinationData* GetData(std::size_t depth);
+ const ServerSplitterDestinationData* GetData(std::size_t depth) const;
+
+ bool HasNewConnection() const;
+ s32 GetLength() const;
+
+ void SetHead(ServerSplitterDestinationData* new_head);
+ void SetHeadDepth(s32 length);
+
+private:
+ s32 sample_rate{};
+ s32 id{};
+ s32 send_length{};
+ ServerSplitterDestinationData* head = nullptr;
+ bool new_connection{};
+};
+
+class SplitterContext {
+public:
+ SplitterContext();
+ ~SplitterContext();
+
+ void Initialize(BehaviorInfo& behavior_info, std::size_t splitter_count,
+ std::size_t data_count);
+
+ bool Update(const std::vector<u8>& input, std::size_t& input_offset, std::size_t& bytes_read);
+ bool UsingSplitter() const;
+
+ ServerSplitterInfo& GetInfo(std::size_t i);
+ const ServerSplitterInfo& GetInfo(std::size_t i) const;
+ ServerSplitterDestinationData& GetData(std::size_t i);
+ const ServerSplitterDestinationData& GetData(std::size_t i) const;
+ ServerSplitterDestinationData* GetDestinationData(std::size_t info, std::size_t data);
+ const ServerSplitterDestinationData* GetDestinationData(std::size_t info,
+ std::size_t data) const;
+ void UpdateInternalState();
+
+ std::size_t GetInfoCount() const;
+ std::size_t GetDataCount() const;
+
+private:
+ void Setup(std::size_t info_count, std::size_t data_count, bool is_splitter_bug_fixed);
+ bool UpdateInfo(const std::vector<u8>& input, std::size_t& input_offset,
+ std::size_t& bytes_read, s32 in_splitter_count);
+ bool UpdateData(const std::vector<u8>& input, std::size_t& input_offset,
+ std::size_t& bytes_read, s32 in_data_count);
+ bool RecomposeDestination(ServerSplitterInfo& info, SplitterInfo::InInfoPrams& header,
+ const std::vector<u8>& input, const std::size_t& input_offset);
+
+ std::vector<ServerSplitterInfo> infos{};
+ std::vector<ServerSplitterDestinationData> datas{};
+
+ std::size_t info_count{};
+ std::size_t data_count{};
+ bool bug_fixed{};
+};
+} // namespace AudioCore
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 7be5d5087..4bbb1e0c4 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -12,7 +12,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core_timing.h"
-#include "core/core_timing_util.h"
#include "core/settings.h"
namespace AudioCore {
@@ -104,11 +103,7 @@ void Stream::PlayNextBuffer(std::chrono::nanoseconds ns_late) {
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
- const auto time_stretch_delta = Settings::values.enable_audio_stretching.GetValue()
- ? std::chrono::nanoseconds::zero()
- : ns_late;
- const auto future_time = GetBufferReleaseNS(*active_buffer) - time_stretch_delta;
- core_timing.ScheduleEvent(future_time, release_event, {});
+ core_timing.ScheduleEvent(GetBufferReleaseNS(*active_buffer) - ns_late, release_event, {});
}
void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) {
diff --git a/src/audio_core/voice_context.cpp b/src/audio_core/voice_context.cpp
new file mode 100644
index 000000000..c46ee55f1
--- /dev/null
+++ b/src/audio_core/voice_context.cpp
@@ -0,0 +1,529 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/behavior_info.h"
+#include "audio_core/voice_context.h"
+#include "core/memory.h"
+
+namespace AudioCore {
+
+ServerVoiceChannelResource::ServerVoiceChannelResource(s32 id) : id(id) {}
+ServerVoiceChannelResource::~ServerVoiceChannelResource() = default;
+
+bool ServerVoiceChannelResource::InUse() const {
+ return in_use;
+}
+
+float ServerVoiceChannelResource::GetCurrentMixVolumeAt(std::size_t i) const {
+ ASSERT(i < AudioCommon::MAX_MIX_BUFFERS);
+ return mix_volume.at(i);
+}
+
+float ServerVoiceChannelResource::GetLastMixVolumeAt(std::size_t i) const {
+ ASSERT(i < AudioCommon::MAX_MIX_BUFFERS);
+ return last_mix_volume.at(i);
+}
+
+void ServerVoiceChannelResource::Update(VoiceChannelResource::InParams& in_params) {
+ in_use = in_params.in_use;
+ // Update our mix volumes only if it's in use
+ if (in_params.in_use) {
+ mix_volume = in_params.mix_volume;
+ }
+}
+
+void ServerVoiceChannelResource::UpdateLastMixVolumes() {
+ last_mix_volume = mix_volume;
+}
+
+const std::array<float, AudioCommon::MAX_MIX_BUFFERS>&
+ServerVoiceChannelResource::GetCurrentMixVolume() const {
+ return mix_volume;
+}
+
+const std::array<float, AudioCommon::MAX_MIX_BUFFERS>&
+ServerVoiceChannelResource::GetLastMixVolume() const {
+ return last_mix_volume;
+}
+
+ServerVoiceInfo::ServerVoiceInfo() {
+ Initialize();
+}
+ServerVoiceInfo::~ServerVoiceInfo() = default;
+
+void ServerVoiceInfo::Initialize() {
+ in_params.in_use = false;
+ in_params.node_id = 0;
+ in_params.id = 0;
+ in_params.current_playstate = ServerPlayState::Stop;
+ in_params.priority = 255;
+ in_params.sample_rate = 0;
+ in_params.sample_format = SampleFormat::Invalid;
+ in_params.channel_count = 0;
+ in_params.pitch = 0.0f;
+ in_params.volume = 0.0f;
+ in_params.last_volume = 0.0f;
+ in_params.biquad_filter.fill({});
+ in_params.wave_buffer_count = 0;
+ in_params.wave_bufffer_head = 0;
+ in_params.mix_id = AudioCommon::NO_MIX;
+ in_params.splitter_info_id = AudioCommon::NO_SPLITTER;
+ in_params.additional_params_address = 0;
+ in_params.additional_params_size = 0;
+ in_params.is_new = false;
+ out_params.played_sample_count = 0;
+ out_params.wave_buffer_consumed = 0;
+ in_params.voice_drop_flag = false;
+ in_params.buffer_mapped = false;
+ in_params.wave_buffer_flush_request_count = 0;
+ in_params.was_biquad_filter_enabled.fill(false);
+
+ for (auto& wave_buffer : in_params.wave_buffer) {
+ wave_buffer.start_sample_offset = 0;
+ wave_buffer.end_sample_offset = 0;
+ wave_buffer.is_looping = false;
+ wave_buffer.end_of_stream = false;
+ wave_buffer.buffer_address = 0;
+ wave_buffer.buffer_size = 0;
+ wave_buffer.context_address = 0;
+ wave_buffer.context_size = 0;
+ wave_buffer.sent_to_dsp = true;
+ }
+
+ stored_samples.clear();
+}
+
+void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in,
+ BehaviorInfo& behavior_info) {
+ in_params.in_use = voice_in.is_in_use;
+ in_params.id = voice_in.id;
+ in_params.node_id = voice_in.node_id;
+ in_params.last_playstate = in_params.current_playstate;
+ switch (voice_in.play_state) {
+ case PlayState::Paused:
+ in_params.current_playstate = ServerPlayState::Paused;
+ break;
+ case PlayState::Stopped:
+ if (in_params.current_playstate != ServerPlayState::Stop) {
+ in_params.current_playstate = ServerPlayState::RequestStop;
+ }
+ break;
+ case PlayState::Started:
+ in_params.current_playstate = ServerPlayState::Play;
+ break;
+ default:
+ UNREACHABLE_MSG("Unknown playstate {}", voice_in.play_state);
+ break;
+ }
+
+ in_params.priority = voice_in.priority;
+ in_params.sorting_order = voice_in.sorting_order;
+ in_params.sample_rate = voice_in.sample_rate;
+ in_params.sample_format = voice_in.sample_format;
+ in_params.channel_count = voice_in.channel_count;
+ in_params.pitch = voice_in.pitch;
+ in_params.volume = voice_in.volume;
+ in_params.biquad_filter = voice_in.biquad_filter;
+ in_params.wave_buffer_count = voice_in.wave_buffer_count;
+ in_params.wave_bufffer_head = voice_in.wave_buffer_head;
+ if (behavior_info.IsFlushVoiceWaveBuffersSupported()) {
+ const auto in_request_count = in_params.wave_buffer_flush_request_count;
+ const auto voice_request_count = voice_in.wave_buffer_flush_request_count;
+ in_params.wave_buffer_flush_request_count =
+ static_cast<u8>(in_request_count + voice_request_count);
+ }
+ in_params.mix_id = voice_in.mix_id;
+ if (behavior_info.IsSplitterSupported()) {
+ in_params.splitter_info_id = voice_in.splitter_info_id;
+ } else {
+ in_params.splitter_info_id = AudioCommon::NO_SPLITTER;
+ }
+
+ std::memcpy(in_params.voice_channel_resource_id.data(),
+ voice_in.voice_channel_resource_ids.data(),
+ sizeof(s32) * in_params.voice_channel_resource_id.size());
+
+ if (behavior_info.IsVoicePlayedSampleCountResetAtLoopPointSupported()) {
+ in_params.behavior_flags.is_played_samples_reset_at_loop_point =
+ voice_in.behavior_flags.is_played_samples_reset_at_loop_point;
+ } else {
+ in_params.behavior_flags.is_played_samples_reset_at_loop_point.Assign(0);
+ }
+ if (behavior_info.IsVoicePitchAndSrcSkippedSupported()) {
+ in_params.behavior_flags.is_pitch_and_src_skipped =
+ voice_in.behavior_flags.is_pitch_and_src_skipped;
+ } else {
+ in_params.behavior_flags.is_pitch_and_src_skipped.Assign(0);
+ }
+
+ if (voice_in.is_voice_drop_flag_clear_requested) {
+ in_params.voice_drop_flag = false;
+ }
+
+ if (in_params.additional_params_address != voice_in.additional_params_address ||
+ in_params.additional_params_size != voice_in.additional_params_size) {
+ in_params.additional_params_address = voice_in.additional_params_address;
+ in_params.additional_params_size = voice_in.additional_params_size;
+ // TODO(ogniK): Reattach buffer, do we actually need to? Maybe just signal to the DSP that
+ // our context is new
+ }
+}
+
+void ServerVoiceInfo::UpdateWaveBuffers(
+ const VoiceInfo::InParams& voice_in,
+ std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states,
+ BehaviorInfo& behavior_info) {
+ if (voice_in.is_new) {
+ // Initialize our wave buffers
+ for (auto& wave_buffer : in_params.wave_buffer) {
+ wave_buffer.start_sample_offset = 0;
+ wave_buffer.end_sample_offset = 0;
+ wave_buffer.is_looping = false;
+ wave_buffer.end_of_stream = false;
+ wave_buffer.buffer_address = 0;
+ wave_buffer.buffer_size = 0;
+ wave_buffer.context_address = 0;
+ wave_buffer.context_size = 0;
+ wave_buffer.sent_to_dsp = true;
+ }
+
+ // Mark all our wave buffers as invalid
+ for (std::size_t channel = 0; channel < static_cast<std::size_t>(in_params.channel_count);
+ channel++) {
+ for (auto& is_valid : voice_states[channel]->is_wave_buffer_valid) {
+ is_valid = false;
+ }
+ }
+ }
+
+ // Update our wave buffers
+ for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; i++) {
+ // Assume that we have at least 1 channel voice state
+ const auto have_valid_wave_buffer = voice_states[0]->is_wave_buffer_valid[i];
+
+ UpdateWaveBuffer(in_params.wave_buffer[i], voice_in.wave_buffer[i], in_params.sample_format,
+ have_valid_wave_buffer, behavior_info);
+ }
+}
+
+void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
+ const WaveBuffer& in_wave_buffer, SampleFormat sample_format,
+ bool is_buffer_valid, BehaviorInfo& behavior_info) {
+ if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) {
+ out_wavebuffer.buffer_address = 0;
+ out_wavebuffer.buffer_size = 0;
+ }
+
+ if (!in_wave_buffer.sent_to_server || !in_params.buffer_mapped) {
+ // Validate sample offset sizings
+ if (sample_format == SampleFormat::Pcm16) {
+ const auto buffer_size = in_wave_buffer.buffer_size;
+ if (in_wave_buffer.start_sample_offset < 0 || in_wave_buffer.end_sample_offset < 0 ||
+ (buffer_size < (sizeof(s16) * in_wave_buffer.start_sample_offset)) ||
+ (buffer_size < (sizeof(s16) * in_wave_buffer.end_sample_offset))) {
+ // TODO(ogniK): Write error info
+ return;
+ }
+ }
+ // TODO(ogniK): ADPCM Size error
+
+ out_wavebuffer.sent_to_dsp = false;
+ out_wavebuffer.start_sample_offset = in_wave_buffer.start_sample_offset;
+ out_wavebuffer.end_sample_offset = in_wave_buffer.end_sample_offset;
+ out_wavebuffer.is_looping = in_wave_buffer.is_looping;
+ out_wavebuffer.end_of_stream = in_wave_buffer.end_of_stream;
+
+ out_wavebuffer.buffer_address = in_wave_buffer.buffer_address;
+ out_wavebuffer.buffer_size = in_wave_buffer.buffer_size;
+ out_wavebuffer.context_address = in_wave_buffer.context_address;
+ out_wavebuffer.context_size = in_wave_buffer.context_size;
+ in_params.buffer_mapped =
+ in_wave_buffer.buffer_address != 0 && in_wave_buffer.buffer_size != 0;
+ // TODO(ogniK): Pool mapper attachment
+ // TODO(ogniK): IsAdpcmLoopContextBugFixed
+ }
+}
+
+void ServerVoiceInfo::WriteOutStatus(
+ VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in,
+ std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states) {
+ if (voice_in.is_new) {
+ in_params.is_new = true;
+ voice_out.wave_buffer_consumed = 0;
+ voice_out.played_sample_count = 0;
+ voice_out.voice_dropped = false;
+ } else if (!in_params.is_new) {
+ voice_out.wave_buffer_consumed = voice_states[0]->wave_buffer_consumed;
+ voice_out.played_sample_count = voice_states[0]->played_sample_count;
+ voice_out.voice_dropped = in_params.voice_drop_flag;
+ } else {
+ voice_out.wave_buffer_consumed = 0;
+ voice_out.played_sample_count = 0;
+ voice_out.voice_dropped = false;
+ }
+}
+
+const ServerVoiceInfo::InParams& ServerVoiceInfo::GetInParams() const {
+ return in_params;
+}
+
+ServerVoiceInfo::InParams& ServerVoiceInfo::GetInParams() {
+ return in_params;
+}
+
+const ServerVoiceInfo::OutParams& ServerVoiceInfo::GetOutParams() const {
+ return out_params;
+}
+
+ServerVoiceInfo::OutParams& ServerVoiceInfo::GetOutParams() {
+ return out_params;
+}
+
+bool ServerVoiceInfo::ShouldSkip() const {
+ // TODO(ogniK): Handle unmapped wave buffers or parameters
+ return !in_params.in_use || (in_params.wave_buffer_count == 0) || in_params.voice_drop_flag;
+}
+
+bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) {
+ std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT> dsp_voice_states{};
+ if (in_params.is_new) {
+ ResetResources(voice_context);
+ in_params.last_volume = in_params.volume;
+ in_params.is_new = false;
+ }
+
+ const s32 channel_count = in_params.channel_count;
+ for (s32 i = 0; i < channel_count; i++) {
+ const auto channel_resource = in_params.voice_channel_resource_id[i];
+ dsp_voice_states[i] =
+ &voice_context.GetDspSharedState(static_cast<std::size_t>(channel_resource));
+ }
+ return UpdateParametersForCommandGeneration(dsp_voice_states);
+}
+
+void ServerVoiceInfo::ResetResources(VoiceContext& voice_context) {
+ const s32 channel_count = in_params.channel_count;
+ for (s32 i = 0; i < channel_count; i++) {
+ const auto channel_resource = in_params.voice_channel_resource_id[i];
+ auto& dsp_state =
+ voice_context.GetDspSharedState(static_cast<std::size_t>(channel_resource));
+ dsp_state = {};
+ voice_context.GetChannelResource(static_cast<std::size_t>(channel_resource))
+ .UpdateLastMixVolumes();
+ }
+}
+
+bool ServerVoiceInfo::UpdateParametersForCommandGeneration(
+ std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states) {
+ const s32 channel_count = in_params.channel_count;
+ if (in_params.wave_buffer_flush_request_count > 0) {
+ FlushWaveBuffers(in_params.wave_buffer_flush_request_count, dsp_voice_states,
+ channel_count);
+ in_params.wave_buffer_flush_request_count = 0;
+ }
+
+ switch (in_params.current_playstate) {
+ case ServerPlayState::Play: {
+ for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; i++) {
+ if (!in_params.wave_buffer[i].sent_to_dsp) {
+ for (s32 channel = 0; channel < channel_count; channel++) {
+ dsp_voice_states[channel]->is_wave_buffer_valid[i] = true;
+ }
+ in_params.wave_buffer[i].sent_to_dsp = true;
+ }
+ }
+ in_params.should_depop = false;
+ return HasValidWaveBuffer(dsp_voice_states[0]);
+ }
+ case ServerPlayState::Paused:
+ case ServerPlayState::Stop: {
+ in_params.should_depop = in_params.last_playstate == ServerPlayState::Play;
+ return in_params.should_depop;
+ }
+ case ServerPlayState::RequestStop: {
+ for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; i++) {
+ in_params.wave_buffer[i].sent_to_dsp = true;
+ for (s32 channel = 0; channel < channel_count; channel++) {
+ auto* dsp_state = dsp_voice_states[channel];
+
+ if (dsp_state->is_wave_buffer_valid[i]) {
+ dsp_state->wave_buffer_index =
+ (dsp_state->wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS;
+ dsp_state->wave_buffer_consumed++;
+ }
+
+ dsp_state->is_wave_buffer_valid[i] = false;
+ }
+ }
+
+ for (s32 channel = 0; channel < channel_count; channel++) {
+ auto* dsp_state = dsp_voice_states[channel];
+ dsp_state->offset = 0;
+ dsp_state->played_sample_count = 0;
+ dsp_state->fraction = 0;
+ dsp_state->sample_history.fill(0);
+ dsp_state->context = {};
+ }
+
+ in_params.current_playstate = ServerPlayState::Stop;
+ in_params.should_depop = in_params.last_playstate == ServerPlayState::Play;
+ return in_params.should_depop;
+ }
+ default:
+ UNREACHABLE_MSG("Invalid playstate {}", in_params.current_playstate);
+ }
+
+ return false;
+}
+
+void ServerVoiceInfo::FlushWaveBuffers(
+ u8 flush_count, std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states,
+ s32 channel_count) {
+ auto wave_head = in_params.wave_bufffer_head;
+
+ for (u8 i = 0; i < flush_count; i++) {
+ in_params.wave_buffer[wave_head].sent_to_dsp = true;
+ for (s32 channel = 0; channel < channel_count; channel++) {
+ auto* dsp_state = dsp_voice_states[channel];
+ dsp_state->wave_buffer_consumed++;
+ dsp_state->is_wave_buffer_valid[wave_head] = false;
+ dsp_state->wave_buffer_index =
+ (dsp_state->wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS;
+ }
+ wave_head = (wave_head + 1) % AudioCommon::MAX_WAVE_BUFFERS;
+ }
+}
+
+bool ServerVoiceInfo::HasValidWaveBuffer(const VoiceState* state) const {
+ const auto& valid_wb = state->is_wave_buffer_valid;
+ return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end();
+}
+
+VoiceContext::VoiceContext(std::size_t voice_count) : voice_count(voice_count) {
+ for (std::size_t i = 0; i < voice_count; i++) {
+ voice_channel_resources.emplace_back(static_cast<s32>(i));
+ sorted_voice_info.push_back(&voice_info.emplace_back());
+ voice_states.emplace_back();
+ dsp_voice_states.emplace_back();
+ }
+}
+
+VoiceContext::~VoiceContext() {
+ sorted_voice_info.clear();
+}
+
+std::size_t VoiceContext::GetVoiceCount() const {
+ return voice_count;
+}
+
+ServerVoiceChannelResource& VoiceContext::GetChannelResource(std::size_t i) {
+ ASSERT(i < voice_count);
+ return voice_channel_resources.at(i);
+}
+
+const ServerVoiceChannelResource& VoiceContext::GetChannelResource(std::size_t i) const {
+ ASSERT(i < voice_count);
+ return voice_channel_resources.at(i);
+}
+
+VoiceState& VoiceContext::GetState(std::size_t i) {
+ ASSERT(i < voice_count);
+ return voice_states.at(i);
+}
+
+const VoiceState& VoiceContext::GetState(std::size_t i) const {
+ ASSERT(i < voice_count);
+ return voice_states.at(i);
+}
+
+VoiceState& VoiceContext::GetDspSharedState(std::size_t i) {
+ ASSERT(i < voice_count);
+ return dsp_voice_states.at(i);
+}
+
+const VoiceState& VoiceContext::GetDspSharedState(std::size_t i) const {
+ ASSERT(i < voice_count);
+ return dsp_voice_states.at(i);
+}
+
+ServerVoiceInfo& VoiceContext::GetInfo(std::size_t i) {
+ ASSERT(i < voice_count);
+ return voice_info.at(i);
+}
+
+const ServerVoiceInfo& VoiceContext::GetInfo(std::size_t i) const {
+ ASSERT(i < voice_count);
+ return voice_info.at(i);
+}
+
+ServerVoiceInfo& VoiceContext::GetSortedInfo(std::size_t i) {
+ ASSERT(i < voice_count);
+ return *sorted_voice_info.at(i);
+}
+
+const ServerVoiceInfo& VoiceContext::GetSortedInfo(std::size_t i) const {
+ ASSERT(i < voice_count);
+ return *sorted_voice_info.at(i);
+}
+
+s32 VoiceContext::DecodePcm16(s32* output_buffer, ServerWaveBuffer* wave_buffer, s32 channel,
+ s32 channel_count, s32 buffer_offset, s32 sample_count,
+ Core::Memory::Memory& memory) {
+ if (wave_buffer->buffer_address == 0) {
+ return 0;
+ }
+ if (wave_buffer->buffer_size == 0) {
+ return 0;
+ }
+ if (wave_buffer->end_sample_offset < wave_buffer->start_sample_offset) {
+ return 0;
+ }
+
+ const auto samples_remaining =
+ (wave_buffer->end_sample_offset - wave_buffer->start_sample_offset) - buffer_offset;
+ const auto start_offset = (wave_buffer->start_sample_offset + buffer_offset) * channel_count;
+ const auto buffer_pos = wave_buffer->buffer_address + start_offset;
+
+ s16* buffer_data = reinterpret_cast<s16*>(memory.GetPointer(buffer_pos));
+
+ const auto samples_processed = std::min(sample_count, samples_remaining);
+
+ // Fast path
+ if (channel_count == 1) {
+ for (std::ptrdiff_t i = 0; i < samples_processed; i++) {
+ output_buffer[i] = buffer_data[i];
+ }
+ } else {
+ for (std::ptrdiff_t i = 0; i < samples_processed; i++) {
+ output_buffer[i] = buffer_data[i * channel_count + channel];
+ }
+ }
+
+ return samples_processed;
+}
+
+void VoiceContext::SortInfo() {
+ for (std::size_t i = 0; i < voice_count; i++) {
+ sorted_voice_info[i] = &voice_info[i];
+ }
+
+ std::sort(sorted_voice_info.begin(), sorted_voice_info.end(),
+ [](const ServerVoiceInfo* lhs, const ServerVoiceInfo* rhs) {
+ const auto& lhs_in = lhs->GetInParams();
+ const auto& rhs_in = rhs->GetInParams();
+ // Sort by priority
+ if (lhs_in.priority != rhs_in.priority) {
+ return lhs_in.priority > rhs_in.priority;
+ } else {
+ // If the priorities match, sort by sorting order
+ return lhs_in.sorting_order > rhs_in.sorting_order;
+ }
+ });
+}
+
+void VoiceContext::UpdateStateByDspShared() {
+ voice_states = dsp_voice_states;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/voice_context.h b/src/audio_core/voice_context.h
new file mode 100644
index 000000000..59d3d7dfb
--- /dev/null
+++ b/src/audio_core/voice_context.h
@@ -0,0 +1,296 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include "audio_core/algorithm/interpolate.h"
+#include "audio_core/codec.h"
+#include "audio_core/common.h"
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Core::Memory {
+class Memory;
+}
+
+namespace AudioCore {
+
+class BehaviorInfo;
+class VoiceContext;
+
+enum class SampleFormat : u8 {
+ Invalid = 0,
+ Pcm8 = 1,
+ Pcm16 = 2,
+ Pcm24 = 3,
+ Pcm32 = 4,
+ PcmFloat = 5,
+ Adpcm = 6,
+};
+
+enum class PlayState : u8 {
+ Started = 0,
+ Stopped = 1,
+ Paused = 2,
+};
+
+enum class ServerPlayState {
+ Play = 0,
+ Stop = 1,
+ RequestStop = 2,
+ Paused = 3,
+};
+
+struct BiquadFilterParameter {
+ bool enabled{};
+ INSERT_PADDING_BYTES(1);
+ std::array<s16, 3> numerator{};
+ std::array<s16, 2> denominator{};
+};
+static_assert(sizeof(BiquadFilterParameter) == 0xc, "BiquadFilterParameter is an invalid size");
+
+struct WaveBuffer {
+ u64_le buffer_address{};
+ u64_le buffer_size{};
+ s32_le start_sample_offset{};
+ s32_le end_sample_offset{};
+ u8 is_looping{};
+ u8 end_of_stream{};
+ u8 sent_to_server{};
+ INSERT_PADDING_BYTES(5);
+ u64 context_address{};
+ u64 context_size{};
+ INSERT_PADDING_BYTES(8);
+};
+static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer is an invalid size");
+
+struct ServerWaveBuffer {
+ VAddr buffer_address{};
+ std::size_t buffer_size{};
+ s32 start_sample_offset{};
+ s32 end_sample_offset{};
+ bool is_looping{};
+ bool end_of_stream{};
+ VAddr context_address{};
+ std::size_t context_size{};
+ bool sent_to_dsp{true};
+};
+
+struct BehaviorFlags {
+ BitField<0, 1, u16> is_played_samples_reset_at_loop_point;
+ BitField<1, 1, u16> is_pitch_and_src_skipped;
+};
+static_assert(sizeof(BehaviorFlags) == 0x4, "BehaviorFlags is an invalid size");
+
+struct ADPCMContext {
+ u16 header{};
+ s16 yn1{};
+ s16 yn2{};
+};
+static_assert(sizeof(ADPCMContext) == 0x6, "ADPCMContext is an invalid size");
+
+struct VoiceState {
+ s64 played_sample_count{};
+ s32 offset{};
+ s32 wave_buffer_index{};
+ std::array<bool, AudioCommon::MAX_WAVE_BUFFERS> is_wave_buffer_valid{};
+ s32 wave_buffer_consumed{};
+ std::array<s32, AudioCommon::MAX_SAMPLE_HISTORY> sample_history{};
+ s32 fraction{};
+ VAddr context_address{};
+ Codec::ADPCM_Coeff coeff{};
+ ADPCMContext context{};
+ std::array<s64, 2> biquad_filter_state{};
+ std::array<s32, AudioCommon::MAX_MIX_BUFFERS> previous_samples{};
+ u32 external_context_size{};
+ bool is_external_context_used{};
+ bool voice_dropped{};
+};
+
+class VoiceChannelResource {
+public:
+ struct InParams {
+ s32_le id{};
+ std::array<float_le, AudioCommon::MAX_MIX_BUFFERS> mix_volume{};
+ bool in_use{};
+ INSERT_PADDING_BYTES(11);
+ };
+ static_assert(sizeof(VoiceChannelResource::InParams) == 0x70, "InParams is an invalid size");
+};
+
+class ServerVoiceChannelResource {
+public:
+ explicit ServerVoiceChannelResource(s32 id);
+ ~ServerVoiceChannelResource();
+
+ bool InUse() const;
+ float GetCurrentMixVolumeAt(std::size_t i) const;
+ float GetLastMixVolumeAt(std::size_t i) const;
+ void Update(VoiceChannelResource::InParams& in_params);
+ void UpdateLastMixVolumes();
+
+ const std::array<float, AudioCommon::MAX_MIX_BUFFERS>& GetCurrentMixVolume() const;
+ const std::array<float, AudioCommon::MAX_MIX_BUFFERS>& GetLastMixVolume() const;
+
+private:
+ s32 id{};
+ std::array<float, AudioCommon::MAX_MIX_BUFFERS> mix_volume{};
+ std::array<float, AudioCommon::MAX_MIX_BUFFERS> last_mix_volume{};
+ bool in_use{};
+};
+
+class VoiceInfo {
+public:
+ struct InParams {
+ s32_le id{};
+ u32_le node_id{};
+ u8 is_new{};
+ u8 is_in_use{};
+ PlayState play_state{};
+ SampleFormat sample_format{};
+ s32_le sample_rate{};
+ s32_le priority{};
+ s32_le sorting_order{};
+ s32_le channel_count{};
+ float_le pitch{};
+ float_le volume{};
+ std::array<BiquadFilterParameter, 2> biquad_filter{};
+ s32_le wave_buffer_count{};
+ s16_le wave_buffer_head{};
+ INSERT_PADDING_BYTES(6);
+ u64_le additional_params_address{};
+ u64_le additional_params_size{};
+ s32_le mix_id{};
+ s32_le splitter_info_id{};
+ std::array<WaveBuffer, 4> wave_buffer{};
+ std::array<u32_le, 6> voice_channel_resource_ids{};
+ // TODO(ogniK): Remaining flags
+ u8 is_voice_drop_flag_clear_requested{};
+ u8 wave_buffer_flush_request_count{};
+ INSERT_PADDING_BYTES(2);
+ BehaviorFlags behavior_flags{};
+ INSERT_PADDING_BYTES(16);
+ };
+ static_assert(sizeof(VoiceInfo::InParams) == 0x170, "InParams is an invalid size");
+
+ struct OutParams {
+ u64_le played_sample_count{};
+ u32_le wave_buffer_consumed{};
+ u8 voice_dropped{};
+ INSERT_PADDING_BYTES(3);
+ };
+ static_assert(sizeof(VoiceInfo::OutParams) == 0x10, "OutParams is an invalid size");
+};
+
+class ServerVoiceInfo {
+public:
+ struct InParams {
+ bool in_use{};
+ bool is_new{};
+ bool should_depop{};
+ SampleFormat sample_format{};
+ s32 sample_rate{};
+ s32 channel_count{};
+ s32 id{};
+ s32 node_id{};
+ s32 mix_id{};
+ ServerPlayState current_playstate{};
+ ServerPlayState last_playstate{};
+ s32 priority{};
+ s32 sorting_order{};
+ float pitch{};
+ float volume{};
+ float last_volume{};
+ std::array<BiquadFilterParameter, AudioCommon::MAX_BIQUAD_FILTERS> biquad_filter{};
+ s32 wave_buffer_count{};
+ s16 wave_bufffer_head{};
+ INSERT_PADDING_BYTES(2);
+ BehaviorFlags behavior_flags{};
+ VAddr additional_params_address{};
+ std::size_t additional_params_size{};
+ std::array<ServerWaveBuffer, AudioCommon::MAX_WAVE_BUFFERS> wave_buffer{};
+ std::array<s32, AudioCommon::MAX_CHANNEL_COUNT> voice_channel_resource_id{};
+ s32 splitter_info_id{};
+ u8 wave_buffer_flush_request_count{};
+ bool voice_drop_flag{};
+ bool buffer_mapped{};
+ std::array<bool, AudioCommon::MAX_BIQUAD_FILTERS> was_biquad_filter_enabled{};
+ };
+
+ struct OutParams {
+ s64 played_sample_count{};
+ s32 wave_buffer_consumed{};
+ };
+
+ ServerVoiceInfo();
+ ~ServerVoiceInfo();
+ void Initialize();
+ void UpdateParameters(const VoiceInfo::InParams& voice_in, BehaviorInfo& behavior_info);
+ void UpdateWaveBuffers(const VoiceInfo::InParams& voice_in,
+ std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states,
+ BehaviorInfo& behavior_info);
+ void UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer, const WaveBuffer& in_wave_buffer,
+ SampleFormat sample_format, bool is_buffer_valid,
+ BehaviorInfo& behavior_info);
+ void WriteOutStatus(VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in,
+ std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states);
+
+ const InParams& GetInParams() const;
+ InParams& GetInParams();
+
+ const OutParams& GetOutParams() const;
+ OutParams& GetOutParams();
+
+ bool ShouldSkip() const;
+ bool UpdateForCommandGeneration(VoiceContext& voice_context);
+ void ResetResources(VoiceContext& voice_context);
+ bool UpdateParametersForCommandGeneration(
+ std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states);
+ void FlushWaveBuffers(u8 flush_count,
+ std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states,
+ s32 channel_count);
+
+private:
+ std::vector<s16> stored_samples;
+ InParams in_params{};
+ OutParams out_params{};
+
+ bool HasValidWaveBuffer(const VoiceState* state) const;
+};
+
+class VoiceContext {
+public:
+ VoiceContext(std::size_t voice_count);
+ ~VoiceContext();
+
+ std::size_t GetVoiceCount() const;
+ ServerVoiceChannelResource& GetChannelResource(std::size_t i);
+ const ServerVoiceChannelResource& GetChannelResource(std::size_t i) const;
+ VoiceState& GetState(std::size_t i);
+ const VoiceState& GetState(std::size_t i) const;
+ VoiceState& GetDspSharedState(std::size_t i);
+ const VoiceState& GetDspSharedState(std::size_t i) const;
+ ServerVoiceInfo& GetInfo(std::size_t i);
+ const ServerVoiceInfo& GetInfo(std::size_t i) const;
+ ServerVoiceInfo& GetSortedInfo(std::size_t i);
+ const ServerVoiceInfo& GetSortedInfo(std::size_t i) const;
+
+ s32 DecodePcm16(s32* output_buffer, ServerWaveBuffer* wave_buffer, s32 channel,
+ s32 channel_count, s32 buffer_offset, s32 sample_count,
+ Core::Memory::Memory& memory);
+ void SortInfo();
+ void UpdateStateByDspShared();
+
+private:
+ std::size_t voice_count{};
+ std::vector<ServerVoiceChannelResource> voice_channel_resources{};
+ std::vector<VoiceState> voice_states{};
+ std::vector<VoiceState> dsp_voice_states{};
+ std::vector<ServerVoiceInfo> voice_info{};
+ std::vector<ServerVoiceInfo*> sorted_voice_info{};
+};
+
+} // namespace AudioCore
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 78c3bfb3b..0fb5d9708 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -172,7 +172,6 @@ add_library(common STATIC
virtual_buffer.h
wall_clock.cpp
wall_clock.h
- web_result.h
zstd_compression.cpp
zstd_compression.h
)
@@ -193,4 +192,9 @@ create_target_directory_groups(common)
find_package(Boost 1.71 COMPONENTS context headers REQUIRED)
target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile)
-target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd xbyak)
+target_link_libraries(common PRIVATE lz4::lz4 xbyak)
+if (MSVC)
+ target_link_libraries(common PRIVATE zstd::zstd)
+else()
+ target_link_libraries(common PRIVATE zstd)
+endif()
diff --git a/src/common/assert.h b/src/common/assert.h
index 5b67c5c52..06d7b5612 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -17,11 +17,12 @@
// enough for our purposes.
template <typename Fn>
#if defined(_MSC_VER)
-__declspec(noinline, noreturn)
+[[msvc::noinline, noreturn]]
#elif defined(__GNUC__)
- __attribute__((noinline, noreturn, cold))
+[[gnu::cold, gnu::noinline, noreturn]]
#endif
- static void assert_noinline_call(const Fn& fn) {
+static void
+assert_noinline_call(const Fn& fn) {
fn();
Crash();
exit(1); // Keeps GCC's mouth shut about this actually returning
diff --git a/src/common/color.h b/src/common/color.h
index 381d6332e..bbcac858e 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -10,7 +10,7 @@
#include "common/swap.h"
#include "common/vector_math.h"
-namespace Color {
+namespace Common::Color {
/// Convert a 1-bit color component to 8 bit
[[nodiscard]] constexpr u8 Convert1To8(u8 value) {
@@ -268,4 +268,4 @@ inline void EncodeX24S8(u8 stencil, u8* bytes) {
bytes[3] = stencil;
}
-} // namespace Color
+} // namespace Common::Color
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 98421bced..367b6bf6e 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -64,14 +64,20 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
} \
- constexpr type& operator|=(type& a, type b) noexcept { \
+ [[nodiscard]] constexpr type operator^(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
- a = static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \
+ return static_cast<type>(static_cast<T>(a) ^ static_cast<T>(b)); \
+ } \
+ constexpr type& operator|=(type& a, type b) noexcept { \
+ a = a | b; \
return a; \
} \
constexpr type& operator&=(type& a, type b) noexcept { \
- using T = std::underlying_type_t<type>; \
- a = static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
+ a = a & b; \
+ return a; \
+ } \
+ constexpr type& operator^=(type& a, type b) noexcept { \
+ a = a ^ b; \
return a; \
} \
[[nodiscard]] constexpr type operator~(type key) noexcept { \
diff --git a/src/common/hex_util.h b/src/common/hex_util.h
index 120f1a5e6..a8d414fb8 100644
--- a/src/common/hex_util.h
+++ b/src/common/hex_util.h
@@ -16,14 +16,14 @@ namespace Common {
[[nodiscard]] constexpr u8 ToHexNibble(char c) {
if (c >= 65 && c <= 70) {
- return c - 55;
+ return static_cast<u8>(c - 55);
}
if (c >= 97 && c <= 102) {
- return c - 87;
+ return static_cast<u8>(c - 87);
}
- return c - 48;
+ return static_cast<u8>(c - 48);
}
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
@@ -33,11 +33,11 @@ template <std::size_t Size, bool le = false>
std::array<u8, Size> out{};
if constexpr (le) {
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
- out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
+ out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
}
} else {
for (std::size_t i = 0; i < 2 * Size; i += 2) {
- out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
+ out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
}
}
return out;
diff --git a/src/common/math_util.h b/src/common/math_util.h
index cc35c90ee..7cec80d57 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -9,7 +9,7 @@
namespace Common {
-constexpr float PI = 3.14159265f;
+constexpr float PI = 3.1415926535f;
template <class T>
struct Rectangle {
@@ -20,8 +20,8 @@ struct Rectangle {
constexpr Rectangle() = default;
- constexpr Rectangle(T left, T top, T right, T bottom)
- : left(left), top(top), right(right), bottom(bottom) {}
+ constexpr Rectangle(T left_, T top_, T right_, T bottom_)
+ : left(left_), top(top_), right(right_), bottom(bottom_) {}
[[nodiscard]] T GetWidth() const {
if constexpr (std::is_floating_point_v<T>) {
diff --git a/src/common/param_package.h b/src/common/param_package.h
index c8a70bfa9..c13e45479 100644
--- a/src/common/param_package.h
+++ b/src/common/param_package.h
@@ -19,7 +19,7 @@ public:
explicit ParamPackage(const std::string& serialized);
ParamPackage(std::initializer_list<DataType::value_type> list);
ParamPackage(const ParamPackage& other) = default;
- ParamPackage(ParamPackage&& other) = default;
+ ParamPackage(ParamPackage&& other) noexcept = default;
ParamPackage& operator=(const ParamPackage& other) = default;
ParamPackage& operator=(ParamPackage&& other) = default;
diff --git a/src/common/quaternion.h b/src/common/quaternion.h
index da44f35cd..4d0871eb4 100644
--- a/src/common/quaternion.h
+++ b/src/common/quaternion.h
@@ -36,6 +36,36 @@ public:
T length = std::sqrt(xyz.Length2() + w * w);
return {xyz / length, w / length};
}
+
+ [[nodiscard]] std::array<decltype(-T{}), 16> ToMatrix() const {
+ const T x2 = xyz[0] * xyz[0];
+ const T y2 = xyz[1] * xyz[1];
+ const T z2 = xyz[2] * xyz[2];
+
+ const T xy = xyz[0] * xyz[1];
+ const T wz = w * xyz[2];
+ const T xz = xyz[0] * xyz[2];
+ const T wy = w * xyz[1];
+ const T yz = xyz[1] * xyz[2];
+ const T wx = w * xyz[0];
+
+ return {1.0f - 2.0f * (y2 + z2),
+ 2.0f * (xy + wz),
+ 2.0f * (xz - wy),
+ 0.0f,
+ 2.0f * (xy - wz),
+ 1.0f - 2.0f * (x2 + z2),
+ 2.0f * (yz + wx),
+ 0.0f,
+ 2.0f * (xz + wy),
+ 2.0f * (yz - wx),
+ 1.0f - 2.0f * (x2 + y2),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f};
+ }
};
template <typename T>
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 8e5935e6a..d2c1ac60d 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/common_funcs.h"
+#include "common/logging/log.h"
#include "common/thread.h"
#ifdef __APPLE__
#include <mach/mach.h>
@@ -19,6 +21,8 @@
#include <unistd.h>
#endif
+#include <string>
+
#ifdef __FreeBSD__
#define cpu_set_t cpuset_t
#endif
@@ -110,6 +114,14 @@ void SetCurrentThreadName(const char* name) {
pthread_set_name_np(pthread_self(), name);
#elif defined(__NetBSD__)
pthread_setname_np(pthread_self(), "%s", (void*)name);
+#elif defined(__linux__)
+ // Linux limits thread names to 15 characters and will outright reject any
+ // attempt to set a longer name with ERANGE.
+ std::string truncated(name, std::min(strlen(name), static_cast<size_t>(15)));
+ if (int e = pthread_setname_np(pthread_self(), truncated.c_str())) {
+ errno = e;
+ LOG_ERROR(Common, "Failed to set thread name to '{}': {}", truncated, GetLastErrorMsg());
+ }
#else
pthread_setname_np(pthread_self(), name);
#endif
diff --git a/src/common/thread.h b/src/common/thread.h
index 52b359413..a8c17c71a 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -4,6 +4,7 @@
#pragma once
+#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstddef>
@@ -25,13 +26,13 @@ public:
void Wait() {
std::unique_lock lk{mutex};
- condvar.wait(lk, [&] { return is_set; });
+ condvar.wait(lk, [&] { return is_set.load(); });
is_set = false;
}
bool WaitFor(const std::chrono::nanoseconds& time) {
std::unique_lock lk{mutex};
- if (!condvar.wait_for(lk, time, [this] { return is_set; }))
+ if (!condvar.wait_for(lk, time, [this] { return is_set.load(); }))
return false;
is_set = false;
return true;
@@ -40,7 +41,7 @@ public:
template <class Clock, class Duration>
bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) {
std::unique_lock lk{mutex};
- if (!condvar.wait_until(lk, time, [this] { return is_set; }))
+ if (!condvar.wait_until(lk, time, [this] { return is_set.load(); }))
return false;
is_set = false;
return true;
@@ -54,9 +55,9 @@ public:
}
private:
- bool is_set = false;
std::condition_variable condvar;
std::mutex mutex;
+ std::atomic_bool is_set{false};
};
class Barrier {
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 2a0fcf541..22dba3c2d 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -87,7 +87,13 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
- return {x * f, y * f};
+ using TV = decltype(T{} * V{});
+ using C = std::common_type_t<T, V>;
+
+ return {
+ static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
+ };
}
template <typename V>
@@ -98,7 +104,13 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
- return {x / f, y / f};
+ using TV = decltype(T{} / V{});
+ using C = std::common_type_t<T, V>;
+
+ return {
+ static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
+ };
}
template <typename V>
@@ -168,7 +180,10 @@ public:
template <typename T, typename V>
[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
- return Vec2<T>(f * vec.x, f * vec.y);
+ using C = std::common_type_t<T, V>;
+
+ return Vec2<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
+ static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)));
}
using Vec2f = Vec2<float>;
@@ -237,7 +252,14 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
- return {x * f, y * f, z * f};
+ using TV = decltype(T{} * V{});
+ using C = std::common_type_t<T, V>;
+
+ return {
+ static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
+ };
}
template <typename V>
@@ -247,7 +269,14 @@ public:
}
template <typename V>
[[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
- return {x / f, y / f, z / f};
+ using TV = decltype(T{} / V{});
+ using C = std::common_type_t<T, V>;
+
+ return {
+ static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
+ };
}
template <typename V>
@@ -367,7 +396,11 @@ public:
template <typename T, typename V>
[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
- return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
+ using C = std::common_type_t<T, V>;
+
+ return Vec3<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
+ static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)),
+ static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.z)));
}
template <>
@@ -446,7 +479,15 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
- return {x * f, y * f, z * f, w * f};
+ using TV = decltype(T{} * V{});
+ using C = std::common_type_t<T, V>;
+
+ return {
+ static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(w) * static_cast<C>(f)),
+ };
}
template <typename V>
@@ -457,7 +498,15 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
- return {x / f, y / f, z / f, w / f};
+ using TV = decltype(T{} / V{});
+ using C = std::common_type_t<T, V>;
+
+ return {
+ static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
+ static_cast<TV>(static_cast<C>(w) / static_cast<C>(f)),
+ };
}
template <typename V>
@@ -582,7 +631,15 @@ public:
template <typename T, typename V>
[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
- return {f * vec.x, f * vec.y, f * vec.z, f * vec.w};
+ using TV = decltype(V{} * T{});
+ using C = std::common_type_t<T, V>;
+
+ return {
+ static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.x)),
+ static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.y)),
+ static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.z)),
+ static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.w)),
+ };
}
using Vec4f = Vec4<float>;
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index 3afbdb898..7a20e95b7 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -15,7 +15,7 @@ namespace Common {
using base_timer = std::chrono::steady_clock;
using base_time_point = std::chrono::time_point<base_timer>;
-class StandardWallClock : public WallClock {
+class StandardWallClock final : public WallClock {
public:
StandardWallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency)
: WallClock(emulated_cpu_frequency, emulated_clock_frequency, false) {
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index 5db30083d..bc7adfbf8 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -13,6 +13,8 @@ namespace Common {
class WallClock {
public:
+ virtual ~WallClock() = default;
+
/// Returns current wall time in nanoseconds
[[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0;
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h
index 891a3bbfd..7c503df26 100644
--- a/src/common/x64/native_clock.h
+++ b/src/common/x64/native_clock.h
@@ -12,7 +12,7 @@
namespace Common {
namespace X64 {
-class NativeClock : public WallClock {
+class NativeClock final : public WallClock {
public:
NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, u64 rtsc_frequency);
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
index a5f5d4fc1..26e4bfda5 100644
--- a/src/common/x64/xbyak_abi.h
+++ b/src/common/x64/xbyak_abi.h
@@ -11,7 +11,7 @@
namespace Common::X64 {
-inline std::size_t RegToIndex(const Xbyak::Reg& reg) {
+constexpr std::size_t RegToIndex(const Xbyak::Reg& reg) {
using Kind = Xbyak::Reg::Kind;
ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
"RegSet only support GPRs and XMM registers.");
@@ -19,17 +19,17 @@ inline std::size_t RegToIndex(const Xbyak::Reg& reg) {
return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16);
}
-inline Xbyak::Reg64 IndexToReg64(std::size_t reg_index) {
+constexpr Xbyak::Reg64 IndexToReg64(std::size_t reg_index) {
ASSERT(reg_index < 16);
return Xbyak::Reg64(static_cast<int>(reg_index));
}
-inline Xbyak::Xmm IndexToXmm(std::size_t reg_index) {
+constexpr Xbyak::Xmm IndexToXmm(std::size_t reg_index) {
ASSERT(reg_index >= 16 && reg_index < 32);
return Xbyak::Xmm(static_cast<int>(reg_index - 16));
}
-inline Xbyak::Reg IndexToReg(std::size_t reg_index) {
+constexpr Xbyak::Reg IndexToReg(std::size_t reg_index) {
if (reg_index < 16) {
return IndexToReg64(reg_index);
} else {
@@ -45,17 +45,17 @@ inline std::bitset<32> BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
return bits;
}
-const std::bitset<32> ABI_ALL_GPRS(0x0000FFFF);
-const std::bitset<32> ABI_ALL_XMMS(0xFFFF0000);
+constexpr inline std::bitset<32> ABI_ALL_GPRS(0x0000FFFF);
+constexpr inline std::bitset<32> ABI_ALL_XMMS(0xFFFF0000);
#ifdef _WIN32
// Microsoft x64 ABI
-const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
-const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx;
-const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
-const Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
-const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
+constexpr inline Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
+constexpr inline Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx;
+constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
+constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
+constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
@@ -102,11 +102,11 @@ constexpr size_t ABI_SHADOW_SPACE = 0x20;
#else
// System V x86-64 ABI
-const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
-const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi;
-const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
-const Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
-const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
+constexpr inline Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
+constexpr inline Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi;
+constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
+constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
+constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c85c9485f..b6dc25f6b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1,9 +1,3 @@
-if (YUZU_ENABLE_BOXCAT)
- set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h)
-else()
- set(BCAT_BOXCAT_ADDITIONAL_SOURCES)
-endif()
-
add_library(core STATIC
arm/arm_interface.h
arm/arm_interface.cpp
@@ -126,6 +120,8 @@ add_library(core STATIC
file_sys/vfs_vector.h
file_sys/xts_archive.cpp
file_sys/xts_archive.h
+ frontend/applets/controller.cpp
+ frontend/applets/controller.h
frontend/applets/error.cpp
frontend/applets/error.h
frontend/applets/general_frontend.cpp
@@ -244,6 +240,8 @@ add_library(core STATIC
hle/service/am/applet_oe.h
hle/service/am/applets/applets.cpp
hle/service/am/applets/applets.h
+ hle/service/am/applets/controller.cpp
+ hle/service/am/applets/controller.h
hle/service/am/applets/error.cpp
hle/service/am/applets/error.h
hle/service/am/applets/general_backend.cpp
@@ -299,7 +297,6 @@ add_library(core STATIC
hle/service/audio/hwopus.h
hle/service/bcat/backend/backend.cpp
hle/service/bcat/backend/backend.h
- ${BCAT_BOXCAT_ADDITIONAL_SOURCES}
hle/service/bcat/bcat.cpp
hle/service/bcat/bcat.h
hle/service/bcat/module.cpp
@@ -491,6 +488,7 @@ add_library(core STATIC
hle/service/sm/controller.h
hle/service/sm/sm.cpp
hle/service/sm/sm.h
+ hle/service/sockets/blocking_worker.h
hle/service/sockets/bsd.cpp
hle/service/sockets/bsd.h
hle/service/sockets/ethc.cpp
@@ -501,6 +499,8 @@ add_library(core STATIC
hle/service/sockets/sfdnsres.h
hle/service/sockets/sockets.cpp
hle/service/sockets/sockets.h
+ hle/service/sockets/sockets_translate.cpp
+ hle/service/sockets/sockets_translate.h
hle/service/spl/csrng.cpp
hle/service/spl/csrng.h
hle/service/spl/module.cpp
@@ -601,6 +601,13 @@ add_library(core STATIC
tools/freezer.h
)
+if (YUZU_ENABLE_BOXCAT)
+ target_sources(core PRIVATE
+ hle/service/bcat/backend/boxcat.cpp
+ hle/service/bcat/backend/boxcat.h
+ )
+endif()
+
if (MSVC)
target_compile_options(core PRIVATE
# 'expression' : signed/unsigned mismatch
@@ -616,6 +623,17 @@ if (MSVC)
# 'context' : truncation from 'type1' to 'type2'
/we4305
)
+else()
+ target_compile_options(core PRIVATE
+ -Werror=conversion
+ -Werror=ignored-qualifiers
+ -Werror=implicit-fallthrough
+ -Werror=reorder
+ -Werror=sign-compare
+ -Werror=unused-but-set-parameter
+ -Werror=unused-but-set-variable
+ -Werror=unused-variable
+ )
endif()
create_target_directory_groups(core)
diff --git a/src/core/arm/cpu_interrupt_handler.cpp b/src/core/arm/cpu_interrupt_handler.cpp
index df0350881..9c8898700 100644
--- a/src/core/arm/cpu_interrupt_handler.cpp
+++ b/src/core/arm/cpu_interrupt_handler.cpp
@@ -7,9 +7,7 @@
namespace Core {
-CPUInterruptHandler::CPUInterruptHandler() : is_interrupted{} {
- interrupt_event = std::make_unique<Common::Event>();
-}
+CPUInterruptHandler::CPUInterruptHandler() : interrupt_event{std::make_unique<Common::Event>()} {}
CPUInterruptHandler::~CPUInterruptHandler() = default;
@@ -17,7 +15,7 @@ void CPUInterruptHandler::SetInterrupt(bool is_interrupted_) {
if (is_interrupted_) {
interrupt_event->Set();
}
- this->is_interrupted = is_interrupted_;
+ is_interrupted = is_interrupted_;
}
void CPUInterruptHandler::AwaitInterrupt() {
diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h
index 3d062d326..71e582f79 100644
--- a/src/core/arm/cpu_interrupt_handler.h
+++ b/src/core/arm/cpu_interrupt_handler.h
@@ -4,6 +4,7 @@
#pragma once
+#include <atomic>
#include <memory>
namespace Common {
@@ -32,8 +33,8 @@ public:
void AwaitInterrupt();
private:
- bool is_interrupted{};
std::unique_ptr<Common::Event> interrupt_event;
+ std::atomic_bool is_interrupted{false};
};
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 443ca72eb..b5f28a86e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -143,7 +143,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
config.wall_clock_cntpct = uses_wall_clock;
// Safe optimizations
- if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
+ if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
config.page_table = nullptr;
}
@@ -170,6 +170,17 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
}
}
+ // Unsafe optimizations
+ if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
+ config.unsafe_optimizations = true;
+ if (Settings::values.cpuopt_unsafe_unfuse_fma) {
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
+ }
+ if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
+ }
+ }
+
return std::make_unique<Dynarmic::A32::Jit>(config);
}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index a63a04a25..ce9968724 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -195,7 +195,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
config.wall_clock_cntpct = uses_wall_clock;
// Safe optimizations
- if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
+ if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
config.page_table = nullptr;
}
@@ -222,6 +222,17 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
}
}
+ // Unsafe optimizations
+ if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
+ config.unsafe_optimizations = true;
+ if (Settings::values.cpuopt_unsafe_unfuse_fma) {
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
+ }
+ if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
+ }
+ }
+
return std::make_shared<Dynarmic::A64::Jit>(config);
}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
index 54556e0f9..caefc09f4 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
@@ -34,7 +34,7 @@ std::optional<Callback> DynarmicCP15::CompileInternalOperation(bool two, unsigne
CoprocReg CRm, unsigned opc2) {
LOG_CRITICAL(Core_ARM, "CP15: cdp{} p15, {}, {}, {}, {}, {}", two ? "2" : "", opc1, CRd, CRn,
CRm, opc2);
- return {};
+ return std::nullopt;
}
CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn,
@@ -115,7 +115,7 @@ std::optional<Callback> DynarmicCP15::CompileLoadWords(bool two, bool long_trans
LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "",
long_transfer ? "l" : "", CRd);
}
- return {};
+ return std::nullopt;
}
std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd,
@@ -127,7 +127,7 @@ std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_tran
LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "",
long_transfer ? "l" : "", CRd);
}
- return {};
+ return std::nullopt;
}
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
index 7356d252e..dc6f4af3a 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
@@ -35,8 +35,8 @@ public:
std::optional<u8> option) override;
ARM_Dynarmic_32& parent;
- u32 uprw;
- u32 uro;
+ u32 uprw = 0;
+ u32 uro = 0;
};
} // namespace Core
diff --git a/src/core/core.cpp b/src/core/core.cpp
index c2c0eec0b..81e8cc338 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -178,7 +178,7 @@ struct System::Impl {
arp_manager.ResetAll();
telemetry_session = std::make_unique<Core::TelemetrySession>();
- service_manager = std::make_shared<Service::SM::ServiceManager>();
+ service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
Service::Init(service_manager, system);
GDBStub::DeferStart();
@@ -188,7 +188,6 @@ struct System::Impl {
if (!gpu_core) {
return ResultStatus::ErrorVideoCore;
}
- gpu_core->Renderer().Rasterizer().SetupDirtyFlags();
is_powered_on = true;
exit_lock = false;
@@ -222,7 +221,7 @@ struct System::Impl {
telemetry_session->AddInitialInfo(*app_loader);
auto main_process =
Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland);
- const auto [load_result, load_parameters] = app_loader->Load(*main_process);
+ const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
Shutdown();
@@ -630,11 +629,11 @@ Loader::AppLoader& System::GetAppLoader() const {
return *impl->app_loader;
}
-void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) {
+void System::SetFilesystem(FileSys::VirtualFilesystem vfs) {
impl->virtual_filesystem = std::move(vfs);
}
-std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
+FileSys::VirtualFilesystem System::GetFilesystem() const {
return impl->virtual_filesystem;
}
diff --git a/src/core/core.h b/src/core/core.h
index 5c6cfbffe..27efe30bb 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -120,7 +120,7 @@ public:
* Gets the instance of the System singleton class.
* @returns Reference to the instance of the System singleton class.
*/
- static System& GetInstance() {
+ [[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance() {
return s_instance;
}
@@ -316,9 +316,9 @@ public:
Service::SM::ServiceManager& ServiceManager();
const Service::SM::ServiceManager& ServiceManager() const;
- void SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs);
+ void SetFilesystem(FileSys::VirtualFilesystem vfs);
- std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
+ FileSys::VirtualFilesystem GetFilesystem() const;
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
const std::array<u8, 0x20>& build_id, VAddr main_region_begin,
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 71af26ec5..e6c8461a5 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -7,14 +7,14 @@
#include <string>
#include <tuple>
-#include "common/assert.h"
#include "common/microprofile.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
namespace Core::Timing {
-constexpr u64 MAX_SLICE_LENGTH = 4000;
+constexpr s64 MAX_SLICE_LENGTH = 4000;
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
return std::make_shared<EventType>(std::move(callback), std::move(name));
@@ -37,10 +37,8 @@ struct CoreTiming::Event {
}
};
-CoreTiming::CoreTiming() {
- clock =
- Common::CreateBestMatchingClock(Core::Hardware::BASE_CLOCK_RATE, Core::Hardware::CNTFREQ);
-}
+CoreTiming::CoreTiming()
+ : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
CoreTiming::~CoreTiming() = default;
@@ -136,7 +134,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
void CoreTiming::AddTicks(u64 ticks) {
this->ticks += ticks;
- downcount -= ticks;
+ downcount -= static_cast<s64>(ticks);
}
void CoreTiming::Idle() {
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp
index aefc63663..8ce8e602e 100644
--- a/src/core/core_timing_util.cpp
+++ b/src/core/core_timing_util.cpp
@@ -8,6 +8,7 @@
#include <limits>
#include "common/logging/log.h"
#include "common/uint128.h"
+#include "core/hardware_properties.h"
namespace Core::Timing {
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h
index 2ed979e14..e4a046bf9 100644
--- a/src/core/core_timing_util.h
+++ b/src/core/core_timing_util.h
@@ -6,7 +6,6 @@
#include <chrono>
#include "common/common_types.h"
-#include "core/hardware_properties.h"
namespace Core::Timing {
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 358943429..688b99eba 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -41,9 +41,9 @@ void CpuManager::Shutdown() {
running_mode = false;
Pause(false);
if (is_multicore) {
- for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
- core_data[core].host_thread->join();
- core_data[core].host_thread.reset();
+ for (auto& data : core_data) {
+ data.host_thread->join();
+ data.host_thread.reset();
}
} else {
core_data[0].host_thread->join();
@@ -166,25 +166,23 @@ void CpuManager::MultiCorePause(bool paused) {
bool all_not_barrier = false;
while (!all_not_barrier) {
all_not_barrier = true;
- for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
- all_not_barrier &=
- !core_data[core].is_running.load() && core_data[core].initialized.load();
+ for (const auto& data : core_data) {
+ all_not_barrier &= !data.is_running.load() && data.initialized.load();
}
}
- for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
- core_data[core].enter_barrier->Set();
+ for (auto& data : core_data) {
+ data.enter_barrier->Set();
}
if (paused_state.load()) {
bool all_barrier = false;
while (!all_barrier) {
all_barrier = true;
- for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
- all_barrier &=
- core_data[core].is_paused.load() && core_data[core].initialized.load();
+ for (const auto& data : core_data) {
+ all_barrier &= data.is_paused.load() && data.initialized.load();
}
}
- for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
- core_data[core].exit_barrier->Set();
+ for (auto& data : core_data) {
+ data.exit_barrier->Set();
}
}
} else {
@@ -192,9 +190,8 @@ void CpuManager::MultiCorePause(bool paused) {
bool all_barrier = false;
while (!all_barrier) {
all_barrier = true;
- for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
- all_barrier &=
- core_data[core].is_paused.load() && core_data[core].initialized.load();
+ for (const auto& data : core_data) {
+ all_barrier &= data.is_paused.load() && data.initialized.load();
}
}
/// Don't release the barrier
@@ -331,7 +328,7 @@ void CpuManager::RunThread(std::size_t core) {
system.RegisterCoreThread(core);
std::string name;
if (is_multicore) {
- name = "yuzu:CoreCPUThread_" + std::to_string(core);
+ name = "yuzu:CPUCore_" + std::to_string(core);
} else {
name = "yuzu:CPUThread";
}
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 8783d1ac2..da15f764a 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -23,7 +23,6 @@
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
-#include "core/core.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/key_manager.h"
#include "core/crypto/partition_data_manager.h"
@@ -36,6 +35,7 @@
#include "core/settings.h"
namespace Core::Crypto {
+namespace {
constexpr u64 CURRENT_CRYPTO_REVISION = 0x5;
constexpr u64 FULL_TICKET_SIZE = 0x400;
@@ -49,7 +49,72 @@ constexpr std::array eticket_source_hashes{
};
// clang-format on
-const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
+constexpr std::array<std::pair<std::string_view, KeyIndex<S128KeyType>>, 30> s128_file_id{{
+ {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
+ {"eticket_rsa_kek_source",
+ {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}},
+ {"eticket_rsa_kekek_source",
+ {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}},
+ {"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}},
+ {"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}},
+ {"rsa_oaep_kek_generation_source",
+ {S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}},
+ {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}},
+ {"aes_kek_generation_source",
+ {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}},
+ {"aes_key_generation_source",
+ {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}},
+ {"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}},
+ {"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}},
+ {"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}},
+ {"key_area_key_application_source",
+ {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
+ static_cast<u64>(KeyAreaKeyType::Application)}},
+ {"key_area_key_ocean_source",
+ {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
+ static_cast<u64>(KeyAreaKeyType::Ocean)}},
+ {"key_area_key_system_source",
+ {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
+ static_cast<u64>(KeyAreaKeyType::System)}},
+ {"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}},
+ {"keyblob_mac_key_source",
+ {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}},
+ {"tsec_key", {S128KeyType::TSEC, 0, 0}},
+ {"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}},
+ {"sd_seed", {S128KeyType::SDSeed, 0, 0}},
+ {"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}},
+ {"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}},
+ {"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}},
+ {"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}},
+ {"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}},
+ {"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}},
+ {"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}},
+ {"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}},
+ {"header_kek", {S128KeyType::HeaderKek, 0, 0}},
+ {"sd_card_kek", {S128KeyType::SDKek, 0, 0}},
+}};
+
+auto Find128ByName(std::string_view name) {
+ return std::find_if(s128_file_id.begin(), s128_file_id.end(),
+ [&name](const auto& pair) { return pair.first == name; });
+}
+
+constexpr std::array<std::pair<std::string_view, KeyIndex<S256KeyType>>, 6> s256_file_id{{
+ {"header_key", {S256KeyType::Header, 0, 0}},
+ {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}},
+ {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}},
+ {"header_key_source", {S256KeyType::HeaderSource, 0, 0}},
+ {"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}},
+ {"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}},
+}};
+
+auto Find256ByName(std::string_view name) {
+ return std::find_if(s256_file_id.begin(), s256_file_id.end(),
+ [&name](const auto& pair) { return pair.first == name; });
+}
+
+using KeyArray = std::array<std::pair<std::pair<S128KeyType, u64>, std::string_view>, 7>;
+constexpr KeyArray KEYS_VARIABLE_LENGTH{{
{{S128KeyType::Master, 0}, "master_key_"},
{{S128KeyType::Package1, 0}, "package1_key_"},
{{S128KeyType::Package2, 0}, "package2_key_"},
@@ -57,14 +122,13 @@ const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
{{S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob)}, "keyblob_key_source_"},
{{S128KeyType::Keyblob, 0}, "keyblob_key_"},
{{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"},
-};
+}};
-namespace {
template <std::size_t Size>
bool IsAllZeroArray(const std::array<u8, Size>& array) {
return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; });
}
-} // namespace
+} // Anonymous namespace
u64 GetSignatureTypeDataSize(SignatureType type) {
switch (type) {
@@ -347,7 +411,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
// Combine sources and seed
for (auto& source : sd_key_sources) {
for (std::size_t i = 0; i < source.size(); ++i) {
- source[i] ^= sd_seed[i & 0xF];
+ source[i] = static_cast<u8>(source[i] ^ sd_seed[i & 0xF]);
}
}
@@ -564,13 +628,13 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key;
} else {
out[0] = Common::ToLower(out[0]);
- if (s128_file_id.find(out[0]) != s128_file_id.end()) {
- const auto index = s128_file_id.at(out[0]);
- Key128 key = Common::HexStringToArray<16>(out[1]);
+ if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) {
+ const auto& index = iter128->second;
+ const Key128 key = Common::HexStringToArray<16>(out[1]);
s128_keys[{index.type, index.field1, index.field2}] = key;
- } else if (s256_file_id.find(out[0]) != s256_file_id.end()) {
- const auto index = s256_file_id.at(out[0]);
- Key256 key = Common::HexStringToArray<32>(out[1]);
+ } else if (const auto iter256 = Find256ByName(out[0]); iter256 != s256_file_id.end()) {
+ const auto& index = iter256->second;
+ const Key256 key = Common::HexStringToArray<32>(out[1]);
s256_keys[{index.type, index.field1, index.field2}] = key;
} else if (out[0].compare(0, 8, "keyblob_") == 0 &&
out[0].compare(0, 9, "keyblob_k") != 0) {
@@ -742,8 +806,7 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
}
const auto iter2 = std::find_if(
- s128_file_id.begin(), s128_file_id.end(),
- [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) {
+ s128_file_id.begin(), s128_file_id.end(), [&id, &field1, &field2](const auto& elem) {
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
std::tie(id, field1, field2);
});
@@ -753,9 +816,11 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
// Variable cases
if (id == S128KeyType::KeyArea) {
- static constexpr std::array<const char*, 3> kak_names = {"key_area_key_application_{:02X}",
- "key_area_key_ocean_{:02X}",
- "key_area_key_system_{:02X}"};
+ static constexpr std::array<const char*, 3> kak_names = {
+ "key_area_key_application_{:02X}",
+ "key_area_key_ocean_{:02X}",
+ "key_area_key_system_{:02X}",
+ };
WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key);
} else if (id == S128KeyType::Master) {
WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key);
@@ -781,8 +846,7 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
return;
}
const auto iter = std::find_if(
- s256_file_id.begin(), s256_file_id.end(),
- [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) {
+ s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const auto& elem) {
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
std::tie(id, field1, field2);
});
@@ -957,10 +1021,10 @@ void KeyManager::DeriveBase() {
}
}
-void KeyManager::DeriveETicket(PartitionDataManager& data) {
+void KeyManager::DeriveETicket(PartitionDataManager& data,
+ const FileSys::ContentProvider& provider) {
// ETicket keys
- const auto es = Core::System::GetInstance().GetContentProvider().GetEntry(
- 0x0100000000000033, FileSys::ContentRecordType::Program);
+ const auto es = provider.GetEntry(0x0100000000000033, FileSys::ContentRecordType::Program);
if (es == nullptr) {
return;
@@ -1245,58 +1309,4 @@ bool KeyManager::AddTicketPersonalized(Ticket raw) {
SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
return true;
}
-
-const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
- {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
- {"eticket_rsa_kek_source",
- {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}},
- {"eticket_rsa_kekek_source",
- {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}},
- {"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}},
- {"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}},
- {"rsa_oaep_kek_generation_source",
- {S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}},
- {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}},
- {"aes_kek_generation_source",
- {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}},
- {"aes_key_generation_source",
- {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}},
- {"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}},
- {"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}},
- {"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}},
- {"key_area_key_application_source",
- {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
- static_cast<u64>(KeyAreaKeyType::Application)}},
- {"key_area_key_ocean_source",
- {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
- static_cast<u64>(KeyAreaKeyType::Ocean)}},
- {"key_area_key_system_source",
- {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
- static_cast<u64>(KeyAreaKeyType::System)}},
- {"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}},
- {"keyblob_mac_key_source",
- {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}},
- {"tsec_key", {S128KeyType::TSEC, 0, 0}},
- {"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}},
- {"sd_seed", {S128KeyType::SDSeed, 0, 0}},
- {"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}},
- {"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}},
- {"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}},
- {"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}},
- {"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}},
- {"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}},
- {"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}},
- {"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}},
- {"header_kek", {S128KeyType::HeaderKek, 0, 0}},
- {"sd_card_kek", {S128KeyType::SDKek, 0, 0}},
-};
-
-const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = {
- {"header_key", {S256KeyType::Header, 0, 0}},
- {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}},
- {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}},
- {"header_key_source", {S256KeyType::HeaderSource, 0, 0}},
- {"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}},
- {"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}},
-};
} // namespace Core::Crypto
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index bdca3770a..0a7220286 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -10,7 +10,6 @@
#include <string>
#include <variant>
-#include <boost/container/flat_map.hpp>
#include <fmt/format.h>
#include "common/common_funcs.h"
#include "common/common_types.h"
@@ -21,6 +20,10 @@ namespace Common::FS {
class IOFile;
}
+namespace FileSys {
+class ContentProvider;
+}
+
namespace Loader {
enum class ResultStatus : u16;
}
@@ -253,7 +256,7 @@ public:
bool BaseDeriveNecessary() const;
void DeriveBase();
- void DeriveETicket(PartitionDataManager& data);
+ void DeriveETicket(PartitionDataManager& data, const FileSys::ContentProvider& provider);
void PopulateTickets();
void SynthesizeTickets();
@@ -293,9 +296,6 @@ private:
void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
-
- static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
- static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id;
};
Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed);
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
index 46136d04a..5f1c86a09 100644
--- a/src/core/crypto/partition_data_manager.cpp
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -26,6 +26,7 @@
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_offset.h"
#include "core/file_sys/vfs_vector.h"
+#include "core/loader/loader.h"
using Common::AsArray;
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 9ffda2e14..7c6304ff0 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -4,11 +4,10 @@
#include <fmt/format.h>
#include "common/file_util.h"
-#include "core/core.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/registered_cache.h"
-#include "core/settings.h"
+#include "core/file_sys/vfs.h"
namespace FileSys {
@@ -82,11 +81,11 @@ VirtualDir BISFactory::OpenPartition(BisPartitionId id) const {
}
}
-VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const {
+VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id,
+ VirtualFilesystem file_system) const {
auto& keys = Core::Crypto::KeyManager::Instance();
- Core::Crypto::PartitionDataManager pdm{
- Core::System::GetInstance().GetFilesystem()->OpenDirectory(
- Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)};
+ Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory(
+ Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)};
keys.PopulateFromPartitionData(pdm);
switch (id) {
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index 8f0451c98..136485881 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -6,7 +6,8 @@
#include <memory>
-#include "core/file_sys/vfs.h"
+#include "common/common_types.h"
+#include "core/file_sys/vfs_types.h"
namespace FileSys {
@@ -51,7 +52,7 @@ public:
VirtualDir GetModificationDumpRoot(u64 title_id) const;
VirtualDir OpenPartition(BisPartitionId id) const;
- VirtualFile OpenPartitionStorage(BisPartitionId id) const;
+ VirtualFile OpenPartitionStorage(BisPartitionId id, VirtualFilesystem file_system) const;
VirtualDir GetImageDirectory() const;
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 664a47e7f..956da68f7 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -8,11 +8,11 @@
#include <fmt/ostream.h>
#include "common/logging/log.h"
+#include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/partition_filesystem.h"
-#include "core/file_sys/romfs.h"
#include "core/file_sys/submission_package.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_offset.h"
@@ -31,7 +31,8 @@ constexpr std::array partition_names{
XCI::XCI(VirtualFile file_)
: file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
- partitions(partition_names.size()), partitions_raw(partition_names.size()) {
+ partitions(partition_names.size()),
+ partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
if (file->ReadObject(&header) != sizeof(GamecardHeader)) {
status = Loader::ResultStatus::ErrorBadXCIHeader;
return;
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index e1b136426..2d0a0f285 100644
--- a/src/core/file_sys/card_image.h
+++ b/src/core/file_sys/card_image.h
@@ -9,9 +9,12 @@
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
-#include "core/crypto/key_manager.h"
#include "core/file_sys/vfs.h"
+namespace Core::Crypto {
+class KeyManager;
+}
+
namespace Loader {
enum class ResultStatus : u16;
}
@@ -140,6 +143,6 @@ private:
u64 update_normal_partition_end;
- Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
+ Core::Crypto::KeyManager& keys;
};
} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 5039341c7..76af47ff9 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -10,10 +10,10 @@
#include "common/logging/log.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/ctr_encryption_layer.h"
+#include "core/crypto/key_manager.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_patch.h"
#include "core/file_sys/partition_filesystem.h"
-#include "core/file_sys/romfs.h"
#include "core/file_sys/vfs_offset.h"
#include "core/loader/loader.h"
@@ -119,7 +119,8 @@ static bool IsValidNCA(const NCAHeader& header) {
}
NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset)
- : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) {
+ : file(std::move(file_)),
+ bktr_base_romfs(std::move(bktr_base_romfs_)), keys{Core::Crypto::KeyManager::Instance()} {
if (file == nullptr) {
status = Loader::ResultStatus::ErrorNullFile;
return;
@@ -322,7 +323,7 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
subsection_buckets.back().entries.push_back({section.bktr.relocation.offset, {0}, ctr_low});
subsection_buckets.back().entries.push_back({size, {0}, 0});
- std::optional<Core::Crypto::Key128> key = {};
+ std::optional<Core::Crypto::Key128> key;
if (encrypted) {
if (has_rights_id) {
status = Loader::ResultStatus::Success;
@@ -441,18 +442,18 @@ std::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
memcpy(rights_id.data(), header.rights_id.data(), 16);
if (rights_id == u128{}) {
status = Loader::ResultStatus::ErrorInvalidRightsID;
- return {};
+ return std::nullopt;
}
auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
if (titlekey == Core::Crypto::Key128{}) {
status = Loader::ResultStatus::ErrorMissingTitlekey;
- return {};
+ return std::nullopt;
}
if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
status = Loader::ResultStatus::ErrorMissingTitlekek;
- return {};
+ return std::nullopt;
}
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
@@ -476,7 +477,7 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
case NCASectionCryptoType::BKTR:
LOG_TRACE(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
{
- std::optional<Core::Crypto::Key128> key = {};
+ std::optional<Core::Crypto::Key128> key;
if (has_rights_id) {
status = Loader::ResultStatus::Success;
key = GetTitlekey();
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index d25cbcf91..69292232a 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -158,7 +158,7 @@ private:
bool encrypted = false;
bool is_update = false;
- Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
+ Core::Crypto::KeyManager& keys;
};
} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 63cd2eead..b0a130345 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -5,6 +5,7 @@
#include "common/string_util.h"
#include "common/swap.h"
#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/vfs.h"
namespace FileSys {
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index e37b2fadf..403c4219a 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -10,7 +10,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
namespace FileSys {
@@ -83,7 +83,7 @@ enum class Language : u8 {
Italian = 7,
Dutch = 8,
CanadianFrench = 9,
- Portugese = 10,
+ Portuguese = 10,
Russian = 11,
Korean = 12,
Taiwanese = 13,
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index 2aff2708a..c52fafb6f 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -266,8 +266,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
cur_file->offset = file_partition_size;
file_partition_size += cur_file->size;
cur_file->entry_offset = entry_offset;
- entry_offset += sizeof(RomFSFileEntry) +
- Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4);
+ entry_offset +=
+ static_cast<u32>(sizeof(RomFSFileEntry) +
+ Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4));
prev_file = cur_file;
}
// Assign deferred parent/sibling ownership.
@@ -284,8 +285,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
for (const auto& it : directories) {
cur_dir = it.second;
cur_dir->entry_offset = entry_offset;
- entry_offset += sizeof(RomFSDirectoryEntry) +
- Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4);
+ entry_offset +=
+ static_cast<u32>(sizeof(RomFSDirectoryEntry) +
+ Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4));
}
// Assign deferred parent/sibling ownership.
for (auto it = directories.rbegin(); it->second != root; ++it) {
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index a08a70efd..a6101f1c0 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -245,9 +245,11 @@ void IPSwitchCompiler::Parse() {
// Read rest of patch
while (true) {
- if (i + 1 >= lines.size())
+ if (i + 1 >= lines.size()) {
break;
- const auto patch_line = lines[++i];
+ }
+
+ const auto& patch_line = lines[++i];
// Start of new patch
if (StartsWith(patch_line, "@enabled") || StartsWith(patch_line, "@disabled")) {
@@ -297,7 +299,7 @@ void IPSwitchCompiler::Parse() {
patch_text->GetName(), offset, Common::HexToString(replace));
}
- patch.records.insert_or_assign(offset, std::move(replace));
+ patch.records.insert_or_assign(static_cast<u32>(offset), std::move(replace));
}
patches.push_back(std::move(patch));
diff --git a/src/core/file_sys/kernel_executable.cpp b/src/core/file_sys/kernel_executable.cpp
index 76313679d..ef93ef3ed 100644
--- a/src/core/file_sys/kernel_executable.cpp
+++ b/src/core/file_sys/kernel_executable.cpp
@@ -2,9 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+
#include "common/string_util.h"
#include "core/file_sys/kernel_executable.h"
#include "core/file_sys/vfs_offset.h"
+#include "core/loader/loader.h"
namespace FileSys {
diff --git a/src/core/file_sys/kernel_executable.h b/src/core/file_sys/kernel_executable.h
index 324a57384..044c554d3 100644
--- a/src/core/file_sys/kernel_executable.h
+++ b/src/core/file_sys/kernel_executable.h
@@ -4,10 +4,17 @@
#pragma once
+#include <array>
+#include <vector>
+
#include "common/common_funcs.h"
+#include "common/common_types.h"
#include "common/swap.h"
#include "core/file_sys/vfs_types.h"
-#include "core/loader/loader.h"
+
+namespace Loader {
+enum class ResultStatus : u16;
+}
namespace FileSys {
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 93d0df6b9..3596541b2 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -7,6 +7,7 @@
#include "common/logging/log.h"
#include "common/swap.h"
#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/vfs.h"
namespace FileSys {
@@ -107,7 +108,7 @@ std::vector<u8> CNMT::Serialize() const {
memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader));
}
- auto offset = header.table_offset;
+ u64_le offset = header.table_offset;
for (const auto& rec : content_records) {
memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord));
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index 1f82fff0a..53535e5f5 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -10,7 +10,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
namespace FileSys {
class CNMT;
diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp
index fe7375e84..5990a2fd5 100644
--- a/src/core/file_sys/nca_patch.cpp
+++ b/src/core/file_sys/nca_patch.cpp
@@ -12,6 +12,49 @@
#include "core/file_sys/nca_patch.h"
namespace FileSys {
+namespace {
+template <bool Subsection, typename BlockType, typename BucketType>
+std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, const BlockType& block,
+ const BucketType& buckets) {
+ if constexpr (Subsection) {
+ const auto& last_bucket = buckets[block.number_buckets - 1];
+ if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch) {
+ return {block.number_buckets - 1, last_bucket.number_entries};
+ }
+ } else {
+ ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block.");
+ }
+
+ std::size_t bucket_id = std::count_if(
+ block.base_offsets.begin() + 1, block.base_offsets.begin() + block.number_buckets,
+ [&offset](u64 base_offset) { return base_offset <= offset; });
+
+ const auto& bucket = buckets[bucket_id];
+
+ if (bucket.number_entries == 1) {
+ return {bucket_id, 0};
+ }
+
+ std::size_t low = 0;
+ std::size_t mid = 0;
+ std::size_t high = bucket.number_entries - 1;
+ while (low <= high) {
+ mid = (low + high) / 2;
+ if (bucket.entries[mid].address_patch > offset) {
+ high = mid - 1;
+ } else {
+ if (mid == bucket.number_entries - 1 ||
+ bucket.entries[mid + 1].address_patch > offset) {
+ return {bucket_id, mid};
+ }
+
+ low = mid + 1;
+ }
+ }
+
+ UNREACHABLE_MSG("Offset could not be found in BKTR block.");
+}
+} // Anonymous namespace
BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock relocation_,
std::vector<RelocationBucket> relocation_buckets_, SubsectionBlock subsection_,
@@ -110,46 +153,6 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
return raw_read;
}
-template <bool Subsection, typename BlockType, typename BucketType>
-std::pair<std::size_t, std::size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block,
- BucketType buckets) const {
- if constexpr (Subsection) {
- const auto last_bucket = buckets[block.number_buckets - 1];
- if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch)
- return {block.number_buckets - 1, last_bucket.number_entries};
- } else {
- ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block.");
- }
-
- std::size_t bucket_id = std::count_if(
- block.base_offsets.begin() + 1, block.base_offsets.begin() + block.number_buckets,
- [&offset](u64 base_offset) { return base_offset <= offset; });
-
- const auto bucket = buckets[bucket_id];
-
- if (bucket.number_entries == 1)
- return {bucket_id, 0};
-
- std::size_t low = 0;
- std::size_t mid = 0;
- std::size_t high = bucket.number_entries - 1;
- while (low <= high) {
- mid = (low + high) / 2;
- if (bucket.entries[mid].address_patch > offset) {
- high = mid - 1;
- } else {
- if (mid == bucket.number_entries - 1 ||
- bucket.entries[mid + 1].address_patch > offset) {
- return {bucket_id, mid};
- }
-
- low = mid + 1;
- }
- }
-
- UNREACHABLE_MSG("Offset could not be found in BKTR block.");
-}
-
RelocationEntry BKTR::GetRelocationEntry(u64 offset) const {
const auto res = SearchBucketEntry<false>(offset, relocation, relocation_buckets);
return relocation_buckets[res.first].entries[res.second];
diff --git a/src/core/file_sys/nca_patch.h b/src/core/file_sys/nca_patch.h
index 8e64e8378..60c544f8e 100644
--- a/src/core/file_sys/nca_patch.h
+++ b/src/core/file_sys/nca_patch.h
@@ -117,10 +117,6 @@ public:
bool Rename(std::string_view name) override;
private:
- template <bool Subsection, typename BlockType, typename BucketType>
- std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, BlockType block,
- BucketType buckets) const;
-
RelocationEntry GetRelocationEntry(u64 offset) const;
RelocationEntry GetNextRelocationEntry(u64 offset) const;
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 846986736..48a2ed4d4 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -21,7 +21,7 @@ bool PartitionFilesystem::Header::HasValidMagicValue() const {
magic == Common::MakeMagic('P', 'F', 'S', '0');
}
-PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
+PartitionFilesystem::PartitionFilesystem(VirtualFile file) {
// At least be as large as the header
if (file->GetSize() < sizeof(Header)) {
status = Loader::ResultStatus::ErrorBadPFSHeader;
@@ -89,11 +89,11 @@ std::map<std::string, u64> PartitionFilesystem::GetFileSizes() const {
return sizes;
}
-std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const {
+std::vector<VirtualFile> PartitionFilesystem::GetFiles() const {
return pfs_files;
}
-std::vector<std::shared_ptr<VfsDirectory>> PartitionFilesystem::GetSubdirectories() const {
+std::vector<VirtualDir> PartitionFilesystem::GetSubdirectories() const {
return {};
}
@@ -101,7 +101,7 @@ std::string PartitionFilesystem::GetName() const {
return is_hfs ? "HFS0" : "PFS0";
}
-std::shared_ptr<VfsDirectory> PartitionFilesystem::GetParentDirectory() const {
+VirtualDir PartitionFilesystem::GetParentDirectory() const {
// TODO(DarkLordZach): Add support for nested containers.
return nullptr;
}
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
index 279193b19..0f831148e 100644
--- a/src/core/file_sys/partition_filesystem.h
+++ b/src/core/file_sys/partition_filesystem.h
@@ -24,7 +24,7 @@ namespace FileSys {
*/
class PartitionFilesystem : public ReadOnlyVfsDirectory {
public:
- explicit PartitionFilesystem(std::shared_ptr<VfsFile> file);
+ explicit PartitionFilesystem(VirtualFile file);
~PartitionFilesystem() override;
Loader::ResultStatus GetStatus() const;
@@ -32,10 +32,10 @@ public:
std::map<std::string, u64> GetFileOffsets() const;
std::map<std::string, u64> GetFileSizes() const;
- std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
- std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
+ std::vector<VirtualFile> GetFiles() const override;
+ std::vector<VirtualDir> GetSubdirectories() const override;
std::string GetName() const override;
- std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
+ VirtualDir GetParentDirectory() const override;
void PrintDebugInfo() const;
private:
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 729dbb5f4..807b05821 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -27,8 +27,9 @@
#include "core/settings.h"
namespace FileSys {
+namespace {
-constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
+constexpr u32 SINGLE_BYTE_MODULUS = 0x100;
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
@@ -36,21 +37,29 @@ constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
"subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
};
-std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
+enum class TitleVersionFormat : u8 {
+ ThreeElements, ///< vX.Y.Z
+ FourElements, ///< vX.Y.Z.W
+};
+
+std::string FormatTitleVersion(u32 version,
+ TitleVersionFormat format = TitleVersionFormat::ThreeElements) {
std::array<u8, sizeof(u32)> bytes{};
- bytes[0] = version % SINGLE_BYTE_MODULUS;
+ bytes[0] = static_cast<u8>(version % SINGLE_BYTE_MODULUS);
for (std::size_t i = 1; i < bytes.size(); ++i) {
version /= SINGLE_BYTE_MODULUS;
- bytes[i] = version % SINGLE_BYTE_MODULUS;
+ bytes[i] = static_cast<u8>(version % SINGLE_BYTE_MODULUS);
}
- if (format == TitleVersionFormat::FourElements)
+ if (format == TitleVersionFormat::FourElements) {
return fmt::format("v{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]);
+ }
return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]);
}
-std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir,
- std::string_view name) {
+// Returns a directory with name matching name case-insensitive. Returns nullptr if directory
+// doesn't have a directory with name.
+VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name) {
#ifdef _WIN32
return dir->GetSubdirectory(name);
#else
@@ -66,6 +75,43 @@ std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<Vfs
#endif
}
+std::optional<std::vector<Core::Memory::CheatEntry>> ReadCheatFileFromFolder(
+ u64 title_id, const PatchManager::BuildID& build_id_, const VirtualDir& base_path, bool upper) {
+ const auto build_id_raw = Common::HexToString(build_id_, upper);
+ const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2);
+ const auto file = base_path->GetFile(fmt::format("{}.txt", build_id));
+
+ if (file == nullptr) {
+ LOG_INFO(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}",
+ title_id, build_id);
+ return std::nullopt;
+ }
+
+ std::vector<u8> data(file->GetSize());
+ if (file->Read(data.data(), data.size()) != data.size()) {
+ LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}",
+ title_id, build_id);
+ return std::nullopt;
+ }
+
+ const Core::Memory::TextCheatParser parser;
+ return parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
+}
+
+void AppendCommaIfNotEmpty(std::string& to, std::string_view with) {
+ if (to.empty()) {
+ to += with;
+ } else {
+ to += ", ";
+ to += with;
+ }
+}
+
+bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
+ return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty());
+}
+} // Anonymous namespace
+
PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
PatchManager::~PatchManager() = default;
@@ -246,7 +292,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
return out;
}
-bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
+bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {
const auto build_id_raw = Common::HexToString(build_id_);
const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
@@ -266,36 +312,8 @@ bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
return !CollectPatches(patch_dirs, build_id).empty();
}
-namespace {
-std::optional<std::vector<Core::Memory::CheatEntry>> ReadCheatFileFromFolder(
- const Core::System& system, u64 title_id, const std::array<u8, 0x20>& build_id_,
- const VirtualDir& base_path, bool upper) {
- const auto build_id_raw = Common::HexToString(build_id_, upper);
- const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2);
- const auto file = base_path->GetFile(fmt::format("{}.txt", build_id));
-
- if (file == nullptr) {
- LOG_INFO(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}",
- title_id, build_id);
- return std::nullopt;
- }
-
- std::vector<u8> data(file->GetSize());
- if (file->Read(data.data(), data.size()) != data.size()) {
- LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}",
- title_id, build_id);
- return std::nullopt;
- }
-
- Core::Memory::TextCheatParser parser;
- return parser.Parse(system,
- std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
-}
-
-} // Anonymous namespace
-
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
- const Core::System& system, const std::array<u8, 32>& build_id_) const {
+ const Core::System& system, const BuildID& build_id_) const {
const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
@@ -315,14 +333,12 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats");
if (cheats_dir != nullptr) {
- auto res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, true);
- if (res.has_value()) {
+ if (const auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) {
std::copy(res->begin(), res->end(), std::back_inserter(out));
continue;
}
- res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, false);
- if (res.has_value()) {
+ if (const auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) {
std::copy(res->begin(), res->end(), std::back_inserter(out));
}
}
@@ -436,21 +452,11 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
return romfs;
}
-static void AppendCommaIfNotEmpty(std::string& to, const std::string& with) {
- if (to.empty())
- to += with;
- else
- to += ", " + with;
-}
-
-static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
- return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty());
-}
-
-std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
- VirtualFile update_raw) const {
- if (title_id == 0)
+PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile update_raw) const {
+ if (title_id == 0) {
return {};
+ }
+
std::map<std::string, std::string, std::less<>> out;
const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto& disabled = Settings::values.disabled_addons[title_id];
@@ -473,8 +479,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
if (meta_ver.value_or(0) == 0) {
out.insert_or_assign(update_label, "");
} else {
- out.insert_or_assign(
- update_label, FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
+ out.insert_or_assign(update_label, FormatTitleVersion(*meta_ver));
}
} else if (update_raw != nullptr) {
out.insert_or_assign(update_label, "PACKED");
@@ -563,40 +568,46 @@ std::optional<u32> PatchManager::GetGameVersion() const {
return installed.GetEntryVersion(title_id);
}
-std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
+PatchManager::Metadata PatchManager::GetControlMetadata() const {
const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
- if (base_control_nca == nullptr)
+ if (base_control_nca == nullptr) {
return {};
+ }
return ParseControlNCA(*base_control_nca);
}
-std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(const NCA& nca) const {
+PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
const auto base_romfs = nca.GetRomFS();
- if (base_romfs == nullptr)
+ if (base_romfs == nullptr) {
return {};
+ }
const auto romfs = PatchRomFS(base_romfs, nca.GetBaseIVFCOffset(), ContentRecordType::Control);
- if (romfs == nullptr)
+ if (romfs == nullptr) {
return {};
+ }
const auto extracted = ExtractRomFS(romfs);
- if (extracted == nullptr)
+ if (extracted == nullptr) {
return {};
+ }
auto nacp_file = extracted->GetFile("control.nacp");
- if (nacp_file == nullptr)
+ if (nacp_file == nullptr) {
nacp_file = extracted->GetFile("Control.nacp");
+ }
auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file);
VirtualFile icon_file;
for (const auto& language : FileSys::LANGUAGE_NAMES) {
- icon_file = extracted->GetFile("icon_" + std::string(language) + ".dat");
- if (icon_file != nullptr)
+ icon_file = extracted->GetFile(std::string("icon_").append(language).append(".dat"));
+ if (icon_file != nullptr) {
break;
+ }
}
return {std::move(nacp), icon_file};
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index f4cb918dd..1f28c6241 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -6,10 +6,11 @@
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include "common/common_types.h"
#include "core/file_sys/nca_metadata.h"
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
#include "core/memory/dmnt_cheat_types.h"
namespace Core {
@@ -21,71 +22,62 @@ namespace FileSys {
class NCA;
class NACP;
-enum class TitleVersionFormat : u8 {
- ThreeElements, ///< vX.Y.Z
- FourElements, ///< vX.Y.Z.W
-};
-
-std::string FormatTitleVersion(u32 version,
- TitleVersionFormat format = TitleVersionFormat::ThreeElements);
-
-// Returns a directory with name matching name case-insensitive. Returns nullptr if directory
-// doesn't have a directory with name.
-std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir,
- std::string_view name);
-
// A centralized class to manage patches to games.
class PatchManager {
public:
+ using BuildID = std::array<u8, 0x20>;
+ using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>;
+ using PatchVersionNames = std::map<std::string, std::string, std::less<>>;
+
explicit PatchManager(u64 title_id);
~PatchManager();
- u64 GetTitleID() const;
+ [[nodiscard]] u64 GetTitleID() const;
// Currently tracked ExeFS patches:
// - Game Updates
- VirtualDir PatchExeFS(VirtualDir exefs) const;
+ [[nodiscard]] VirtualDir PatchExeFS(VirtualDir exefs) const;
// Currently tracked NSO patches:
// - IPS
// - IPSwitch
- std::vector<u8> PatchNSO(const std::vector<u8>& nso, const std::string& name) const;
+ [[nodiscard]] std::vector<u8> PatchNSO(const std::vector<u8>& nso,
+ const std::string& name) const;
// Checks to see if PatchNSO() will have any effect given the NSO's build ID.
// Used to prevent expensive copies in NSO loader.
- bool HasNSOPatch(const std::array<u8, 0x20>& build_id) const;
+ [[nodiscard]] bool HasNSOPatch(const BuildID& build_id) const;
// Creates a CheatList object with all
- std::vector<Core::Memory::CheatEntry> CreateCheatList(
- const Core::System& system, const std::array<u8, 0x20>& build_id) const;
+ [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList(
+ const Core::System& system, const BuildID& build_id) const;
// Currently tracked RomFS patches:
// - Game Updates
// - LayeredFS
- VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset,
- ContentRecordType type = ContentRecordType::Program,
- VirtualFile update_raw = nullptr) const;
+ [[nodiscard]] VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset,
+ ContentRecordType type = ContentRecordType::Program,
+ VirtualFile update_raw = nullptr) const;
// Returns a vector of pairs between patch names and patch versions.
// i.e. Update 3.2.2 will return {"Update", "3.2.2"}
- std::map<std::string, std::string, std::less<>> GetPatchVersionNames(
- VirtualFile update_raw = nullptr) const;
+ [[nodiscard]] PatchVersionNames GetPatchVersionNames(VirtualFile update_raw = nullptr) const;
// If the game update exists, returns the u32 version field in its Meta-type NCA. If that fails,
// it will fallback to the Meta-type NCA of the base game. If that fails, the result will be
// std::nullopt
- std::optional<u32> GetGameVersion() const;
+ [[nodiscard]] std::optional<u32> GetGameVersion() const;
// Given title_id of the program, attempts to get the control data of the update and parse
// it, falling back to the base control data.
- std::pair<std::unique_ptr<NACP>, VirtualFile> GetControlMetadata() const;
+ [[nodiscard]] Metadata GetControlMetadata() const;
// Version of GetControlMetadata that takes an arbitrary NCA
- std::pair<std::unique_ptr<NACP>, VirtualFile> ParseControlNCA(const NCA& nca) const;
+ [[nodiscard]] Metadata ParseControlNCA(const NCA& nca) const;
private:
- std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
- const std::string& build_id) const;
+ [[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
+ const std::string& build_id) const;
u64 title_id;
};
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 43169bf9f..9cf49bf44 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -7,6 +7,7 @@
#include "common/logging/log.h"
#include "core/file_sys/program_metadata.h"
+#include "core/file_sys/vfs.h"
#include "core/loader/loader.h"
namespace FileSys {
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 35069972b..455532567 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -9,7 +9,7 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/swap.h"
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
namespace Loader {
enum class ResultStatus : u16;
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index e42b677f7..da01002d5 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -257,8 +257,7 @@ std::vector<NcaID> PlaceholderCache::List() const {
for (const auto& sdir : dir->GetSubdirectories()) {
for (const auto& file : sdir->GetFiles()) {
const auto name = file->GetName();
- if (name.length() == 36 && name[32] == '.' && name[33] == 'n' && name[34] == 'c' &&
- name[35] == 'a') {
+ if (name.length() == 36 && name.ends_with(".nca")) {
out.push_back(Common::HexStringToArray<0x10>(name.substr(0, 32)));
}
}
@@ -621,25 +620,25 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
bool overwrite_if_exists, const VfsCopyFunction& copy) {
- CNMTHeader header{
- nca.GetTitleId(), // Title ID
- 0, // Ignore/Default title version
- type, // Type
- {}, // Padding
- 0x10, // Default table offset
- 1, // 1 Content Entry
- 0, // No Meta Entries
- {}, // Padding
- {}, // Reserved 1
- 0, // Is committed
- 0, // Required download system version
- {}, // Reserved 2
+ const CNMTHeader header{
+ .title_id = nca.GetTitleId(),
+ .title_version = 0,
+ .type = type,
+ .reserved = {},
+ .table_offset = 0x10,
+ .number_content_entries = 1,
+ .number_meta_entries = 0,
+ .attributes = 0,
+ .reserved2 = {},
+ .is_committed = 0,
+ .required_download_system_version = 0,
+ .reserved3 = {},
};
- OptionalHeader opt_header{0, 0};
+ const OptionalHeader opt_header{0, 0};
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0);
- memcpy(&c_rec.nca_id, &c_rec.hash, 16);
+ std::memcpy(&c_rec.nca_id, &c_rec.hash, 16);
const CNMT new_cnmt(header, opt_header, {c_rec}, {});
if (!RawInstallYuzuMeta(new_cnmt)) {
return InstallResult::ErrorMetaFailed;
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h
index 2fd07ed04..82e683782 100644
--- a/src/core/file_sys/romfs.h
+++ b/src/core/file_sys/romfs.h
@@ -4,7 +4,6 @@
#pragma once
-#include <array>
#include "core/file_sys/vfs.h"
namespace FileSys {
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 418a39a7e..e967a254e 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -6,7 +6,6 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
-#include "core/core.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
@@ -19,7 +18,9 @@
namespace FileSys {
-RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
+RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provider,
+ Service::FileSystem::FileSystemController& controller)
+ : content_provider{provider}, filesystem_controller{controller} {
// Load the RomFS from the app
if (app_loader.ReadRomFS(file) != Loader::ResultStatus::Success) {
LOG_ERROR(Service_FS, "Unable to read RomFS!");
@@ -46,39 +47,38 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_titl
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
ContentRecordType type) const {
- std::shared_ptr<NCA> res;
-
- switch (storage) {
- case StorageId::None:
- res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type);
- break;
- case StorageId::NandSystem:
- res =
- Core::System::GetInstance().GetFileSystemController().GetSystemNANDContents()->GetEntry(
- title_id, type);
- break;
- case StorageId::NandUser:
- res = Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->GetEntry(
- title_id, type);
- break;
- case StorageId::SdCard:
- res = Core::System::GetInstance().GetFileSystemController().GetSDMCContents()->GetEntry(
- title_id, type);
- break;
- default:
- UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));
- }
-
+ const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type);
if (res == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return RESULT_UNKNOWN;
}
+
const auto romfs = res->GetRomFS();
if (romfs == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return RESULT_UNKNOWN;
}
+
return MakeResult<VirtualFile>(romfs);
}
+std::shared_ptr<NCA> RomFSFactory::GetEntry(u64 title_id, StorageId storage,
+ ContentRecordType type) const {
+ switch (storage) {
+ case StorageId::None:
+ return content_provider.GetEntry(title_id, type);
+ case StorageId::NandSystem:
+ return filesystem_controller.GetSystemNANDContents()->GetEntry(title_id, type);
+ case StorageId::NandUser:
+ return filesystem_controller.GetUserNANDContents()->GetEntry(title_id, type);
+ case StorageId::SdCard:
+ return filesystem_controller.GetSDMCContents()->GetEntry(title_id, type);
+ case StorageId::Host:
+ case StorageId::GameCard:
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));
+ return nullptr;
+ }
+}
+
} // namespace FileSys
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index c5d40285c..ec704dfa8 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -13,8 +13,15 @@ namespace Loader {
class AppLoader;
} // namespace Loader
+namespace Service::FileSystem {
+class FileSystemController;
+}
+
namespace FileSys {
+class ContentProvider;
+class NCA;
+
enum class ContentRecordType : u8;
enum class StorageId : u8 {
@@ -29,18 +36,26 @@ enum class StorageId : u8 {
/// File system interface to the RomFS archive
class RomFSFactory {
public:
- explicit RomFSFactory(Loader::AppLoader& app_loader);
+ explicit RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provider,
+ Service::FileSystem::FileSystemController& controller);
~RomFSFactory();
void SetPackedUpdate(VirtualFile update_raw);
- ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
- ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type) const;
+ [[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
+ [[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage,
+ ContentRecordType type) const;
private:
+ [[nodiscard]] std::shared_ptr<NCA> GetEntry(u64 title_id, StorageId storage,
+ ContentRecordType type) const;
+
VirtualFile file;
VirtualFile update_raw;
bool updatable;
u64 ivfc_offset;
+
+ ContentProvider& content_provider;
+ Service::FileSystem::FileSystemController& filesystem_controller;
};
} // namespace FileSys
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index 6f732e4d8..cb56d8f2d 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -5,8 +5,8 @@
#include <memory>
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/sdmc_factory.h"
+#include "core/file_sys/vfs.h"
#include "core/file_sys/xts_archive.h"
-#include "core/settings.h"
namespace FileSys {
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
index 42dc4e08a..2bb92ba93 100644
--- a/src/core/file_sys/sdmc_factory.h
+++ b/src/core/file_sys/sdmc_factory.h
@@ -5,7 +5,7 @@
#pragma once
#include <memory>
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
#include "core/hle/result.h"
namespace FileSys {
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 175a8266a..90641d23b 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -19,42 +19,10 @@
#include "core/loader/loader.h"
namespace FileSys {
-namespace {
-void SetTicketKeys(const std::vector<VirtualFile>& files) {
- auto& keys = Core::Crypto::KeyManager::Instance();
-
- for (const auto& ticket_file : files) {
- if (ticket_file == nullptr) {
- continue;
- }
-
- if (ticket_file->GetExtension() != "tik") {
- continue;
- }
-
- if (ticket_file->GetSize() <
- Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
- continue;
- }
-
- Core::Crypto::Key128 key{};
- ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
-
- // We get the name without the extension in order to create the rights ID.
- std::string name_only(ticket_file->GetName());
- name_only.erase(name_only.size() - 4);
-
- const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
- u128 rights_id;
- std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
- keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
- }
-}
-} // Anonymous namespace
NSP::NSP(VirtualFile file_)
: file(std::move(file_)), status{Loader::ResultStatus::Success},
- pfs(std::make_shared<PartitionFilesystem>(file)) {
+ pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
if (pfs->GetStatus() != Loader::ResultStatus::Success) {
status = pfs->GetStatus();
return;
@@ -232,6 +200,35 @@ VirtualDir NSP::GetParentDirectory() const {
return file->GetContainingDirectory();
}
+void NSP::SetTicketKeys(const std::vector<VirtualFile>& files) {
+ for (const auto& ticket_file : files) {
+ if (ticket_file == nullptr) {
+ continue;
+ }
+
+ if (ticket_file->GetExtension() != "tik") {
+ continue;
+ }
+
+ if (ticket_file->GetSize() <
+ Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
+ continue;
+ }
+
+ Core::Crypto::Key128 key{};
+ ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
+
+ // We get the name without the extension in order to create the rights ID.
+ std::string name_only(ticket_file->GetName());
+ name_only.erase(name_only.size() - 4);
+
+ const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
+ u128 rights_id;
+ std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
+ keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
+ }
+}
+
void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
exefs = pfs;
@@ -267,9 +264,9 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
}
const CNMT cnmt(inner_file);
- auto& ncas_title = ncas[cnmt.GetTitleID()];
- ncas_title[{cnmt.GetType(), ContentRecordType::Meta}] = nca;
+ ncas[cnmt.GetTitleID()][{cnmt.GetType(), ContentRecordType::Meta}] = nca;
+
for (const auto& rec : cnmt.GetContentRecords()) {
const auto id_string = Common::HexToString(rec.nca_id, false);
auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));
@@ -286,13 +283,32 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
}
auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0);
+
if (next_nca->GetType() == NCAContentType::Program) {
- program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
+ program_status[next_nca->GetTitleId()] = next_nca->GetStatus();
}
- if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
- (next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
- (cnmt.GetTitleID() & 0x800) != 0)) {
- ncas_title[{cnmt.GetType(), rec.type}] = std::move(next_nca);
+
+ if (next_nca->GetStatus() != Loader::ResultStatus::Success &&
+ next_nca->GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
+ continue;
+ }
+
+ // If the last 3 hexadecimal digits of the CNMT TitleID is 0x800 or is missing the
+ // BKTRBaseRomFS, this is an update NCA. Otherwise, this is a base NCA.
+ if ((cnmt.GetTitleID() & 0x800) != 0 ||
+ next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
+ // If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and
+ // 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
+ // update NCA.
+ if ((next_nca->GetTitleId() & 0x7FF) != 0 &&
+ (next_nca->GetTitleId() & 0x800) == 0) {
+ ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
+ std::move(next_nca);
+ } else {
+ ncas[cnmt.GetTitleID()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
+ }
+ } else {
+ ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
}
}
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index cf89de6a9..c70a11b5b 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -10,6 +10,10 @@
#include "common/common_types.h"
#include "core/file_sys/vfs.h"
+namespace Core::Crypto {
+class KeyManager;
+}
+
namespace Loader {
enum class ResultStatus : u16;
}
@@ -59,6 +63,7 @@ public:
VirtualDir GetParentDirectory() const override;
private:
+ void SetTicketKeys(const std::vector<VirtualFile>& files);
void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files);
void ReadNCAs(const std::vector<VirtualFile>& files);
@@ -73,7 +78,7 @@ private:
std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas;
std::vector<VirtualFile> ticket_files;
- Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
+ Core::Crypto::KeyManager& keys;
VirtualFile romfs;
VirtualDir exefs;
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index a4c3f67c4..b2f026b6d 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -169,11 +169,12 @@ VfsDirectory::~VfsDirectory() = default;
std::optional<u8> VfsFile::ReadByte(std::size_t offset) const {
u8 out{};
- std::size_t size = Read(&out, 1, offset);
- if (size == 1)
+ const std::size_t size = Read(&out, sizeof(u8), offset);
+ if (size == 1) {
return out;
+ }
- return {};
+ return std::nullopt;
}
std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const {
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index c96f88488..7714d3de5 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -58,10 +58,11 @@ std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t
}
std::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const {
- if (r_offset < size)
- return file->ReadByte(offset + r_offset);
+ if (r_offset >= size) {
+ return std::nullopt;
+ }
- return {};
+ return file->ReadByte(offset + r_offset);
}
std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const {
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 1dbf632c1..488687ba9 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -72,8 +72,10 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
- if (cache.find(path) != cache.end()) {
- auto weak = cache[path];
+
+ if (const auto weak_iter = cache.find(path); weak_iter != cache.cend()) {
+ const auto& weak = weak_iter->second;
+
if (!weak.expired()) {
return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms));
}
@@ -84,7 +86,7 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
}
auto backing = std::make_shared<FS::IOFile>(path, ModeFlagsToString(perms).c_str());
- cache[path] = backing;
+ cache.insert_or_assign(path, backing);
// Cannot use make_shared as RealVfsFile constructor is private
return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms));
@@ -116,11 +118,12 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_
VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
+ const auto cached_file_iter = cache.find(old_path);
- if (cache.find(old_path) != cache.end()) {
- auto file = cache[old_path].lock();
+ if (cached_file_iter != cache.cend()) {
+ auto file = cached_file_iter->second.lock();
- if (!cache[old_path].expired()) {
+ if (!cached_file_iter->second.expired()) {
file->Close();
}
@@ -131,7 +134,7 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
cache.erase(old_path);
file->Open(new_path, "r+b");
- cache[new_path] = file;
+ cache.insert_or_assign(new_path, std::move(file));
} else {
UNREACHABLE();
return nullptr;
@@ -142,12 +145,15 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
- if (cache.find(path) != cache.end()) {
- if (!cache[path].expired()) {
- cache[path].lock()->Close();
+ const auto cached_iter = cache.find(path);
+
+ if (cached_iter != cache.cend()) {
+ if (!cached_iter->second.expired()) {
+ cached_iter->second.lock()->Close();
}
cache.erase(path);
}
+
return FS::Delete(path);
}
@@ -192,21 +198,25 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
}
for (auto& kv : cache) {
- // Path in cache starts with old_path
- if (kv.first.rfind(old_path, 0) == 0) {
- const auto file_old_path =
- FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault);
- const auto file_new_path =
- FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
- FS::DirectorySeparator::PlatformDefault);
- auto cached = cache[file_old_path];
- if (!cached.expired()) {
- auto file = cached.lock();
- file->Open(file_new_path, "r+b");
- cache.erase(file_old_path);
- cache[file_new_path] = file;
- }
+ // If the path in the cache doesn't start with old_path, then bail on this file.
+ if (kv.first.rfind(old_path, 0) != 0) {
+ continue;
+ }
+
+ const auto file_old_path =
+ FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault);
+ auto file_new_path = FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
+ FS::DirectorySeparator::PlatformDefault);
+ const auto& cached = cache[file_old_path];
+
+ if (cached.expired()) {
+ continue;
}
+
+ auto file = cached.lock();
+ file->Open(file_new_path, "r+b");
+ cache.erase(file_old_path);
+ cache.insert_or_assign(std::move(file_new_path), std::move(file));
}
return OpenDirectory(new_path, Mode::ReadWrite);
@@ -214,15 +224,21 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
+
for (auto& kv : cache) {
- // Path in cache starts with old_path
- if (kv.first.rfind(path, 0) == 0) {
- if (!cache[kv.first].expired()) {
- cache[kv.first].lock()->Close();
- }
- cache.erase(kv.first);
+ // If the path in the cache doesn't start with path, then bail on this file.
+ if (kv.first.rfind(path, 0) != 0) {
+ continue;
}
+
+ const auto& entry = cache[kv.first];
+ if (!entry.expired()) {
+ entry.lock()->Close();
+ }
+
+ cache.erase(kv.first);
}
+
return FS::DeleteDirRecursively(path);
}
@@ -260,14 +276,14 @@ bool RealVfsFile::IsReadable() const {
}
std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
- if (!backing->Seek(offset, SEEK_SET)) {
+ if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {
return 0;
}
return backing->ReadBytes(data, length);
}
std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
- if (!backing->Seek(offset, SEEK_SET)) {
+ if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {
return 0;
}
return backing->WriteBytes(data, length);
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h
index 9f5a90b1b..8b27c30fa 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs_static.h
@@ -54,9 +54,11 @@ public:
}
std::optional<u8> ReadByte(std::size_t offset) const override {
- if (offset < size)
- return value;
- return {};
+ if (offset >= size) {
+ return std::nullopt;
+ }
+
+ return value;
}
std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override {
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index ccf5966d0..24c58e7ae 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -15,8 +15,9 @@
#include "common/hex_util.h"
#include "common/string_util.h"
#include "core/crypto/aes_util.h"
+#include "core/crypto/key_manager.h"
#include "core/crypto/xts_encryption_layer.h"
-#include "core/file_sys/partition_filesystem.h"
+#include "core/file_sys/content_archive.h"
#include "core/file_sys/vfs_offset.h"
#include "core/file_sys/xts_archive.h"
#include "core/loader/loader.h"
@@ -43,7 +44,9 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
return true;
}
-NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
+NAX::NAX(VirtualFile file_)
+ : header(std::make_unique<NAXHeader>()),
+ file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
std::string path = Common::FS::SanitizePath(file->GetFullPath());
static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
std::regex_constants::ECMAScript |
@@ -60,7 +63,8 @@ NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::m
}
NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
- : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
+ : header(std::make_unique<NAXHeader>()),
+ file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h
index 563531bb6..c472e226e 100644
--- a/src/core/file_sys/xts_archive.h
+++ b/src/core/file_sys/xts_archive.h
@@ -9,12 +9,16 @@
#include "common/common_types.h"
#include "common/swap.h"
#include "core/crypto/key_manager.h"
-#include "core/file_sys/content_archive.h"
#include "core/file_sys/vfs.h"
-#include "core/loader/loader.h"
+
+namespace Loader {
+enum class ResultStatus : u16;
+}
namespace FileSys {
+class NCA;
+
struct NAXHeader {
std::array<u8, 0x20> hmac;
u64_le magic;
@@ -62,6 +66,6 @@ private:
VirtualFile dec_file;
- Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
+ Core::Crypto::KeyManager& keys;
};
} // namespace FileSys
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
new file mode 100644
index 000000000..c5d65f2d0
--- /dev/null
+++ b/src/core/frontend/applets/controller.cpp
@@ -0,0 +1,81 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/frontend/applets/controller.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Core::Frontend {
+
+ControllerApplet::~ControllerApplet() = default;
+
+DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_)
+ : service_manager{service_manager_} {}
+
+DefaultControllerApplet::~DefaultControllerApplet() = default;
+
+void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
+ ControllerParameters parameters) const {
+ LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
+
+ auto& npad =
+ service_manager.GetService<Service::HID::Hid>("hid")
+ ->GetAppletResource()
+ ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
+
+ auto& players = Settings::values.players;
+
+ const std::size_t min_supported_players =
+ parameters.enable_single_mode ? 1 : parameters.min_players;
+
+ // Disconnect Handheld first.
+ npad.DisconnectNPadAtIndex(8);
+
+ // Deduce the best configuration based on the input parameters.
+ for (std::size_t index = 0; index < players.size() - 2; ++index) {
+ // First, disconnect all controllers regardless of the value of keep_controllers_connected.
+ // This makes it easy to connect the desired controllers.
+ npad.DisconnectNPadAtIndex(index);
+
+ // Only connect the minimum number of required players.
+ if (index >= min_supported_players) {
+ continue;
+ }
+
+ // Connect controllers based on the following priority list from highest to lowest priority:
+ // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
+ if (parameters.allow_pro_controller) {
+ npad.AddNewControllerAt(
+ npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index);
+ } else if (parameters.allow_dual_joycons) {
+ npad.AddNewControllerAt(
+ npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index);
+ } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
+ // Assign left joycons to even player indices and right joycons to odd player indices.
+ // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
+ // a right Joycon for Player 2 in 2 Player Assist mode.
+ if (index % 2 == 0) {
+ npad.AddNewControllerAt(
+ npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index);
+ } else {
+ npad.AddNewControllerAt(
+ npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index);
+ }
+ } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
+ !Settings::values.use_docked_mode) {
+ // We should *never* reach here under any normal circumstances.
+ npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld),
+ index);
+ } else {
+ UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!");
+ }
+ }
+
+ callback();
+}
+
+} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h
new file mode 100644
index 000000000..3e49cdbb9
--- /dev/null
+++ b/src/core/frontend/applets/controller.h
@@ -0,0 +1,56 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+
+#include "common/common_types.h"
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Core::Frontend {
+
+using BorderColor = std::array<u8, 4>;
+using ExplainText = std::array<char, 0x81>;
+
+struct ControllerParameters {
+ s8 min_players{};
+ s8 max_players{};
+ bool keep_controllers_connected{};
+ bool enable_single_mode{};
+ bool enable_border_color{};
+ std::vector<BorderColor> border_colors{};
+ bool enable_explain_text{};
+ std::vector<ExplainText> explain_text{};
+ bool allow_pro_controller{};
+ bool allow_handheld{};
+ bool allow_dual_joycons{};
+ bool allow_left_joycon{};
+ bool allow_right_joycon{};
+};
+
+class ControllerApplet {
+public:
+ virtual ~ControllerApplet();
+
+ virtual void ReconfigureControllers(std::function<void()> callback,
+ ControllerParameters parameters) const = 0;
+};
+
+class DefaultControllerApplet final : public ControllerApplet {
+public:
+ explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_);
+ ~DefaultControllerApplet() override;
+
+ void ReconfigureControllers(std::function<void()> callback,
+ ControllerParameters parameters) const override;
+
+private:
+ Service::SM::ServiceManager& service_manager;
+};
+
+} // namespace Core::Frontend
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 9a081fbd4..8c1193894 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -84,10 +84,12 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
return;
std::lock_guard guard{touch_state->mutex};
- touch_state->touch_x = static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
- (framebuffer_layout.screen.right - framebuffer_layout.screen.left);
- touch_state->touch_y = static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
- (framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
+ touch_state->touch_x =
+ static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
+ static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
+ touch_state->touch_y =
+ static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
+ static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
touch_state->touch_pressed = true;
}
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index c1fbc235b..1acc82497 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -14,8 +14,8 @@ namespace Layout {
template <class T>
static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area,
float screen_aspect_ratio) {
- float scale = std::min(static_cast<float>(window_area.GetWidth()),
- window_area.GetHeight() / screen_aspect_ratio);
+ const float scale = std::min(static_cast<float>(window_area.GetWidth()),
+ static_cast<float>(window_area.GetHeight()) / screen_aspect_ratio);
return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)),
static_cast<T>(std::round(scale * screen_aspect_ratio))};
}
@@ -27,7 +27,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
// so just calculate them both even if the other isn't showing.
FramebufferLayout res{width, height, false, {}};
- const float window_aspect_ratio = static_cast<float>(height) / width;
+ const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width);
const float emulation_aspect_ratio = EmulationAspectRatio(
static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio);
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h
index 91ecc30ab..e2e3bbbb3 100644
--- a/src/core/frontend/framebuffer_layout.h
+++ b/src/core/frontend/framebuffer_layout.h
@@ -4,6 +4,7 @@
#pragma once
+#include "common/common_types.h"
#include "common/math_util.h"
namespace Layout {
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index 2b098b7c6..277b70e53 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -33,6 +33,9 @@ public:
virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const {
return {};
}
+ virtual bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const {
+ return {};
+ }
};
/// An abstract class template for a factory that can create input devices.
@@ -119,11 +122,11 @@ using ButtonDevice = InputDevice<bool>;
using AnalogDevice = InputDevice<std::tuple<float, float>>;
/**
- * A motion device is an input device that returns a tuple of accelerometer state vector and
- * gyroscope state vector.
+ * A motion status is an object that returns a tuple of accelerometer state vector,
+ * gyroscope state vector, rotation state vector and orientation state matrix.
*
* For both vectors:
- * x+ is the same direction as LEFT on D-pad.
+ * x+ is the same direction as RIGHT on D-pad.
* y+ is normal to the touch screen, pointing outward.
* z+ is the same direction as UP on D-pad.
*
@@ -133,8 +136,22 @@ using AnalogDevice = InputDevice<std::tuple<float, float>>;
* For gyroscope state vector:
* Orientation is determined by right-hand rule.
* Units: deg/sec
+ *
+ * For rotation state vector
+ * Units: rotations
+ *
+ * For orientation state matrix
+ * x vector
+ * y vector
+ * z vector
+ */
+using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>,
+ std::array<Common::Vec3f, 3>>;
+
+/**
+ * A motion device is an input device that returns a motion status object
*/
-using MotionDevice = InputDevice<std::tuple<Common::Vec3<float>, Common::Vec3<float>>>;
+using MotionDevice = InputDevice<MotionStatus>;
/**
* A touch device is an input device that returns a tuple of two floats and a bool. The floats are
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 79f22a403..97ee65464 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -291,11 +291,11 @@ static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr)
*/
static u8 HexCharToValue(u8 hex) {
if (hex >= '0' && hex <= '9') {
- return hex - '0';
+ return static_cast<u8>(hex - '0');
} else if (hex >= 'a' && hex <= 'f') {
- return hex - 'a' + 0xA;
+ return static_cast<u8>(hex - 'a' + 0xA);
} else if (hex >= 'A' && hex <= 'F') {
- return hex - 'A' + 0xA;
+ return static_cast<u8>(hex - 'A' + 0xA);
}
LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex);
@@ -310,9 +310,9 @@ static u8 HexCharToValue(u8 hex) {
static u8 NibbleToHex(u8 n) {
n &= 0xF;
if (n < 0xA) {
- return '0' + n;
+ return static_cast<u8>('0' + n);
} else {
- return 'a' + n - 0xA;
+ return static_cast<u8>('a' + n - 0xA);
}
}
@@ -355,8 +355,8 @@ static u64 HexToLong(const u8* src, std::size_t len) {
*/
static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) {
while (len-- > 0) {
- u8 tmp = *src++;
- *dest++ = NibbleToHex(tmp >> 4);
+ const u8 tmp = *src++;
+ *dest++ = NibbleToHex(static_cast<u8>(tmp >> 4));
*dest++ = NibbleToHex(tmp);
}
}
@@ -370,7 +370,7 @@ static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) {
*/
static void GdbHexToMem(u8* dest, const u8* src, std::size_t len) {
while (len-- > 0) {
- *dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]);
+ *dest++ = static_cast<u8>((HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]));
src += 2;
}
}
@@ -602,22 +602,22 @@ static void SendReply(const char* reply) {
memcpy(command_buffer + 1, reply, command_length);
- u8 checksum = CalculateChecksum(command_buffer, command_length + 1);
+ const u8 checksum = CalculateChecksum(command_buffer, command_length + 1);
command_buffer[0] = GDB_STUB_START;
command_buffer[command_length + 1] = GDB_STUB_END;
- command_buffer[command_length + 2] = NibbleToHex(checksum >> 4);
+ command_buffer[command_length + 2] = NibbleToHex(static_cast<u8>(checksum >> 4));
command_buffer[command_length + 3] = NibbleToHex(checksum);
u8* ptr = command_buffer;
u32 left = command_length + 4;
while (left > 0) {
- int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0);
+ const auto sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0);
if (sent_size < 0) {
LOG_ERROR(Debug_GDBStub, "gdb: send failed");
return Shutdown();
}
- left -= sent_size;
+ left -= static_cast<u32>(sent_size);
ptr += sent_size;
}
}
@@ -777,10 +777,10 @@ static void ReadCommand() {
command_buffer[command_length++] = c;
}
- u8 checksum_received = HexCharToValue(ReadByte()) << 4;
- checksum_received |= HexCharToValue(ReadByte());
+ auto checksum_received = static_cast<u32>(HexCharToValue(ReadByte()) << 4);
+ checksum_received |= static_cast<u32>(HexCharToValue(ReadByte()));
- u8 checksum_calculated = CalculateChecksum(command_buffer, command_length);
+ const u32 checksum_calculated = CalculateChecksum(command_buffer, command_length);
if (checksum_received != checksum_calculated) {
LOG_ERROR(Debug_GDBStub,
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 1b503331f..1c354037d 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -38,10 +38,11 @@ public:
explicit RequestHelperBase(Kernel::HLERequestContext& context)
: context(&context), cmdbuf(context.CommandBuffer()) {}
- void Skip(unsigned size_in_words, bool set_to_null) {
- if (set_to_null)
+ void Skip(u32 size_in_words, bool set_to_null) {
+ if (set_to_null) {
memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
- index += size_in_words;
+ }
+ index += static_cast<ptrdiff_t>(size_in_words);
}
/**
@@ -49,15 +50,15 @@ public:
*/
void AlignWithPadding() {
if (index & 3) {
- Skip(4 - (index & 3), true);
+ Skip(static_cast<u32>(4 - (index & 3)), true);
}
}
- unsigned GetCurrentOffset() const {
- return static_cast<unsigned>(index);
+ u32 GetCurrentOffset() const {
+ return static_cast<u32>(index);
}
- void SetCurrentOffset(unsigned offset) {
+ void SetCurrentOffset(u32 offset) {
index = static_cast<ptrdiff_t>(offset);
}
};
@@ -89,7 +90,7 @@ public:
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
// padding.
- u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
+ u64 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
u32 num_handles_to_move{};
u32 num_domain_objects{};
@@ -105,7 +106,7 @@ public:
raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
}
- header.data_size.Assign(raw_data_size);
+ header.data_size.Assign(static_cast<u32>(raw_data_size));
if (num_handles_to_copy || num_handles_to_move) {
header.enable_handle_descriptor.Assign(1);
}
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index 5ab204b9b..be9eba519 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -48,14 +48,15 @@ ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kern
}
ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread,
- Core::Memory::Memory& memory) {
+ Core::Memory::Memory& memory,
+ Core::Timing::CoreTiming& core_timing) {
// Keep ServerSession alive until we're done working with it.
if (!parent->Server()) {
return ERR_SESSION_CLOSED_BY_REMOTE;
}
// Signal the server session that new data is available
- return parent->Server()->HandleSyncRequest(std::move(thread), memory);
+ return parent->Server()->HandleSyncRequest(std::move(thread), memory, core_timing);
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index c5f760d7d..e5e0690c2 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -16,6 +16,10 @@ namespace Core::Memory {
class Memory;
}
+namespace Core::Timing {
+class CoreTiming;
+}
+
namespace Kernel {
class KernelCore;
@@ -42,7 +46,8 @@ public:
return HANDLE_TYPE;
}
- ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
+ ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
+ Core::Timing::CoreTiming& core_timing);
bool ShouldWait(const Thread* thread) const override;
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index fb30b6f8b..3e745c18b 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -118,7 +118,7 @@ std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
void HandleTable::Clear() {
for (u16 i = 0; i < table_size; ++i) {
- generations[i] = i + 1;
+ generations[i] = static_cast<u16>(i + 1);
objects[i] = nullptr;
}
next_free_slot = 0;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index cabe8d418..f2b0fe2fd 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -219,6 +219,7 @@ struct KernelCore::Impl {
return static_cast<u32>(system.GetCpuManager().CurrentCore());
}
}
+ std::unique_lock lock{register_thread_mutex};
const auto it = host_thread_ids.find(this_id);
if (it == host_thread_ids.end()) {
return Core::INVALID_HOST_THREAD_ID;
@@ -324,7 +325,7 @@ struct KernelCore::Impl {
std::unordered_map<std::thread::id, u32> host_thread_ids;
u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
- std::mutex register_thread_mutex;
+ mutable std::mutex register_thread_mutex;
// Kernel memory management
std::unique_ptr<Memory::MemoryManager> memory_manager;
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index a4b234424..6b7db5372 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -72,7 +72,7 @@ u32 GlobalScheduler::SelectThreads() {
if (top_thread != nullptr) {
// TODO(Blinkhawk): Implement Thread Pinning
} else {
- idle_cores |= (1ul << core);
+ idle_cores |= (1U << core);
}
top_threads[core] = top_thread;
}
@@ -126,7 +126,7 @@ u32 GlobalScheduler::SelectThreads() {
top_threads[core_id] = suggested;
}
- idle_cores &= ~(1ul << core_id);
+ idle_cores &= ~(1U << core_id);
}
u32 cores_needing_context_switch{};
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
@@ -134,7 +134,7 @@ u32 GlobalScheduler::SelectThreads() {
ASSERT(top_threads[core] == nullptr ||
static_cast<u32>(top_threads[core]->GetProcessorID()) == core);
if (update_thread(top_threads[core], sched)) {
- cores_needing_context_switch |= (1ul << core);
+ cores_needing_context_switch |= (1U << core);
}
}
return cores_needing_context_switch;
@@ -364,7 +364,7 @@ void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule,
} else {
must_context_switch = true;
}
- cores_pending_reschedule &= ~(1ul << core);
+ cores_pending_reschedule &= ~(1U << core);
}
if (must_context_switch) {
auto& core_scheduler = kernel.CurrentScheduler();
@@ -756,14 +756,18 @@ void Scheduler::SwitchToCurrent() {
current_thread = selected_thread;
is_context_switch_pending = false;
}
- while (!is_context_switch_pending) {
+ const auto is_switch_pending = [this] {
+ std::scoped_lock lock{guard};
+ return is_context_switch_pending;
+ };
+ do {
if (current_thread != nullptr && !current_thread->IsHLEThread()) {
current_thread->context_guard.lock();
if (!current_thread->IsRunnable()) {
current_thread->context_guard.unlock();
break;
}
- if (current_thread->GetProcessorID() != core_id) {
+ if (static_cast<u32>(current_thread->GetProcessorID()) != core_id) {
current_thread->context_guard.unlock();
break;
}
@@ -775,7 +779,7 @@ void Scheduler::SwitchToCurrent() {
next_context = &idle_thread->GetHostContext();
}
Common::Fiber::YieldTo(switch_fiber, *next_context);
- }
+ } while (!is_switch_pending());
}
}
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 36e3c26fb..b6f04dcea 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -188,7 +188,7 @@ private:
/// Scheduler lock mechanisms.
bool is_locked{};
- Common::SpinLock inner_lock{};
+ std::mutex inner_lock;
std::atomic<s64> scope_lock{};
Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()};
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 7e6391c6c..8c19f2534 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -8,7 +8,6 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
-#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
@@ -185,10 +184,11 @@ ResultCode ServerSession::CompleteSyncRequest() {
}
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
- Core::Memory::Memory& memory) {
+ Core::Memory::Memory& memory,
+ Core::Timing::CoreTiming& core_timing) {
const ResultCode result = QueueSyncRequest(std::move(thread), memory);
const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000};
- Core::System::GetInstance().CoreTiming().ScheduleEvent(delay, request_event, {});
+ core_timing.ScheduleEvent(delay, request_event, {});
return result;
}
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 403aaf10b..d23e9ec68 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -18,8 +18,9 @@ class Memory;
}
namespace Core::Timing {
+class CoreTiming;
struct EventType;
-}
+} // namespace Core::Timing
namespace Kernel {
@@ -87,12 +88,14 @@ public:
/**
* Handle a sync request from the emulated application.
*
- * @param thread Thread that initiated the request.
- * @param memory Memory context to handle the sync request under.
+ * @param thread Thread that initiated the request.
+ * @param memory Memory context to handle the sync request under.
+ * @param core_timing Core timing context to schedule the request event under.
*
* @returns ResultCode from the operation.
*/
- ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
+ ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
+ Core::Timing::CoreTiming& core_timing);
bool ShouldWait(const Thread* thread) const override;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 01ae57053..bafd1ced7 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -346,7 +346,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
SchedulerLock lock(system.Kernel());
thread->InvalidateHLECallback();
thread->SetStatus(ThreadStatus::WaitIPC);
- session->SendSyncRequest(SharedFrom(thread), system.Memory());
+ session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
}
if (thread->HasHLECallback()) {
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index eb54cb123..2850dd805 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -496,7 +496,7 @@ public:
{3, nullptr, "LoadIdTokenCache"},
{130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
{150, nullptr, "CreateAuthorizationRequest"},
- {160, nullptr, "StoreOpenContext"},
+ {160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"},
{170, nullptr, "LoadNetworkServiceLicenseKindAsync"},
};
// clang-format on
@@ -520,6 +520,12 @@ private:
rb.PushRaw<u64>(user_id.GetNintendoID());
}
+ void StoreOpenContext(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_ACC, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
Common::UUID user_id;
};
@@ -774,6 +780,17 @@ void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
+void Module::Interface::LoadOpenContext(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_ACC, "(STUBBED) called");
+
+ // This is similar to GetBaasAccountManagerForApplication
+ // This command is used concurrently with ListOpenContextStoredUsers
+ // TODO: Find the differences between this and GetBaasAccountManagerForApplication
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IManagerForApplication>(profile_manager->GetLastOpenedUser());
+}
+
void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index d4c6395c6..c611efd89 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -34,6 +34,7 @@ public:
void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx);
void GetProfileEditor(Kernel::HLERequestContext& ctx);
void ListQualifiedUsers(Kernel::HLERequestContext& ctx);
+ void LoadOpenContext(Kernel::HLERequestContext& ctx);
void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx);
private:
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index cb44e06b7..75a24f8f5 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -29,7 +29,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{110, nullptr, "StoreSaveDataThumbnail"},
{111, nullptr, "ClearSaveDataThumbnail"},
{120, nullptr, "CreateGuestLoginRequest"},
- {130, nullptr, "LoadOpenContext"}, // 5.0.0+
+ {130, &ACC_U0::LoadOpenContext, "LoadOpenContext"}, // 5.0.0+
{131, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 6.0.0+
{140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+
{141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 7d92b25a3..d7a81f64a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1192,7 +1192,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{120, nullptr, "ExecuteProgram"},
{121, nullptr, "ClearUserChannel"},
{122, nullptr, "UnpopToUserChannel"},
- {123, nullptr, "GetPreviousProgramIndex"},
+ {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
{140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
@@ -1554,6 +1554,14 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque
rb.Push<u32>(0);
}
+void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<s32>(previous_program_index);
+}
+
void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 6e69796ec..bcc06affe 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -288,11 +288,13 @@ private:
void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);
void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
+ void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx);
void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx);
bool launch_popped_application_specific = false;
bool launch_popped_account_preselect = false;
+ s32 previous_program_index{-1};
Kernel::EventPair gpu_error_detected_event;
Kernel::EventPair friend_invitation_storage_channel_event;
Core::System& system;
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index c3261f3e6..2b626bb40 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -5,6 +5,7 @@
#include <cstring>
#include "common/assert.h"
#include "core/core.h"
+#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/profile_select.h"
@@ -15,6 +16,7 @@
#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applets.h"
+#include "core/hle/service/am/applets/controller.h"
#include "core/hle/service/am/applets/error.h"
#include "core/hle/service/am/applets/general_backend.h"
#include "core/hle/service/am/applets/profile_select.h"
@@ -140,14 +142,14 @@ void Applet::Initialize() {
AppletFrontendSet::AppletFrontendSet() = default;
-AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
+AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce,
+ ErrorApplet error, ParentalControlsApplet parental_controls,
PhotoViewer photo_viewer, ProfileSelect profile_select,
- SoftwareKeyboard software_keyboard, WebBrowser web_browser,
- ECommerceApplet e_commerce)
- : parental_controls{std::move(parental_controls)}, error{std::move(error)},
- photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)},
- software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)},
- e_commerce{std::move(e_commerce)} {}
+ SoftwareKeyboard software_keyboard, WebBrowser web_browser)
+ : controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)},
+ parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)},
+ profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)},
+ web_browser{std::move(web_browser)} {}
AppletFrontendSet::~AppletFrontendSet() = default;
@@ -164,20 +166,37 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
}
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
- if (set.parental_controls != nullptr)
- frontend.parental_controls = std::move(set.parental_controls);
- if (set.error != nullptr)
+ if (set.controller != nullptr) {
+ frontend.controller = std::move(set.controller);
+ }
+
+ if (set.e_commerce != nullptr) {
+ frontend.e_commerce = std::move(set.e_commerce);
+ }
+
+ if (set.error != nullptr) {
frontend.error = std::move(set.error);
- if (set.photo_viewer != nullptr)
+ }
+
+ if (set.parental_controls != nullptr) {
+ frontend.parental_controls = std::move(set.parental_controls);
+ }
+
+ if (set.photo_viewer != nullptr) {
frontend.photo_viewer = std::move(set.photo_viewer);
- if (set.profile_select != nullptr)
+ }
+
+ if (set.profile_select != nullptr) {
frontend.profile_select = std::move(set.profile_select);
- if (set.software_keyboard != nullptr)
+ }
+
+ if (set.software_keyboard != nullptr) {
frontend.software_keyboard = std::move(set.software_keyboard);
- if (set.web_browser != nullptr)
+ }
+
+ if (set.web_browser != nullptr) {
frontend.web_browser = std::move(set.web_browser);
- if (set.e_commerce != nullptr)
- frontend.e_commerce = std::move(set.e_commerce);
+ }
}
void AppletManager::SetDefaultAppletFrontendSet() {
@@ -186,15 +205,24 @@ void AppletManager::SetDefaultAppletFrontendSet() {
}
void AppletManager::SetDefaultAppletsIfMissing() {
- if (frontend.parental_controls == nullptr) {
- frontend.parental_controls =
- std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
+ if (frontend.controller == nullptr) {
+ frontend.controller =
+ std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager());
+ }
+
+ if (frontend.e_commerce == nullptr) {
+ frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
}
if (frontend.error == nullptr) {
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
}
+ if (frontend.parental_controls == nullptr) {
+ frontend.parental_controls =
+ std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
+ }
+
if (frontend.photo_viewer == nullptr) {
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
}
@@ -211,10 +239,6 @@ void AppletManager::SetDefaultAppletsIfMissing() {
if (frontend.web_browser == nullptr) {
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
}
-
- if (frontend.e_commerce == nullptr) {
- frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
- }
}
void AppletManager::ClearAll() {
@@ -225,6 +249,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
switch (id) {
case AppletId::Auth:
return std::make_shared<Auth>(system, *frontend.parental_controls);
+ case AppletId::Controller:
+ return std::make_shared<Controller>(system, *frontend.controller);
case AppletId::Error:
return std::make_shared<Error>(system, *frontend.error);
case AppletId::ProfileSelect:
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index e75be86a2..a1f4cf897 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -17,6 +17,7 @@ class System;
}
namespace Core::Frontend {
+class ControllerApplet;
class ECommerceApplet;
class ErrorApplet;
class ParentalControlsApplet;
@@ -155,19 +156,20 @@ protected:
};
struct AppletFrontendSet {
- using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
+ using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
+ using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
+ using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
- using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
AppletFrontendSet();
- AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
- PhotoViewer photo_viewer, ProfileSelect profile_select,
- SoftwareKeyboard software_keyboard, WebBrowser web_browser,
- ECommerceApplet e_commerce);
+ AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, ErrorApplet error,
+ ParentalControlsApplet parental_controls, PhotoViewer photo_viewer,
+ ProfileSelect profile_select, SoftwareKeyboard software_keyboard,
+ WebBrowser web_browser);
~AppletFrontendSet();
AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -176,13 +178,14 @@ struct AppletFrontendSet {
AppletFrontendSet(AppletFrontendSet&&) noexcept;
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
- ParentalControlsApplet parental_controls;
+ ControllerApplet controller;
+ ECommerceApplet e_commerce;
ErrorApplet error;
+ ParentalControlsApplet parental_controls;
PhotoViewer photo_viewer;
ProfileSelect profile_select;
SoftwareKeyboard software_keyboard;
WebBrowser web_browser;
- ECommerceApplet e_commerce;
};
class AppletManager {
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
new file mode 100644
index 000000000..2151da783
--- /dev/null
+++ b/src/core/hle/service/am/applets/controller.cpp
@@ -0,0 +1,210 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <cstring>
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/frontend/applets/controller.h"
+#include "core/hle/result.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applets/controller.h"
+#include "core/hle/service/hid/controllers/npad.h"
+
+namespace Service::AM::Applets {
+
+// This error code (0x183ACA) is thrown when the applet fails to initialize.
+[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3101{ErrorModule::HID, 3101};
+// This error code (0x183CCA) is thrown when the u32 result in ControllerSupportResultInfo is 2.
+[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3102{ErrorModule::HID, 3102};
+
+static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
+ ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
+ std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
+ HID::Controller_NPad::NPadType npad_style_set;
+ npad_style_set.raw = private_arg.style_set;
+
+ return {
+ .min_players = std::max(s8(1), header.player_count_min),
+ .max_players = header.player_count_max,
+ .keep_controllers_connected = header.enable_take_over_connection,
+ .enable_single_mode = header.enable_single_mode,
+ .enable_border_color = header.enable_identification_color,
+ .border_colors = identification_colors,
+ .enable_explain_text = enable_text,
+ .explain_text = text,
+ .allow_pro_controller = npad_style_set.pro_controller == 1,
+ .allow_handheld = npad_style_set.handheld == 1,
+ .allow_dual_joycons = npad_style_set.joycon_dual == 1,
+ .allow_left_joycon = npad_style_set.joycon_left == 1,
+ .allow_right_joycon = npad_style_set.joycon_right == 1,
+ };
+}
+
+Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_)
+ : Applet{system_.Kernel()}, frontend(frontend_) {}
+
+Controller::~Controller() = default;
+
+void Controller::Initialize() {
+ Applet::Initialize();
+
+ LOG_INFO(Service_HID, "Initializing Controller Applet.");
+
+ LOG_DEBUG(Service_HID,
+ "Initializing Applet with common_args: arg_version={}, lib_version={}, "
+ "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
+ common_args.arguments_version, common_args.library_version,
+ common_args.play_startup_sound, common_args.size, common_args.system_tick,
+ common_args.theme_color);
+
+ library_applet_version = LibraryAppletVersion{common_args.library_version};
+
+ const auto private_arg_storage = broker.PopNormalDataToApplet();
+ ASSERT(private_arg_storage != nullptr);
+
+ const auto& private_arg = private_arg_storage->GetData();
+ ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate));
+
+ std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate));
+ ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),
+ "Unknown ControllerSupportArgPrivate revision={} with size={}",
+ library_applet_version, controller_private_arg.arg_private_size);
+
+ switch (controller_private_arg.mode) {
+ case ControllerSupportMode::ShowControllerSupport: {
+ const auto user_arg_storage = broker.PopNormalDataToApplet();
+ ASSERT(user_arg_storage != nullptr);
+
+ const auto& user_arg = user_arg_storage->GetData();
+ switch (library_applet_version) {
+ case LibraryAppletVersion::Version3:
+ case LibraryAppletVersion::Version4:
+ case LibraryAppletVersion::Version5:
+ ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld));
+ std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld));
+ break;
+ case LibraryAppletVersion::Version7:
+ ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew));
+ std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}",
+ library_applet_version, controller_private_arg.arg_size);
+ ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));
+ std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
+ break;
+ }
+ break;
+ }
+ case ControllerSupportMode::ShowControllerStrapGuide:
+ case ControllerSupportMode::ShowControllerFirmwareUpdate:
+ default: {
+ UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);
+ break;
+ }
+ }
+}
+
+bool Controller::TransactionComplete() const {
+ return complete;
+}
+
+ResultCode Controller::GetStatus() const {
+ return status;
+}
+
+void Controller::ExecuteInteractive() {
+ UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
+}
+
+void Controller::Execute() {
+ switch (controller_private_arg.mode) {
+ case ControllerSupportMode::ShowControllerSupport: {
+ const auto parameters = [this] {
+ switch (library_applet_version) {
+ case LibraryAppletVersion::Version3:
+ case LibraryAppletVersion::Version4:
+ case LibraryAppletVersion::Version5:
+ return ConvertToFrontendParameters(
+ controller_private_arg, controller_user_arg_old.header,
+ controller_user_arg_old.enable_explain_text,
+ std::vector<IdentificationColor>(
+ controller_user_arg_old.identification_colors.begin(),
+ controller_user_arg_old.identification_colors.end()),
+ std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(),
+ controller_user_arg_old.explain_text.end()));
+ case LibraryAppletVersion::Version7:
+ default:
+ return ConvertToFrontendParameters(
+ controller_private_arg, controller_user_arg_new.header,
+ controller_user_arg_new.enable_explain_text,
+ std::vector<IdentificationColor>(
+ controller_user_arg_new.identification_colors.begin(),
+ controller_user_arg_new.identification_colors.end()),
+ std::vector<ExplainText>(controller_user_arg_new.explain_text.begin(),
+ controller_user_arg_new.explain_text.end()));
+ }
+ }();
+
+ is_single_mode = parameters.enable_single_mode;
+
+ LOG_DEBUG(Service_HID,
+ "Controller Parameters: min_players={}, max_players={}, "
+ "keep_controllers_connected={}, enable_single_mode={}, enable_border_color={}, "
+ "enable_explain_text={}, allow_pro_controller={}, allow_handheld={}, "
+ "allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}",
+ parameters.min_players, parameters.max_players,
+ parameters.keep_controllers_connected, parameters.enable_single_mode,
+ parameters.enable_border_color, parameters.enable_explain_text,
+ parameters.allow_pro_controller, parameters.allow_handheld,
+ parameters.allow_dual_joycons, parameters.allow_left_joycon,
+ parameters.allow_right_joycon);
+
+ frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters);
+ break;
+ }
+ case ControllerSupportMode::ShowControllerStrapGuide:
+ case ControllerSupportMode::ShowControllerFirmwareUpdate:
+ default: {
+ ConfigurationComplete();
+ break;
+ }
+ }
+}
+
+void Controller::ConfigurationComplete() {
+ ControllerSupportResultInfo result_info{};
+
+ const auto& players = Settings::values.players;
+
+ // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
+ // Otherwise, only count connected players from P1-P8.
+ result_info.player_count =
+ is_single_mode ? 1
+ : static_cast<s8>(std::count_if(
+ players.begin(), players.end() - 2,
+ [](Settings::PlayerInput player) { return player.connected; }));
+
+ result_info.selected_id = HID::Controller_NPad::IndexToNPad(
+ std::distance(players.begin(),
+ std::find_if(players.begin(), players.end(),
+ [](Settings::PlayerInput player) { return player.connected; })));
+
+ result_info.result = 0;
+
+ LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}",
+ result_info.player_count, result_info.selected_id, result_info.result);
+
+ complete = true;
+ out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
+ std::memcpy(out_data.data(), &result_info, out_data.size());
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out_data)));
+ broker.SignalStateChanged();
+}
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h
new file mode 100644
index 000000000..f7bb3fba9
--- /dev/null
+++ b/src/core/hle/service/am/applets/controller.h
@@ -0,0 +1,123 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <vector>
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "core/hle/result.h"
+#include "core/hle/service/am/applets/applets.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::AM::Applets {
+
+using IdentificationColor = std::array<u8, 4>;
+using ExplainText = std::array<char, 0x81>;
+
+enum class LibraryAppletVersion : u32_le {
+ Version3 = 0x3, // 1.0.0 - 2.3.0
+ Version4 = 0x4, // 3.0.0 - 5.1.0
+ Version5 = 0x5, // 6.0.0 - 7.0.1
+ Version7 = 0x7, // 8.0.0+
+};
+
+enum class ControllerSupportMode : u8 {
+ ShowControllerSupport = 0,
+ ShowControllerStrapGuide = 1,
+ ShowControllerFirmwareUpdate = 2,
+};
+
+enum class ControllerSupportCaller : u8 {
+ Application = 0,
+ System = 1,
+};
+
+struct ControllerSupportArgPrivate {
+ u32 arg_private_size{};
+ u32 arg_size{};
+ bool flag_0{};
+ bool flag_1{};
+ ControllerSupportMode mode{};
+ ControllerSupportCaller caller{};
+ u32 style_set{};
+ u32 joy_hold_type{};
+};
+static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
+ "ControllerSupportArgPrivate has incorrect size.");
+
+struct ControllerSupportArgHeader {
+ s8 player_count_min{};
+ s8 player_count_max{};
+ bool enable_take_over_connection{};
+ bool enable_left_justify{};
+ bool enable_permit_joy_dual{};
+ bool enable_single_mode{};
+ bool enable_identification_color{};
+};
+static_assert(sizeof(ControllerSupportArgHeader) == 0x7,
+ "ControllerSupportArgHeader has incorrect size.");
+
+// LibraryAppletVersion 0x3, 0x4, 0x5
+struct ControllerSupportArgOld {
+ ControllerSupportArgHeader header{};
+ std::array<IdentificationColor, 4> identification_colors{};
+ bool enable_explain_text{};
+ std::array<ExplainText, 4> explain_text{};
+};
+static_assert(sizeof(ControllerSupportArgOld) == 0x21C,
+ "ControllerSupportArgOld has incorrect size.");
+
+// LibraryAppletVersion 0x7
+struct ControllerSupportArgNew {
+ ControllerSupportArgHeader header{};
+ std::array<IdentificationColor, 8> identification_colors{};
+ bool enable_explain_text{};
+ std::array<ExplainText, 8> explain_text{};
+};
+static_assert(sizeof(ControllerSupportArgNew) == 0x430,
+ "ControllerSupportArgNew has incorrect size.");
+
+struct ControllerSupportResultInfo {
+ s8 player_count{};
+ INSERT_PADDING_BYTES(3);
+ u32 selected_id{};
+ u32 result{};
+};
+static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
+ "ControllerSupportResultInfo has incorrect size.");
+
+class Controller final : public Applet {
+public:
+ explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_);
+ ~Controller() override;
+
+ void Initialize() override;
+
+ bool TransactionComplete() const override;
+ ResultCode GetStatus() const override;
+ void ExecuteInteractive() override;
+ void Execute() override;
+
+ void ConfigurationComplete();
+
+private:
+ const Core::Frontend::ControllerApplet& frontend;
+
+ LibraryAppletVersion library_applet_version;
+ ControllerSupportArgPrivate controller_private_arg;
+ ControllerSupportArgOld controller_user_arg_old;
+ ControllerSupportArgNew controller_user_arg_new;
+ bool complete{false};
+ ResultCode status{RESULT_SUCCESS};
+ bool is_single_mode{false};
+ std::vector<u8> out_data;
+};
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index d8359abaa..a2d3ded7b 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -26,7 +26,7 @@ namespace Service::Audio {
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
public:
- explicit IAudioRenderer(Core::System& system, AudioCore::AudioRendererParameter audren_params,
+ explicit IAudioRenderer(Core::System& system, AudioCommon::AudioRendererParameter audren_params,
const std::size_t instance_number)
: ServiceFramework("IAudioRenderer") {
// clang-format off
@@ -94,14 +94,15 @@ private:
void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "(STUBBED) called");
- auto result = renderer->UpdateAudioRenderer(ctx.ReadBuffer());
+ std::vector<u8> output_params(ctx.GetWriteBufferSize());
+ auto result = renderer->UpdateAudioRenderer(ctx.ReadBuffer(), output_params);
- if (result.Succeeded()) {
- ctx.WriteBuffer(result.Unwrap());
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(output_params);
}
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.Code());
+ rb.Push(result);
}
void Start(Kernel::HLERequestContext& ctx) {
@@ -346,7 +347,7 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
OpenAudioRendererImpl(ctx);
}
-static u64 CalculateNumPerformanceEntries(const AudioCore::AudioRendererParameter& params) {
+static u64 CalculateNumPerformanceEntries(const AudioCommon::AudioRendererParameter& params) {
// +1 represents the final mix.
return u64{params.effect_count} + params.submix_count + params.sink_count + params.voice_count +
1;
@@ -375,7 +376,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
constexpr u64 upsampler_manager_size = 0x48;
// Calculates the part of the size that relates to mix buffers.
- const auto calculate_mix_buffer_sizes = [](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_mix_buffer_sizes = [](const AudioCommon::AudioRendererParameter& params) {
// As of 8.0.0 this is the maximum on voice channels.
constexpr u64 max_voice_channels = 6;
@@ -397,7 +398,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
};
// Calculates the portion of the size related to the mix data (and the sorting thereof).
- const auto calculate_mix_info_size = [](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_mix_info_size = [](const AudioCommon::AudioRendererParameter& params) {
// The size of the mixing info data structure.
constexpr u64 mix_info_size = 0x940;
@@ -447,7 +448,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
};
// Calculates the part of the size related to voice channel info.
- const auto calculate_voice_info_size = [](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_voice_info_size = [](const AudioCommon::AudioRendererParameter& params) {
constexpr u64 voice_info_size = 0x220;
constexpr u64 voice_resource_size = 0xD0;
@@ -461,7 +462,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
};
// Calculates the part of the size related to memory pools.
- const auto calculate_memory_pools_size = [](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_memory_pools_size = [](const AudioCommon::AudioRendererParameter& params) {
const u64 num_memory_pools = sizeof(s32) * (u64{params.effect_count} + params.voice_count);
const u64 memory_pool_info_size = 0x20;
return Common::AlignUp(num_memory_pools * memory_pool_info_size, info_field_alignment_size);
@@ -469,7 +470,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
// Calculates the part of the size related to the splitter context.
const auto calculate_splitter_context_size =
- [](const AudioCore::AudioRendererParameter& params) -> u64 {
+ [](const AudioCommon::AudioRendererParameter& params) -> u64 {
if (!IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
return 0;
}
@@ -488,27 +489,29 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
};
// Calculates the part of the size related to the upsampler info.
- const auto calculate_upsampler_info_size = [](const AudioCore::AudioRendererParameter& params) {
- constexpr u64 upsampler_info_size = 0x280;
- // Yes, using the buffer size over info alignment size is intentional here.
- return Common::AlignUp(upsampler_info_size * (u64{params.submix_count} + params.sink_count),
- buffer_alignment_size);
- };
+ const auto calculate_upsampler_info_size =
+ [](const AudioCommon::AudioRendererParameter& params) {
+ constexpr u64 upsampler_info_size = 0x280;
+ // Yes, using the buffer size over info alignment size is intentional here.
+ return Common::AlignUp(upsampler_info_size *
+ (u64{params.submix_count} + params.sink_count),
+ buffer_alignment_size);
+ };
// Calculates the part of the size related to effect info.
- const auto calculate_effect_info_size = [](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_effect_info_size = [](const AudioCommon::AudioRendererParameter& params) {
constexpr u64 effect_info_size = 0x2B0;
return Common::AlignUp(effect_info_size * params.effect_count, info_field_alignment_size);
};
// Calculates the part of the size related to audio sink info.
- const auto calculate_sink_info_size = [](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_sink_info_size = [](const AudioCommon::AudioRendererParameter& params) {
const u64 sink_info_size = 0x170;
return Common::AlignUp(sink_info_size * params.sink_count, info_field_alignment_size);
};
// Calculates the part of the size related to voice state info.
- const auto calculate_voice_state_size = [](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_voice_state_size = [](const AudioCommon::AudioRendererParameter& params) {
const u64 voice_state_size = 0x100;
const u64 additional_size = buffer_alignment_size - 1;
return Common::AlignUp(voice_state_size * params.voice_count + additional_size,
@@ -516,7 +519,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
};
// Calculates the part of the size related to performance statistics.
- const auto calculate_perf_size = [](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_perf_size = [](const AudioCommon::AudioRendererParameter& params) {
// Extra size value appended to the end of the calculation.
constexpr u64 appended = 128;
@@ -543,79 +546,81 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
};
// Calculates the part of the size that relates to the audio command buffer.
- const auto calculate_command_buffer_size = [](const AudioCore::AudioRendererParameter& params) {
- constexpr u64 alignment = (buffer_alignment_size - 1) * 2;
+ const auto calculate_command_buffer_size =
+ [](const AudioCommon::AudioRendererParameter& params) {
+ constexpr u64 alignment = (buffer_alignment_size - 1) * 2;
- if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) {
- constexpr u64 command_buffer_size = 0x18000;
+ if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) {
+ constexpr u64 command_buffer_size = 0x18000;
- return command_buffer_size + alignment;
- }
+ return command_buffer_size + alignment;
+ }
- // When the variadic command buffer is supported, this means
- // the command generator for the audio renderer can issue commands
- // that are (as one would expect), variable in size. So what we need to do
- // is determine the maximum possible size for a few command data structures
- // then multiply them by the amount of present commands indicated by the given
- // respective audio parameters.
+ // When the variadic command buffer is supported, this means
+ // the command generator for the audio renderer can issue commands
+ // that are (as one would expect), variable in size. So what we need to do
+ // is determine the maximum possible size for a few command data structures
+ // then multiply them by the amount of present commands indicated by the given
+ // respective audio parameters.
- constexpr u64 max_biquad_filters = 2;
- constexpr u64 max_mix_buffers = 24;
+ constexpr u64 max_biquad_filters = 2;
+ constexpr u64 max_mix_buffers = 24;
- constexpr u64 biquad_filter_command_size = 0x2C;
+ constexpr u64 biquad_filter_command_size = 0x2C;
- constexpr u64 depop_mix_command_size = 0x24;
- constexpr u64 depop_setup_command_size = 0x50;
+ constexpr u64 depop_mix_command_size = 0x24;
+ constexpr u64 depop_setup_command_size = 0x50;
- constexpr u64 effect_command_max_size = 0x540;
+ constexpr u64 effect_command_max_size = 0x540;
- constexpr u64 mix_command_size = 0x1C;
- constexpr u64 mix_ramp_command_size = 0x24;
- constexpr u64 mix_ramp_grouped_command_size = 0x13C;
+ constexpr u64 mix_command_size = 0x1C;
+ constexpr u64 mix_ramp_command_size = 0x24;
+ constexpr u64 mix_ramp_grouped_command_size = 0x13C;
- constexpr u64 perf_command_size = 0x28;
+ constexpr u64 perf_command_size = 0x28;
- constexpr u64 sink_command_size = 0x130;
+ constexpr u64 sink_command_size = 0x130;
- constexpr u64 submix_command_max_size =
- depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers;
+ constexpr u64 submix_command_max_size =
+ depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers;
- constexpr u64 volume_command_size = 0x1C;
- constexpr u64 volume_ramp_command_size = 0x20;
+ constexpr u64 volume_command_size = 0x1C;
+ constexpr u64 volume_ramp_command_size = 0x20;
- constexpr u64 voice_biquad_filter_command_size =
- biquad_filter_command_size * max_biquad_filters;
- constexpr u64 voice_data_command_size = 0x9C;
- const u64 voice_command_max_size =
- (params.splitter_count * depop_setup_command_size) +
- (voice_data_command_size + voice_biquad_filter_command_size + volume_ramp_command_size +
- mix_ramp_grouped_command_size);
+ constexpr u64 voice_biquad_filter_command_size =
+ biquad_filter_command_size * max_biquad_filters;
+ constexpr u64 voice_data_command_size = 0x9C;
+ const u64 voice_command_max_size =
+ (params.splitter_count * depop_setup_command_size) +
+ (voice_data_command_size + voice_biquad_filter_command_size +
+ volume_ramp_command_size + mix_ramp_grouped_command_size);
- // Now calculate the individual elements that comprise the size and add them together.
- const u64 effect_commands_size = params.effect_count * effect_command_max_size;
+ // Now calculate the individual elements that comprise the size and add them together.
+ const u64 effect_commands_size = params.effect_count * effect_command_max_size;
- const u64 final_mix_commands_size =
- depop_mix_command_size + volume_command_size * max_mix_buffers;
+ const u64 final_mix_commands_size =
+ depop_mix_command_size + volume_command_size * max_mix_buffers;
- const u64 perf_commands_size =
- perf_command_size * (CalculateNumPerformanceEntries(params) + max_perf_detail_entries);
+ const u64 perf_commands_size =
+ perf_command_size *
+ (CalculateNumPerformanceEntries(params) + max_perf_detail_entries);
- const u64 sink_commands_size = params.sink_count * sink_command_size;
+ const u64 sink_commands_size = params.sink_count * sink_command_size;
- const u64 splitter_commands_size =
- params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size;
+ const u64 splitter_commands_size =
+ params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size;
- const u64 submix_commands_size = params.submix_count * submix_command_max_size;
+ const u64 submix_commands_size = params.submix_count * submix_command_max_size;
- const u64 voice_commands_size = params.voice_count * voice_command_max_size;
+ const u64 voice_commands_size = params.voice_count * voice_command_max_size;
- return effect_commands_size + final_mix_commands_size + perf_commands_size +
- sink_commands_size + splitter_commands_size + submix_commands_size +
- voice_commands_size + alignment;
- };
+ return effect_commands_size + final_mix_commands_size + perf_commands_size +
+ sink_commands_size + splitter_commands_size + submix_commands_size +
+ voice_commands_size + alignment;
+ };
IPC::RequestParser rp{ctx};
- const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
+ const auto params = rp.PopRaw<AudioCommon::AudioRendererParameter>();
u64 size = 0;
size += calculate_mix_buffer_sizes(params);
@@ -681,7 +686,7 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c
void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
+ const auto params = rp.PopRaw<AudioCommon::AudioRendererParameter>();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index ca021a99f..3b6f7498e 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -196,7 +196,9 @@ private:
const std::string& content_type_name) {
if (client == nullptr) {
client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT);
- client->set_timeout_sec(timeout_seconds);
+ client->set_connection_timeout(timeout_seconds);
+ client->set_read_timeout(timeout_seconds);
+ client->set_write_timeout(timeout_seconds);
}
httplib::Headers headers{
@@ -255,7 +257,7 @@ private:
return out;
}
- std::unique_ptr<httplib::Client> client;
+ std::unique_ptr<httplib::SSLClient> client;
std::string path;
u64 title_id;
u64 build_id;
@@ -443,13 +445,25 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
std::map<std::string, EventStatus>& games) {
httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)};
- client.set_timeout_sec(static_cast<int>(TIMEOUT_SECONDS));
+ client.set_connection_timeout(static_cast<int>(TIMEOUT_SECONDS));
+ client.set_read_timeout(static_cast<int>(TIMEOUT_SECONDS));
+ client.set_write_timeout(static_cast<int>(TIMEOUT_SECONDS));
httplib::Headers headers{
{std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)},
{std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
};
+ if (!client.is_valid()) {
+ LOG_ERROR(Service_BCAT, "Client is invalid, going offline!");
+ return StatusResult::Offline;
+ }
+
+ if (!client.is_socket_open()) {
+ LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!");
+ return StatusResult::Offline;
+ }
+
const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers);
if (response == nullptr)
return StatusResult::Offline;
diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp
index ab17a187e..a0ee116fa 100644
--- a/src/core/hle/service/caps/caps_c.cpp
+++ b/src/core/hle/service/caps/caps_c.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
#include "core/hle/service/caps/caps_c.h"
namespace Service::Capture {
@@ -47,7 +49,7 @@ CAPS_C::CAPS_C() : ServiceFramework("caps:c") {
static const FunctionInfo functions[] = {
{1, nullptr, "CaptureRawImage"},
{2, nullptr, "CaptureRawImageWithTimeout"},
- {33, nullptr, "Unknown33"},
+ {33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"},
{1001, nullptr, "RequestTakingScreenShot"},
{1002, nullptr, "RequestTakingScreenShotWithTimeout"},
{1011, nullptr, "NotifyTakingScreenShotRefused"},
@@ -72,4 +74,16 @@ CAPS_C::CAPS_C() : ServiceFramework("caps:c") {
CAPS_C::~CAPS_C() = default;
+void CAPS_C::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto library_version{rp.Pop<u64>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
+ library_version, applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h
index a9d028689..b110301d4 100644
--- a/src/core/hle/service/caps/caps_c.h
+++ b/src/core/hle/service/caps/caps_c.h
@@ -16,6 +16,9 @@ class CAPS_C final : public ServiceFramework<CAPS_C> {
public:
explicit CAPS_C();
~CAPS_C() override;
+
+private:
+ void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
};
} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp
index fffb2ecf9..e386470f7 100644
--- a/src/core/hle/service/caps/caps_su.cpp
+++ b/src/core/hle/service/caps/caps_su.cpp
@@ -25,7 +25,12 @@ CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") {
CAPS_SU::~CAPS_SU() = default;
void CAPS_SU::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Capture, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ const auto library_version{rp.Pop<u64>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
+ library_version, applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp
index f36d8de2d..8e2b83629 100644
--- a/src/core/hle/service/caps/caps_u.cpp
+++ b/src/core/hle/service/caps/caps_u.cpp
@@ -31,8 +31,7 @@ public:
CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
// clang-format off
static const FunctionInfo functions[] = {
- {31, nullptr, "GetShimLibraryVersion"},
- {32, nullptr, "SetShimLibraryVersion"},
+ {32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"},
{102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
{103, nullptr, "DeleteAlbumContentsFileForApplication"},
{104, nullptr, "GetAlbumContentsFileSizeForApplication"},
@@ -53,6 +52,18 @@ CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
CAPS_U::~CAPS_U() = default;
+void CAPS_U::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto library_version{rp.Pop<u64>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
+ library_version, applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) {
// Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
// u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h
index 689364de4..e04e56bbc 100644
--- a/src/core/hle/service/caps/caps_u.h
+++ b/src/core/hle/service/caps/caps_u.h
@@ -18,6 +18,7 @@ public:
~CAPS_U() override;
private:
+ void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx);
};
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 2cee1193c..54a5fb84b 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -379,7 +379,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
- auto part = bis_factory->OpenPartitionStorage(id);
+ auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem());
if (part == nullptr) {
return FileSys::ERROR_INVALID_ARGUMENT;
}
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 26fd87f58..649128be4 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -844,8 +844,7 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
return;
}
- FileSys::StorageId id;
-
+ FileSys::StorageId id{};
switch (parameters.space_id) {
case FileSys::SaveDataSpaceId::NandUser:
id = FileSys::StorageId::NandUser;
@@ -857,6 +856,10 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
case FileSys::SaveDataSpaceId::NandSystem:
id = FileSys::StorageId::NandSystem;
break;
+ case FileSys::SaveDataSpaceId::TemporaryStorage:
+ case FileSys::SaveDataSpaceId::ProperSystem:
+ case FileSys::SaveDataSpaceId::SafeMode:
+ UNREACHABLE();
}
auto filesystem =
@@ -902,7 +905,14 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
// Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
- LOG_WARNING(Service_FS, "(STUBBED) called, flags={}", flags);
+ LOG_WARNING(Service_FS,
+ "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
+ "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
+ "attribute.type={}, attribute.rank={}, attribute.index={}",
+ flags, static_cast<u32>(parameters.space_id), parameters.attribute.title_id,
+ parameters.attribute.user_id[1], parameters.attribute.user_id[0],
+ parameters.attribute.save_id, static_cast<u32>(parameters.attribute.type),
+ static_cast<u32>(parameters.attribute.rank), parameters.attribute.index);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index 8bc69c372..f47a9e61c 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -31,6 +31,10 @@ public:
virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) = 0;
+ // When the controller is requesting a motion update for the shared memory
+ virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {}
+
// Called when input devices should be loaded
virtual void OnLoadInputDevices() = 0;
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index 0b896d5ad..59b694cd4 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -42,8 +42,8 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing,
cur_entry.modifier = 0;
if (Settings::values.keyboard_enabled) {
for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
- cur_entry.key[i / KEYS_PER_BYTE] |=
- (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE));
+ auto& entry = cur_entry.key[i / KEYS_PER_BYTE];
+ entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)));
}
for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 0e7794dc7..e311bc18c 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -24,6 +24,7 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
constexpr std::size_t NPAD_OFFSET = 0x9A00;
constexpr u32 BATTERY_FULL = 2;
constexpr u32 MAX_NPAD_ID = 7;
+constexpr std::size_t HANDHELD_INDEX = 8;
constexpr std::array<u32, 10> npad_id_list{
0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN,
};
@@ -33,19 +34,41 @@ enum class JoystickId : std::size_t {
Joystick_Right,
};
-static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type) {
+Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad(
+ Settings::ControllerType type) {
switch (type) {
case Settings::ControllerType::ProController:
- return Controller_NPad::NPadControllerType::ProController;
- case Settings::ControllerType::DualJoycon:
- return Controller_NPad::NPadControllerType::JoyDual;
+ return NPadControllerType::ProController;
+ case Settings::ControllerType::DualJoyconDetached:
+ return NPadControllerType::JoyDual;
case Settings::ControllerType::LeftJoycon:
- return Controller_NPad::NPadControllerType::JoyLeft;
+ return NPadControllerType::JoyLeft;
case Settings::ControllerType::RightJoycon:
- return Controller_NPad::NPadControllerType::JoyRight;
+ return NPadControllerType::JoyRight;
+ case Settings::ControllerType::Handheld:
+ return NPadControllerType::Handheld;
default:
UNREACHABLE();
- return Controller_NPad::NPadControllerType::JoyDual;
+ return NPadControllerType::ProController;
+ }
+}
+
+Settings::ControllerType Controller_NPad::MapNPadToSettingsType(
+ Controller_NPad::NPadControllerType type) {
+ switch (type) {
+ case NPadControllerType::ProController:
+ return Settings::ControllerType::ProController;
+ case NPadControllerType::JoyDual:
+ return Settings::ControllerType::DualJoyconDetached;
+ case NPadControllerType::JoyLeft:
+ return Settings::ControllerType::LeftJoycon;
+ case NPadControllerType::JoyRight:
+ return Settings::ControllerType::RightJoycon;
+ case NPadControllerType::Handheld:
+ return Settings::ControllerType::Handheld;
+ default:
+ UNREACHABLE();
+ return Settings::ControllerType::ProController;
}
}
@@ -60,9 +83,9 @@ std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
case 6:
case 7:
return npad_id;
- case 8:
+ case HANDHELD_INDEX:
case NPAD_HANDHELD:
- return 8;
+ return HANDHELD_INDEX;
case 9:
case NPAD_UNKNOWN:
return 9;
@@ -83,7 +106,7 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
case 6:
case 7:
return static_cast<u32>(index);
- case 8:
+ case HANDHELD_INDEX:
return NPAD_HANDHELD;
case 9:
return NPAD_UNKNOWN;
@@ -96,25 +119,35 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
Controller_NPad::~Controller_NPad() = default;
-void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
+void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
const auto controller_type = connected_controllers[controller_idx].type;
auto& controller = shared_memory_entries[controller_idx];
if (controller_type == NPadControllerType::None) {
+ styleset_changed_events[controller_idx].writable->Signal();
return;
}
controller.joy_styles.raw = 0; // Zero out
controller.device_type.raw = 0;
+ controller.properties.raw = 0;
switch (controller_type) {
case NPadControllerType::None:
UNREACHABLE();
break;
+ case NPadControllerType::ProController:
+ controller.joy_styles.pro_controller.Assign(1);
+ controller.device_type.pro_controller.Assign(1);
+ controller.properties.is_vertical.Assign(1);
+ controller.properties.use_plus.Assign(1);
+ controller.properties.use_minus.Assign(1);
+ controller.pad_assignment = NPadAssignments::Single;
+ break;
case NPadControllerType::Handheld:
controller.joy_styles.handheld.Assign(1);
controller.device_type.handheld.Assign(1);
- controller.pad_assignment = NPadAssignments::Dual;
controller.properties.is_vertical.Assign(1);
controller.properties.use_plus.Assign(1);
controller.properties.use_minus.Assign(1);
+ controller.pad_assignment = NPadAssignments::Dual;
break;
case NPadControllerType::JoyDual:
controller.joy_styles.joycon_dual.Assign(1);
@@ -144,14 +177,6 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
controller.device_type.pokeball.Assign(1);
controller.pad_assignment = NPadAssignments::Single;
break;
- case NPadControllerType::ProController:
- controller.joy_styles.pro_controller.Assign(1);
- controller.device_type.pro_controller.Assign(1);
- controller.properties.is_vertical.Assign(1);
- controller.properties.use_plus.Assign(1);
- controller.properties.use_minus.Assign(1);
- controller.pad_assignment = NPadAssignments::Single;
- break;
}
controller.single_color_error = ColorReadError::ReadOk;
@@ -168,7 +193,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
controller.battery_level[0] = BATTERY_FULL;
controller.battery_level[1] = BATTERY_FULL;
controller.battery_level[2] = BATTERY_FULL;
- styleset_changed_events[controller_idx].writable->Signal();
+
+ SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
}
void Controller_NPad::OnInit() {
@@ -192,36 +218,25 @@ void Controller_NPad::OnInit() {
style.pokeball.Assign(1);
}
- std::transform(
- Settings::values.players.begin(), Settings::values.players.end(),
- connected_controllers.begin(), [](const Settings::PlayerInput& player) {
- return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected};
- });
-
- std::stable_partition(connected_controllers.begin(), connected_controllers.begin() + 8,
- [](const ControllerHolder& holder) { return holder.is_connected; });
+ std::transform(Settings::values.players.begin(), Settings::values.players.end(),
+ connected_controllers.begin(), [](const Settings::PlayerInput& player) {
+ return ControllerHolder{MapSettingsTypeToNPad(player.controller_type),
+ player.connected};
+ });
// Account for handheld
- if (connected_controllers[8].is_connected)
- connected_controllers[8].type = NPadControllerType::Handheld;
+ if (connected_controllers[HANDHELD_INDEX].is_connected) {
+ connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld;
+ }
supported_npad_id_types.resize(npad_id_list.size());
std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
npad_id_list.size() * sizeof(u32));
- // Add a default dual joycon controller if none are present.
- if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
- [](const ControllerHolder& controller) { return controller.is_connected; })) {
- supported_npad_id_types.resize(npad_id_list.size());
- std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
- npad_id_list.size() * sizeof(u32));
- AddNewController(NPadControllerType::JoyDual);
- }
-
for (std::size_t i = 0; i < connected_controllers.size(); ++i) {
const auto& controller = connected_controllers[i];
if (controller.is_connected) {
- AddNewControllerAt(controller.type, IndexToNPad(i));
+ AddNewControllerAt(controller.type, i);
}
}
}
@@ -235,6 +250,9 @@ void Controller_NPad::OnLoadInputDevices() {
std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
+ std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
+ players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,
+ motions[i].begin(), Input::CreateDevice<Input::MotionDevice>);
}
}
@@ -242,7 +260,7 @@ void Controller_NPad::OnRelease() {}
void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
const auto controller_idx = NPadIdToIndex(npad_id);
- [[maybe_unused]] const auto controller_type = connected_controllers[controller_idx].type;
+ const auto controller_type = connected_controllers[controller_idx].type;
if (!connected_controllers[controller_idx].is_connected) {
return;
}
@@ -257,60 +275,70 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
using namespace Settings::NativeButton;
- pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
-
- pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
-
- pad_state.l_stick_right.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
- Input::AnalogDirection::RIGHT));
- pad_state.l_stick_left.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
- Input::AnalogDirection::LEFT));
- pad_state.l_stick_up.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
- Input::AnalogDirection::UP));
- pad_state.l_stick_down.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
- Input::AnalogDirection::DOWN));
-
- pad_state.r_stick_right.Assign(
- analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
- pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
- pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
- pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
-
- pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
-
- lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
- lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
- rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
- rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
+ if (controller_type != NPadControllerType::JoyLeft) {
+ pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
+
+ pad_state.r_stick_right.Assign(
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
+ pad_state.r_stick_left.Assign(
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
+ pad_state.r_stick_up.Assign(
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
+ pad_state.r_stick_down.Assign(
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
+ rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
+ rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
+ }
+
+ if (controller_type != NPadControllerType::JoyRight) {
+ pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
+
+ pad_state.l_stick_right.Assign(
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
+ pad_state.l_stick_left.Assign(
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
+ pad_state.l_stick_up.Assign(
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
+ pad_state.l_stick_down.Assign(
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
+ lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
+ lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
+ }
+
+ if (controller_type == NPadControllerType::JoyLeft ||
+ controller_type == NPadControllerType::JoyRight) {
+ pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
+ }
}
void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t data_len) {
- if (!IsControllerActivated())
+ if (!IsControllerActivated()) {
return;
+ }
for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
auto& npad = shared_memory_entries[i];
const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
@@ -344,6 +372,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
continue;
}
const u32 npad_index = static_cast<u32>(i);
+
RequestPadStateUpdate(npad_index);
auto& pad_state = npad_pad_states[npad_index];
@@ -360,13 +389,25 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
libnx_entry.connection_status.raw = 0;
+ libnx_entry.connection_status.IsConnected.Assign(1);
switch (controller_type) {
case NPadControllerType::None:
UNREACHABLE();
break;
+ case NPadControllerType::ProController:
+ main_controller.connection_status.raw = 0;
+ main_controller.connection_status.IsConnected.Assign(1);
+ main_controller.connection_status.IsWired.Assign(1);
+ main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
+ main_controller.pad.l_stick = pad_state.l_stick;
+ main_controller.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsWired.Assign(1);
+ break;
case NPadControllerType::Handheld:
handheld_entry.connection_status.raw = 0;
+ handheld_entry.connection_status.IsConnected.Assign(1);
handheld_entry.connection_status.IsWired.Assign(1);
handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
@@ -375,57 +416,52 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
handheld_entry.pad.l_stick = pad_state.l_stick;
handheld_entry.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsWired.Assign(1);
+ libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
+ libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
+ libnx_entry.connection_status.IsRightJoyWired.Assign(1);
break;
case NPadControllerType::JoyDual:
dual_entry.connection_status.raw = 0;
-
+ dual_entry.connection_status.IsConnected.Assign(1);
dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
dual_entry.connection_status.IsRightJoyConnected.Assign(1);
- dual_entry.connection_status.IsConnected.Assign(1);
-
- libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
- libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
- libnx_entry.connection_status.IsConnected.Assign(1);
-
dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
dual_entry.pad.l_stick = pad_state.l_stick;
dual_entry.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
break;
case NPadControllerType::JoyLeft:
left_entry.connection_status.raw = 0;
-
left_entry.connection_status.IsConnected.Assign(1);
+ left_entry.connection_status.IsLeftJoyConnected.Assign(1);
left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
left_entry.pad.l_stick = pad_state.l_stick;
left_entry.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
break;
case NPadControllerType::JoyRight:
right_entry.connection_status.raw = 0;
-
right_entry.connection_status.IsConnected.Assign(1);
+ right_entry.connection_status.IsRightJoyConnected.Assign(1);
right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
right_entry.pad.l_stick = pad_state.l_stick;
right_entry.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
break;
case NPadControllerType::Pokeball:
pokeball_entry.connection_status.raw = 0;
-
pokeball_entry.connection_status.IsConnected.Assign(1);
- pokeball_entry.connection_status.IsWired.Assign(1);
-
pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
pokeball_entry.pad.l_stick = pad_state.l_stick;
pokeball_entry.pad.r_stick = pad_state.r_stick;
break;
- case NPadControllerType::ProController:
- main_controller.connection_status.raw = 0;
-
- main_controller.connection_status.IsConnected.Assign(1);
- main_controller.connection_status.IsWired.Assign(1);
- main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
- main_controller.pad.l_stick = pad_state.l_stick;
- main_controller.pad.r_stick = pad_state.r_stick;
- break;
}
// LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
@@ -440,6 +476,131 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
shared_memory_entries.size() * sizeof(NPadEntry));
}
+void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t data_len) {
+ if (!IsControllerActivated()) {
+ return;
+ }
+ for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
+ auto& npad = shared_memory_entries[i];
+
+ const auto& controller_type = connected_controllers[i].type;
+
+ if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
+ continue;
+ }
+
+ const std::array<SixAxisGeneric*, 6> controller_sixaxes{
+ &npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
+ &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right,
+ };
+
+ for (auto* sixaxis_sensor : controller_sixaxes) {
+ sixaxis_sensor->common.entry_count = 16;
+ sixaxis_sensor->common.total_entry_count = 17;
+
+ const auto& last_entry =
+ sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
+
+ sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks();
+ sixaxis_sensor->common.last_entry_index =
+ (sixaxis_sensor->common.last_entry_index + 1) % 17;
+
+ auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
+
+ cur_entry.timestamp = last_entry.timestamp + 1;
+ cur_entry.timestamp2 = cur_entry.timestamp;
+ }
+
+ // Try to read sixaxis sensor states
+ std::array<MotionDevice, 2> motion_devices;
+
+ if (sixaxis_sensors_enabled && Settings::values.motion_enabled) {
+ sixaxis_at_rest = true;
+ for (std::size_t e = 0; e < motion_devices.size(); ++e) {
+ const auto& device = motions[i][e];
+ if (device) {
+ std::tie(motion_devices[e].accel, motion_devices[e].gyro,
+ motion_devices[e].rotation, motion_devices[e].orientation) =
+ device->GetStatus();
+ sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f;
+ }
+ }
+ }
+
+ auto& full_sixaxis_entry =
+ npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index];
+ auto& handheld_sixaxis_entry =
+ npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index];
+ auto& dual_left_sixaxis_entry =
+ npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index];
+ auto& dual_right_sixaxis_entry =
+ npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index];
+ auto& left_sixaxis_entry =
+ npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index];
+ auto& right_sixaxis_entry =
+ npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index];
+
+ switch (controller_type) {
+ case NPadControllerType::None:
+ UNREACHABLE();
+ break;
+ case NPadControllerType::ProController:
+ if (sixaxis_sensors_enabled && motions[i][0]) {
+ full_sixaxis_entry.accel = motion_devices[0].accel;
+ full_sixaxis_entry.gyro = motion_devices[0].gyro;
+ full_sixaxis_entry.rotation = motion_devices[0].rotation;
+ full_sixaxis_entry.orientation = motion_devices[0].orientation;
+ }
+ break;
+ case NPadControllerType::Handheld:
+ if (sixaxis_sensors_enabled && motions[i][0]) {
+ handheld_sixaxis_entry.accel = motion_devices[0].accel;
+ handheld_sixaxis_entry.gyro = motion_devices[0].gyro;
+ handheld_sixaxis_entry.rotation = motion_devices[0].rotation;
+ handheld_sixaxis_entry.orientation = motion_devices[0].orientation;
+ }
+ break;
+ case NPadControllerType::JoyDual:
+ if (sixaxis_sensors_enabled && motions[i][0]) {
+ // Set motion for the left joycon
+ dual_left_sixaxis_entry.accel = motion_devices[0].accel;
+ dual_left_sixaxis_entry.gyro = motion_devices[0].gyro;
+ dual_left_sixaxis_entry.rotation = motion_devices[0].rotation;
+ dual_left_sixaxis_entry.orientation = motion_devices[0].orientation;
+ }
+ if (sixaxis_sensors_enabled && motions[i][1]) {
+ // Set motion for the right joycon
+ dual_right_sixaxis_entry.accel = motion_devices[1].accel;
+ dual_right_sixaxis_entry.gyro = motion_devices[1].gyro;
+ dual_right_sixaxis_entry.rotation = motion_devices[1].rotation;
+ dual_right_sixaxis_entry.orientation = motion_devices[1].orientation;
+ }
+ break;
+ case NPadControllerType::JoyLeft:
+ if (sixaxis_sensors_enabled && motions[i][0]) {
+ left_sixaxis_entry.accel = motion_devices[0].accel;
+ left_sixaxis_entry.gyro = motion_devices[0].gyro;
+ left_sixaxis_entry.rotation = motion_devices[0].rotation;
+ left_sixaxis_entry.orientation = motion_devices[0].orientation;
+ }
+ break;
+ case NPadControllerType::JoyRight:
+ if (sixaxis_sensors_enabled && motions[i][1]) {
+ right_sixaxis_entry.accel = motion_devices[1].accel;
+ right_sixaxis_entry.gyro = motion_devices[1].gyro;
+ right_sixaxis_entry.rotation = motion_devices[1].rotation;
+ right_sixaxis_entry.orientation = motion_devices[1].orientation;
+ }
+ break;
+ case NPadControllerType::Pokeball:
+ break;
+ }
+ }
+ std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
+ shared_memory_entries.size() * sizeof(NPadEntry));
+}
+
void Controller_NPad::SetSupportedStyleSet(NPadType style_set) {
style.raw = style_set.raw;
}
@@ -453,26 +614,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
supported_npad_id_types.clear();
supported_npad_id_types.resize(length / sizeof(u32));
std::memcpy(supported_npad_id_types.data(), data, length);
- for (std::size_t i = 0; i < connected_controllers.size(); i++) {
- auto& controller = connected_controllers[i];
- if (!controller.is_connected) {
- continue;
- }
- const auto requested_controller =
- i <= MAX_NPAD_ID ? MapSettingsTypeToNPad(Settings::values.players[i].type)
- : NPadControllerType::Handheld;
- if (!IsControllerSupported(requested_controller)) {
- const auto is_handheld = requested_controller == NPadControllerType::Handheld;
- if (is_handheld) {
- controller.type = NPadControllerType::None;
- controller.is_connected = false;
- AddNewController(requested_controller);
- } else {
- controller.type = requested_controller;
- InitNewlyAddedControler(i);
- }
- }
- }
}
void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
@@ -492,6 +633,14 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
return hold_type;
}
+void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
+ handheld_activation_mode = activation_mode;
+}
+
+Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActivationMode() const {
+ return handheld_activation_mode;
+}
+
void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
const std::size_t npad_index = NPadIdToIndex(npad_id);
ASSERT(npad_index < shared_memory_entries.size());
@@ -500,70 +649,86 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode)
}
}
-void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
+void Controller_NPad::VibrateController(const std::vector<u32>& controllers,
const std::vector<Vibration>& vibrations) {
- LOG_DEBUG(Service_HID, "(STUBBED) called");
+ LOG_TRACE(Service_HID, "called");
- if (!can_controllers_vibrate) {
+ if (!Settings::values.vibration_enabled || !can_controllers_vibrate) {
return;
}
- for (std::size_t i = 0; i < controller_ids.size(); i++) {
- std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i));
- if (connected_controllers[controller_pos].is_connected) {
- // TODO(ogniK): Vibrate the physical controller
+ bool success = true;
+ for (std::size_t i = 0; i < controllers.size(); ++i) {
+ if (!connected_controllers[i].is_connected) {
+ continue;
+ }
+ using namespace Settings::NativeButton;
+ const auto& button_state = buttons[i];
+ if (button_state[A - BUTTON_HID_BEGIN]) {
+ if (button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
+ vibrations[0].amp_high, vibrations[0].amp_low, vibrations[0].freq_high,
+ vibrations[0].freq_low)) {
+ success = false;
+ }
}
}
- last_processed_vibration = vibrations.back();
+ if (success) {
+ last_processed_vibration = vibrations.back();
+ }
+}
+
+Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
+ return last_processed_vibration;
}
std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
- // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
- // be signalled at least once, and signaled after a new controller is connected?
const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
return styleset_event.readable;
}
-Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
- return last_processed_vibration;
+void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
+ styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal();
}
-void Controller_NPad::AddNewController(NPadControllerType controller) {
- controller = DecideBestController(controller);
- if (controller == NPadControllerType::Handheld) {
- connected_controllers[8] = {controller, true};
- InitNewlyAddedControler(8);
- return;
- }
- const auto pos =
- std::find_if(connected_controllers.begin(), connected_controllers.end() - 2,
- [](const ControllerHolder& holder) { return !holder.is_connected; });
- if (pos == connected_controllers.end() - 2) {
- LOG_ERROR(Service_HID, "Cannot connect any more controllers!");
+void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
+ UpdateControllerAt(controller, npad_index, true);
+}
+
+void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
+ bool connected) {
+ if (!connected) {
+ DisconnectNPadAtIndex(npad_index);
return;
}
- const auto controller_id = std::distance(connected_controllers.begin(), pos);
- connected_controllers[controller_id] = {controller, true};
- InitNewlyAddedControler(controller_id);
-}
-void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) {
- controller = DecideBestController(controller);
if (controller == NPadControllerType::Handheld) {
- connected_controllers[NPadIdToIndex(NPAD_HANDHELD)] = {controller, true};
- InitNewlyAddedControler(NPadIdToIndex(NPAD_HANDHELD));
+ Settings::values.players[HANDHELD_INDEX].controller_type =
+ MapNPadToSettingsType(controller);
+ Settings::values.players[HANDHELD_INDEX].connected = true;
+ connected_controllers[HANDHELD_INDEX] = {controller, true};
+ InitNewlyAddedController(HANDHELD_INDEX);
return;
}
- connected_controllers[NPadIdToIndex(npad_id)] = {controller, true};
- InitNewlyAddedControler(NPadIdToIndex(npad_id));
+ Settings::values.players[npad_index].controller_type = MapNPadToSettingsType(controller);
+ Settings::values.players[npad_index].connected = true;
+ connected_controllers[npad_index] = {controller, true};
+ InitNewlyAddedController(npad_index);
}
-void Controller_NPad::ConnectNPad(u32 npad_id) {
- connected_controllers[NPadIdToIndex(npad_id)].is_connected = true;
+void Controller_NPad::DisconnectNPad(u32 npad_id) {
+ DisconnectNPadAtIndex(NPadIdToIndex(npad_id));
}
-void Controller_NPad::DisconnectNPad(u32 npad_id) {
- connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
+void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) {
+ Settings::values.players[npad_index].connected = false;
+ connected_controllers[npad_index].is_connected = false;
+
+ auto& controller = shared_memory_entries[npad_index];
+ controller.joy_styles.raw = 0; // Zero out
+ controller.device_type.raw = 0;
+ controller.properties.raw = 0;
+
+ SignalStyleSetChangedEvent(IndexToNPad(npad_index));
}
void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
@@ -574,6 +739,30 @@ Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMo
return gyroscope_zero_drift_mode;
}
+bool Controller_NPad::IsSixAxisSensorAtRest() const {
+ return sixaxis_at_rest;
+}
+
+void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) {
+ sixaxis_sensors_enabled = six_axis_status;
+}
+
+void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {
+ const auto npad_index_1 = NPadIdToIndex(npad_id_1);
+ const auto npad_index_2 = NPadIdToIndex(npad_id_2);
+
+ // If the controllers at both npad indices form a pair of left and right joycons, merge them.
+ // Otherwise, do nothing.
+ if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft &&
+ connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) ||
+ (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft &&
+ connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) {
+ // Disconnect the joycon at the second id and connect the dual joycon at the first index.
+ DisconnectNPad(npad_id_2);
+ AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1);
+ }
+}
+
void Controller_NPad::StartLRAssignmentMode() {
// Nothing internally is used for lr assignment mode. Since we have the ability to set the
// controller types from boot, it doesn't really matter about showing a selection screen
@@ -599,8 +788,8 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
- InitNewlyAddedControler(npad_index_1);
- InitNewlyAddedControler(npad_index_2);
+ AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1);
+ AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2);
return true;
}
@@ -614,11 +803,11 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
case 0:
return LedPattern{1, 0, 0, 0};
case 1:
- return LedPattern{0, 1, 0, 0};
+ return LedPattern{1, 1, 0, 0};
case 2:
- return LedPattern{0, 0, 1, 0};
+ return LedPattern{1, 1, 1, 0};
case 3:
- return LedPattern{0, 0, 0, 1};
+ return LedPattern{1, 1, 1, 1};
case 4:
return LedPattern{1, 0, 0, 1};
case 5:
@@ -628,11 +817,19 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
case 7:
return LedPattern{0, 1, 1, 0};
default:
- UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id);
return LedPattern{0, 0, 0, 0};
}
}
+bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const {
+ return unintended_home_button_input_protection[NPadIdToIndex(npad_id)];
+}
+
+void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
+ u32 npad_id) {
+ unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
+}
+
void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
can_controllers_vibrate = can_vibrate;
}
@@ -651,13 +848,13 @@ void Controller_NPad::ClearAllConnectedControllers() {
}
void Controller_NPad::DisconnectAllConnectedControllers() {
- for (ControllerHolder& controller : connected_controllers) {
+ for (auto& controller : connected_controllers) {
controller.is_connected = false;
}
}
void Controller_NPad::ConnectAllDisconnectedControllers() {
- for (ControllerHolder& controller : connected_controllers) {
+ for (auto& controller : connected_controllers) {
if (controller.type != NPadControllerType::None && !controller.is_connected) {
controller.is_connected = true;
}
@@ -665,7 +862,7 @@ void Controller_NPad::ConnectAllDisconnectedControllers() {
}
void Controller_NPad::ClearAllControllers() {
- for (ControllerHolder& controller : connected_controllers) {
+ for (auto& controller : connected_controllers) {
controller.type = NPadControllerType::None;
controller.is_connected = false;
}
@@ -713,92 +910,4 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
return false;
}
-Controller_NPad::NPadControllerType Controller_NPad::DecideBestController(
- NPadControllerType priority) const {
- if (IsControllerSupported(priority)) {
- return priority;
- }
- const auto is_docked = Settings::values.use_docked_mode;
- if (is_docked && priority == NPadControllerType::Handheld) {
- priority = NPadControllerType::JoyDual;
- if (IsControllerSupported(priority)) {
- return priority;
- }
- }
- std::vector<NPadControllerType> priority_list;
- switch (priority) {
- case NPadControllerType::ProController:
- priority_list.push_back(NPadControllerType::JoyDual);
- if (!is_docked) {
- priority_list.push_back(NPadControllerType::Handheld);
- }
- priority_list.push_back(NPadControllerType::JoyLeft);
- priority_list.push_back(NPadControllerType::JoyRight);
- priority_list.push_back(NPadControllerType::Pokeball);
- break;
- case NPadControllerType::Handheld:
- priority_list.push_back(NPadControllerType::JoyDual);
- priority_list.push_back(NPadControllerType::ProController);
- priority_list.push_back(NPadControllerType::JoyLeft);
- priority_list.push_back(NPadControllerType::JoyRight);
- priority_list.push_back(NPadControllerType::Pokeball);
- break;
- case NPadControllerType::JoyDual:
- if (!is_docked) {
- priority_list.push_back(NPadControllerType::Handheld);
- }
- priority_list.push_back(NPadControllerType::ProController);
- priority_list.push_back(NPadControllerType::JoyLeft);
- priority_list.push_back(NPadControllerType::JoyRight);
- priority_list.push_back(NPadControllerType::Pokeball);
- break;
- case NPadControllerType::JoyLeft:
- priority_list.push_back(NPadControllerType::JoyRight);
- priority_list.push_back(NPadControllerType::JoyDual);
- if (!is_docked) {
- priority_list.push_back(NPadControllerType::Handheld);
- }
- priority_list.push_back(NPadControllerType::ProController);
- priority_list.push_back(NPadControllerType::Pokeball);
- break;
- case NPadControllerType::JoyRight:
- priority_list.push_back(NPadControllerType::JoyLeft);
- priority_list.push_back(NPadControllerType::JoyDual);
- if (!is_docked) {
- priority_list.push_back(NPadControllerType::Handheld);
- }
- priority_list.push_back(NPadControllerType::ProController);
- priority_list.push_back(NPadControllerType::Pokeball);
- break;
- case NPadControllerType::Pokeball:
- priority_list.push_back(NPadControllerType::JoyLeft);
- priority_list.push_back(NPadControllerType::JoyRight);
- priority_list.push_back(NPadControllerType::JoyDual);
- if (!is_docked) {
- priority_list.push_back(NPadControllerType::Handheld);
- }
- priority_list.push_back(NPadControllerType::ProController);
- break;
- default:
- priority_list.push_back(NPadControllerType::JoyDual);
- if (!is_docked) {
- priority_list.push_back(NPadControllerType::Handheld);
- }
- priority_list.push_back(NPadControllerType::ProController);
- priority_list.push_back(NPadControllerType::JoyLeft);
- priority_list.push_back(NPadControllerType::JoyRight);
- priority_list.push_back(NPadControllerType::JoyDual);
- break;
- }
-
- const auto iter = std::find_if(priority_list.begin(), priority_list.end(),
- [this](auto type) { return IsControllerSupported(type); });
- if (iter == priority_list.end()) {
- UNIMPLEMENTED_MSG("Could not find supported controller!");
- return priority;
- }
-
- return *iter;
-}
-
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 5d4c58a43..fd5c5a6eb 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -32,6 +32,10 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
+ // When the controller is requesting a motion update for the shared memory
+ void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) override;
+
// Called when input devices should be loaded
void OnLoadInputDevices() override;
@@ -74,6 +78,12 @@ public:
Single = 1,
};
+ enum class NpadHandheldActivationMode : u64 {
+ Dual = 0,
+ Single = 1,
+ None = 2,
+ };
+
enum class NPadControllerType {
None,
ProController,
@@ -110,22 +120,34 @@ public:
void SetHoldType(NpadHoldType joy_hold_type);
NpadHoldType GetHoldType() const;
+ void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
+ NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
+
void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode);
- void VibrateController(const std::vector<u32>& controller_ids,
+ void VibrateController(const std::vector<u32>& controllers,
const std::vector<Vibration>& vibrations);
- std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
Vibration GetLastVibration() const;
- void AddNewController(NPadControllerType controller);
- void AddNewControllerAt(NPadControllerType controller, u32 npad_id);
+ std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
+ void SignalStyleSetChangedEvent(u32 npad_id) const;
+
+ // Adds a new controller at an index.
+ void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index);
+ // Adds a new controller at an index with connection status.
+ void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
- void ConnectNPad(u32 npad_id);
void DisconnectNPad(u32 npad_id);
+ void DisconnectNPadAtIndex(std::size_t index);
+
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
+ bool IsSixAxisSensorAtRest() const;
+ void SetSixAxisEnabled(bool six_axis_status);
LedPattern GetLedPattern(u32 npad_id);
+ bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
+ void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
void SetVibrationEnabled(bool can_vibrate);
bool IsVibrationEnabled() const;
void ClearAllConnectedControllers();
@@ -133,6 +155,7 @@ public:
void ConnectAllDisconnectedControllers();
void ClearAllControllers();
+ void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2);
void StartLRAssignmentMode();
void StopLRAssignmentMode();
bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2);
@@ -141,6 +164,8 @@ public:
// Specifically for cheat engine and other features.
u32 GetAndResetPressState();
+ static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type);
+ static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type);
static std::size_t NPadIdToIndex(u32 npad_id);
static u32 IndexToNPad(std::size_t index);
@@ -244,6 +269,24 @@ private:
};
static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size");
+ struct SixAxisStates {
+ s64_le timestamp{};
+ INSERT_PADDING_WORDS(2);
+ s64_le timestamp2{};
+ Common::Vec3f accel{};
+ Common::Vec3f gyro{};
+ Common::Vec3f rotation{};
+ std::array<Common::Vec3f, 3> orientation{};
+ s64_le always_one{1};
+ };
+ static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size");
+
+ struct SixAxisGeneric {
+ CommonHeader common{};
+ std::array<SixAxisStates, 17> sixaxis{};
+ };
+ static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size");
+
enum class ColorReadError : u32_le {
ReadOk = 0,
ColorDoesntExist = 1,
@@ -273,6 +316,13 @@ private:
};
};
+ struct MotionDevice {
+ Common::Vec3f accel;
+ Common::Vec3f gyro;
+ Common::Vec3f rotation;
+ std::array<Common::Vec3f, 3> orientation;
+ };
+
struct NPadEntry {
NPadType joy_styles;
NPadAssignments pad_assignment;
@@ -292,9 +342,12 @@ private:
NPadGeneric pokeball_states;
NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be
// relying on this for the time being
- INSERT_PADDING_BYTES(
- 0x708 *
- 6); // TODO(ogniK): SixAxis states, require more information before implementation
+ SixAxisGeneric sixaxis_full;
+ SixAxisGeneric sixaxis_handheld;
+ SixAxisGeneric sixaxis_dual_left;
+ SixAxisGeneric sixaxis_dual_right;
+ SixAxisGeneric sixaxis_left;
+ SixAxisGeneric sixaxis_right;
NPadDevice device_type;
NPadProperties properties;
INSERT_PADDING_WORDS(1);
@@ -309,31 +362,38 @@ private:
bool is_connected;
};
- void InitNewlyAddedControler(std::size_t controller_idx);
+ void InitNewlyAddedController(std::size_t controller_idx);
bool IsControllerSupported(NPadControllerType controller) const;
- NPadControllerType DecideBestController(NPadControllerType priority) const;
void RequestPadStateUpdate(u32 npad_id);
u32 press_state{};
NPadType style{};
std::array<NPadEntry, 10> shared_memory_entries{};
- std::array<
+ using ButtonArray = std::array<
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
- 10>
- buttons;
- std::array<
+ 10>;
+ using StickArray = std::array<
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
- 10>
- sticks;
+ 10>;
+ using MotionArray = std::array<
+ std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>,
+ 10>;
+ ButtonArray buttons;
+ StickArray sticks;
+ MotionArray motions;
std::vector<u32> supported_npad_id_types{};
NpadHoldType hold_type{NpadHoldType::Vertical};
+ NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
// Each controller should have their own styleset changed event
std::array<Kernel::EventPair, 10> styleset_changed_events;
Vibration last_processed_vibration{};
std::array<ControllerHolder, 10> connected_controllers{};
+ std::array<bool, 10> unintended_home_button_input_protection{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
bool can_controllers_vibrate{true};
+ bool sixaxis_sensors_enabled{true};
+ bool sixaxis_at_rest{true};
std::array<ControllerPad, 10> npad_pad_states{};
bool is_in_lr_assignment_mode{false};
Core::System& system;
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index e326f8f5c..0df395e85 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -40,9 +40,14 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
- const auto [x, y, pressed] = touch_device->GetStatus();
+ bool pressed = false;
+ float x, y;
+ std::tie(x, y, pressed) = touch_device->GetStatus();
auto& touch_entry = cur_entry.states[0];
touch_entry.attribute.raw = 0;
+ if (!pressed && touch_btn_device) {
+ std::tie(x, y, pressed) = touch_btn_device->GetStatus();
+ }
if (pressed && Settings::values.touchscreen.enabled) {
touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width);
touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height);
@@ -63,5 +68,10 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
void Controller_Touchscreen::OnLoadInputDevices() {
touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device);
+ if (Settings::values.use_touch_from_button) {
+ touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button");
+ } else {
+ touch_btn_device.reset();
+ }
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index a1d97269e..4d9042adc 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -68,6 +68,7 @@ private:
"TouchScreenSharedMemory is an invalid size");
TouchScreenSharedMemory shared_memory{};
std::unique_ptr<Input::TouchDevice> touch_device;
+ std::unique_ptr<Input::TouchDevice> touch_btn_device;
s64_le last_touch{};
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1e95b7580..8918946a1 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -38,11 +38,10 @@
namespace Service::HID {
// Updating period for each HID device.
-// TODO(ogniK): Find actual polling rate of hid
-constexpr auto pad_update_ns = std::chrono::nanoseconds{1000000000 / 66};
-[[maybe_unused]] constexpr auto accelerometer_update_ns =
- std::chrono::nanoseconds{1000000000 / 100};
-[[maybe_unused]] constexpr auto gyroscope_update_ticks = std::chrono::nanoseconds{1000000000 / 100};
+// HID is polled every 15ms, this value was derived from
+// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet
+constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz)
+constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz)
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
IAppletResource::IAppletResource(Core::System& system)
@@ -81,10 +80,14 @@ IAppletResource::IAppletResource(Core::System& system)
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
UpdateControllers(user_data, ns_late);
});
-
- // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
+ motion_update_event = Core::Timing::CreateEvent(
+ "HID::MotionPadCallback",
+ [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ UpdateMotion(user_data, ns_late);
+ });
system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
+ system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
ReloadInputDevices();
}
@@ -124,6 +127,16 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
}
+void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ auto& core_timing = system.CoreTiming();
+
+ for (const auto& controller : controllers) {
+ controller->OnMotionUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
+ }
+
+ core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
+}
+
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
public:
IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") {
@@ -166,8 +179,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{56, nullptr, "ActivateJoyXpad"},
{58, nullptr, "GetJoyXpadLifoHandle"},
{59, nullptr, "GetJoyXpadIds"},
- {60, nullptr, "ActivateSixAxisSensor"},
- {61, nullptr, "DeactivateSixAxisSensor"},
+ {60, &Hid::ActivateSixAxisSensor, "ActivateSixAxisSensor"},
+ {61, &Hid::DeactivateSixAxisSensor, "DeactivateSixAxisSensor"},
{62, nullptr, "GetSixAxisSensorLifoHandle"},
{63, nullptr, "ActivateJoySixAxisSensor"},
{64, nullptr, "DeactivateJoySixAxisSensor"},
@@ -175,7 +188,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
{67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
{68, nullptr, "IsSixAxisSensorFusionEnabled"},
- {69, nullptr, "EnableSixAxisSensorFusion"},
+ {69, &Hid::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"},
{70, nullptr, "SetSixAxisSensorFusionParameters"},
{71, nullptr, "GetSixAxisSensorFusionParameters"},
{72, nullptr, "ResetSixAxisSensorFusionParameters"},
@@ -211,8 +224,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
{129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"},
{130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
- {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
- {132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
+ {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
+ {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
{134, nullptr, "SetNpadAnalogStickUseCenterClamp"},
{135, nullptr, "SetNpadCaptureButtonAssignment"},
@@ -331,6 +344,31 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {
rb.Push(0);
}
+void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto handle{rp.Pop<u32>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+ applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
+ LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
+ applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto handle{rp.Pop<u32>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+ applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
+
+ LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
+ applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -435,6 +473,19 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
+void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ [[maybe_unused]] const auto enable{rp.Pop<bool>()};
+ const auto handle{rp.Pop<u32>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
+ applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto handle{rp.Pop<u32>()};
@@ -486,13 +537,13 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
const auto handle{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
- LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
- applet_resource_user_id);
+ LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
+ applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- // TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
- rb.Push(true);
+ rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+ .IsSixAxisSensorAtRest());
}
void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
@@ -673,13 +724,15 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto unknown_1{rp.Pop<u32>()};
- const auto unknown_2{rp.Pop<u32>()};
+ const auto npad_id_1{rp.Pop<u32>()};
+ const auto npad_id_2{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
- LOG_WARNING(Service_HID,
- "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
- unknown_1, unknown_2, applet_resource_user_id);
+ LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
+ npad_id_1, npad_id_2, applet_resource_user_id);
+
+ auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+ controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -714,8 +767,11 @@ void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
const auto applet_resource_user_id{rp.Pop<u64>()};
const auto mode{rp.Pop<u64>()};
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}",
- applet_resource_user_id, mode);
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, mode={}", applet_resource_user_id,
+ mode);
+
+ applet_resource->GetController<Controller_NPad>(HidController::NPad)
+ .SetNpadHandheldActivationMode(Controller_NPad::NpadHandheldActivationMode{mode});
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -725,11 +781,13 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
- applet_resource_user_id);
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
- IPC::ResponseBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
+ rb.Push<u64>(
+ static_cast<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+ .GetNpadHandheldActivationMode()));
}
void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
@@ -751,6 +809,40 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
}
}
+void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id{rp.Pop<u32>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
+ applet_resource_user_id);
+
+ auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<bool>(controller.IsUnintendedHomeButtonInputProtectionEnabled(npad_id));
+}
+
+void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto unintended_home_button_input_protection{rp.Pop<bool>()};
+ const auto npad_id{rp.Pop<u32>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID,
+ "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"
+ "applet_resource_user_id={}",
+ npad_id, unintended_home_button_input_protection, applet_resource_user_id);
+
+ auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+ controller.SetUnintendedHomeButtonInputProtectionEnabled(
+ unintended_home_button_input_protection, npad_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -772,18 +864,18 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto controller_id{rp.Pop<u32>()};
+ const auto controller{rp.Pop<u32>()};
const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
- LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
+ LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller,
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .VibrateController({controller_id}, {vibration_values});
+ .VibrateController({controller}, {vibration_values});
}
void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
@@ -801,8 +893,6 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
std::memcpy(controller_list.data(), controllers.data(), controllers.size());
std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
- std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(),
- [](u32 controller_id) { return controller_id - 3; });
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.VibrateController(controller_list, vibration_list);
@@ -845,8 +935,7 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto can_vibrate{rp.Pop<bool>()};
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SetVibrationEnabled(can_vibrate);
+ Settings::values.vibration_enabled = can_vibrate;
LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
@@ -859,8 +948,7 @@ void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push(
- applet_resource->GetController<Controller_NPad>(HidController::NPad).IsVibrationEnabled());
+ rb.Push(Settings::values.vibration_enabled);
}
void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index efb07547f..fd0372b18 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -65,10 +65,12 @@ private:
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
+ void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
std::shared_ptr<Kernel::SharedMemory> shared_mem;
std::shared_ptr<Core::Timing::EventType> pad_update_event;
+ std::shared_ptr<Core::Timing::EventType> motion_update_event;
Core::System& system;
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
@@ -86,6 +88,8 @@ private:
void CreateAppletResource(Kernel::HLERequestContext& ctx);
void ActivateXpad(Kernel::HLERequestContext& ctx);
void GetXpadIDs(Kernel::HLERequestContext& ctx);
+ void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx);
+ void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);
void ActivateDebugPad(Kernel::HLERequestContext& ctx);
void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
void ActivateMouse(Kernel::HLERequestContext& ctx);
@@ -95,6 +99,7 @@ private:
void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
+ void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx);
void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
@@ -118,6 +123,8 @@ private:
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
+ void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
+ void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
void SendVibrationValue(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp
index 4730070cb..d73b90015 100644
--- a/src/core/hle/service/mii/manager.cpp
+++ b/src/core/hle/service/mii/manager.cpp
@@ -131,7 +131,7 @@ template <typename T>
T GetRandomValue(T min, T max) {
std::random_device device;
std::mt19937 gen(device());
- std::uniform_int_distribution<u64> distribution(0, static_cast<u64>(max));
+ std::uniform_int_distribution<u64> distribution(static_cast<u64>(min), static_cast<u64>(max));
return static_cast<T>(distribution(gen));
}
@@ -428,7 +428,7 @@ bool MiiManager::IsFullDatabase() const {
}
u32 MiiManager::GetCount(SourceFlag source_flag) const {
- u32 count{};
+ std::size_t count{};
if ((source_flag & SourceFlag::Database) != SourceFlag::None) {
// TODO(bunnei): We don't implement the Mii database, but when we do, update this
count += 0;
@@ -436,7 +436,7 @@ u32 MiiManager::GetCount(SourceFlag source_flag) const {
if ((source_flag & SourceFlag::Default) != SourceFlag::None) {
count += DefaultMiiCount;
}
- return count;
+ return static_cast<u32>(count);
}
ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info,
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 5e2d769a4..a0469ffbd 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <array>
#include <atomic>
#include "common/logging/log.h"
@@ -72,10 +73,10 @@ private:
std::array<u8, 10> uuid;
u8 uuid_length; // TODO(ogniK): Figure out if this is actual the uuid length or does it
// mean something else
- INSERT_PADDING_BYTES(0x15);
+ std::array<u8, 0x15> padding_1;
u32_le protocol;
u32_le tag_type;
- INSERT_PADDING_BYTES(0x2c);
+ std::array<u8, 0x2c> padding_2;
};
static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size");
@@ -213,13 +214,15 @@ private:
LOG_DEBUG(Service_NFP, "called");
IPC::ResponseBuilder rb{ctx, 2};
- auto amiibo = nfp_interface.GetAmiiboBuffer();
- TagInfo tag_info{};
- tag_info.uuid = amiibo.uuid;
- tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size());
-
- tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
- tag_info.tag_type = 2;
+ const auto& amiibo = nfp_interface.GetAmiiboBuffer();
+ const TagInfo tag_info{
+ .uuid = amiibo.uuid,
+ .uuid_length = static_cast<u8>(tag_info.uuid.size()),
+ .padding_1 = {},
+ .protocol = 1, // TODO(ogniK): Figure out actual values
+ .tag_type = 2,
+ .padding_2 = {},
+ };
ctx.WriteBuffer(tag_info);
rb.Push(RESULT_SUCCESS);
}
@@ -236,7 +239,7 @@ private:
LOG_DEBUG(Service_NFP, "called");
IPC::ResponseBuilder rb{ctx, 2};
- auto amiibo = nfp_interface.GetAmiiboBuffer();
+ const auto& amiibo = nfp_interface.GetAmiiboBuffer();
ctx.WriteBuffer(amiibo.model_info);
rb.Push(RESULT_SUCCESS);
}
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 01ddcdbd6..2e9d95195 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -9,6 +9,7 @@
#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/service.h"
+#include "core/network/network.h"
#include "core/settings.h"
namespace Service::NIFM {
@@ -174,6 +175,16 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+ void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
+ const auto [ipv4, error] = Network::GetHostIPv4Address();
+ UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw(ipv4);
+ }
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
@@ -235,7 +246,7 @@ IGeneralService::IGeneralService(Core::System& system)
{9, nullptr, "SetNetworkProfile"},
{10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"},
{11, nullptr, "GetScanDataOld"},
- {12, nullptr, "GetCurrentIpAddress"},
+ {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"},
{13, nullptr, "GetCurrentAccessPointOld"},
{14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"},
{15, nullptr, "GetCurrentIpConfigInfo"},
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 886450be2..58ee1f712 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -5,6 +5,7 @@
#include "common/logging/log.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/vfs.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/ns/errors.h"
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index d4ba88147..f2529a12e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -46,6 +46,8 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std:
return GetVARegions(input, output);
case IoctlCommand::IocUnmapBufferCommand:
return UnmapBuffer(input, output);
+ case IoctlCommand::IocFreeSpaceCommand:
+ return FreeSpace(input, output);
default:
break;
}
@@ -91,6 +93,20 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
return result;
}
+u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlFreeSpace params{};
+ std::memcpy(&params, input.data(), input.size());
+
+ LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
+ params.pages, params.page_size);
+
+ system.GPU().MemoryManager().Unmap(params.offset,
+ static_cast<std::size_t>(params.pages) * params.page_size);
+
+ std::memcpy(output.data(), &params, output.size());
+ return NvErrCodes::Success;
+}
+
u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
@@ -265,7 +281,7 @@ std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gp
}
}
- return {};
+ return std::nullopt;
}
void nvhost_as_gpu::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
@@ -286,7 +302,7 @@ std::optional<std::size_t> nvhost_as_gpu::RemoveBufferMap(GPUVAddr gpu_addr) {
return size;
}
- return {};
+ return std::nullopt;
}
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 9a0cdff0c..fcdb40d93 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -82,6 +82,7 @@ private:
IocBindChannelCommand = 0x40044101,
IocGetVaRegionsCommand = 0xC0404108,
IocUnmapBufferCommand = 0xC0084105,
+ IocFreeSpaceCommand = 0xC0104103,
};
struct IoctlInitalizeEx {
@@ -107,6 +108,13 @@ private:
};
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
+ struct IoctlFreeSpace {
+ u64_le offset;
+ u32_le pages;
+ u32_le page_size;
+ };
+ static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
+
struct IoctlRemapEntry {
u16_le flags;
u16_le kind;
@@ -162,6 +170,7 @@ private:
u32 Remap(const std::vector<u8>& input, std::vector<u8>& output);
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index bdae8b887..fcb612864 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -22,6 +22,18 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
switch (static_cast<IoctlCommand>(command.raw)) {
case IoctlCommand::IocSetNVMAPfdCommand:
return SetNVMAPfd(input, output);
+ case IoctlCommand::IocSubmit:
+ return Submit(input, output);
+ case IoctlCommand::IocGetSyncpoint:
+ return GetSyncpoint(input, output);
+ case IoctlCommand::IocGetWaitbase:
+ return GetWaitbase(input, output);
+ case IoctlCommand::IocMapBuffer:
+ return MapBuffer(input, output);
+ case IoctlCommand::IocMapBufferEx:
+ return MapBufferEx(input, output);
+ case IoctlCommand::IocUnmapBufferEx:
+ return UnmapBufferEx(input, output);
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
@@ -30,11 +42,67 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlSetNvmapFD params{};
- std::memcpy(&params, input.data(), input.size());
+ std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
nvmap_fd = params.nvmap_fd;
return 0;
}
+u32 nvhost_nvdec::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlSubmit params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+ std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
+ return 0;
+}
+
+u32 nvhost_nvdec::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlGetSyncpoint params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
+ LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
+ params.value = 0; // Seems to be hard coded at 0
+ std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
+ return 0;
+}
+
+u32 nvhost_nvdec::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlGetWaitbase params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
+ LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
+ params.value = 0; // Seems to be hard coded at 0
+ std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
+ return 0;
+}
+
+u32 nvhost_nvdec::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlMapBuffer params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
+ params.address_1);
+ params.address_1 = 0;
+ params.address_2 = 0;
+ std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
+ return 0;
+}
+
+u32 nvhost_nvdec::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlMapBufferEx params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlMapBufferEx));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
+ params.address_1);
+ params.address_1 = 0;
+ params.address_2 = 0;
+ std::memcpy(output.data(), &params, sizeof(IoctlMapBufferEx));
+ return 0;
+}
+
+u32 nvhost_nvdec::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlUnmapBufferEx params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlUnmapBufferEx));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+ std::memcpy(output.data(), &params, sizeof(IoctlUnmapBufferEx));
+ return 0;
+}
+
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index cbdac8069..4332db118 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -23,16 +23,66 @@ public:
private:
enum class IoctlCommand : u32_le {
IocSetNVMAPfdCommand = 0x40044801,
+ IocSubmit = 0xC0400001,
+ IocGetSyncpoint = 0xC0080002,
+ IocGetWaitbase = 0xC0080003,
+ IocMapBuffer = 0xC01C0009,
+ IocMapBufferEx = 0xC0A40009,
+ IocUnmapBufferEx = 0xC0A4000A,
};
struct IoctlSetNvmapFD {
u32_le nvmap_fd;
};
- static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
+ static_assert(sizeof(IoctlSetNvmapFD) == 0x4, "IoctlSetNvmapFD is incorrect size");
+
+ struct IoctlSubmit {
+ INSERT_PADDING_BYTES(0x40); // TODO(DarkLordZach): RE this structure
+ };
+ static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit has incorrect size");
+
+ struct IoctlGetSyncpoint {
+ u32 unknown; // seems to be ignored? Nintendo added this
+ u32 value;
+ };
+ static_assert(sizeof(IoctlGetSyncpoint) == 0x08, "IoctlGetSyncpoint has incorrect size");
+
+ struct IoctlGetWaitbase {
+ u32 unknown; // seems to be ignored? Nintendo added this
+ u32 value;
+ };
+ static_assert(sizeof(IoctlGetWaitbase) == 0x08, "IoctlGetWaitbase has incorrect size");
+
+ struct IoctlMapBuffer {
+ u32 unknown;
+ u32 address_1;
+ u32 address_2;
+ INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
+ };
+ static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
+
+ struct IoctlMapBufferEx {
+ u32 unknown;
+ u32 address_1;
+ u32 address_2;
+ INSERT_PADDING_BYTES(0x98); // TODO(DarkLordZach): RE this structure
+ };
+ static_assert(sizeof(IoctlMapBufferEx) == 0xA4, "IoctlMapBufferEx has incorrect size");
+
+ struct IoctlUnmapBufferEx {
+ INSERT_PADDING_BYTES(0xA4); // TODO(DarkLordZach): RE this structure
+ };
+ static_assert(sizeof(IoctlUnmapBufferEx) == 0xA4, "IoctlUnmapBufferEx has incorrect size");
u32_le nvmap_fd{};
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index c695b8863..9da19ad56 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -22,6 +22,18 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
switch (static_cast<IoctlCommand>(command.raw)) {
case IoctlCommand::IocSetNVMAPfdCommand:
return SetNVMAPfd(input, output);
+ case IoctlCommand::IocSubmit:
+ return Submit(input, output);
+ case IoctlCommand::IocGetSyncpoint:
+ return GetSyncpoint(input, output);
+ case IoctlCommand::IocGetWaitbase:
+ return GetWaitbase(input, output);
+ case IoctlCommand::IocMapBuffer:
+ return MapBuffer(input, output);
+ case IoctlCommand::IocMapBufferEx:
+ return MapBuffer(input, output);
+ case IoctlCommand::IocUnmapBufferEx:
+ return UnmapBufferEx(input, output);
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
@@ -30,11 +42,71 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlSetNvmapFD params{};
- std::memcpy(&params, input.data(), input.size());
+ std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
nvmap_fd = params.nvmap_fd;
return 0;
}
+u32 nvhost_vic::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlSubmit params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
+ // Workaround for Luigi's Mansion 3, as nvhost_vic is not implemented for asynch GPU
+ params.command_buffer = {};
+
+ std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
+ return 0;
+}
+
+u32 nvhost_vic::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlGetSyncpoint params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
+ LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
+ params.value = 0; // Seems to be hard coded at 0
+ std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
+ return 0;
+}
+
+u32 nvhost_vic::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlGetWaitbase params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
+ LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
+ params.value = 0; // Seems to be hard coded at 0
+ std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
+ return 0;
+}
+
+u32 nvhost_vic::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlMapBuffer params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
+ params.address_1);
+ params.address_1 = 0;
+ params.address_2 = 0;
+ std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
+ return 0;
+}
+
+u32 nvhost_vic::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlMapBufferEx params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlMapBufferEx));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
+ params.address_1);
+ params.address_1 = 0;
+ params.address_2 = 0;
+ std::memcpy(output.data(), &params, sizeof(IoctlMapBufferEx));
+ return 0;
+}
+
+u32 nvhost_vic::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlUnmapBufferEx params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlUnmapBufferEx));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+ std::memcpy(output.data(), &params, sizeof(IoctlUnmapBufferEx));
+ return 0;
+}
+
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index bec32bea1..a7bb7bbd5 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -4,6 +4,7 @@
#pragma once
+#include <array>
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
@@ -23,6 +24,12 @@ public:
private:
enum class IoctlCommand : u32_le {
IocSetNVMAPfdCommand = 0x40044801,
+ IocSubmit = 0xC0400001,
+ IocGetSyncpoint = 0xC0080002,
+ IocGetWaitbase = 0xC0080003,
+ IocMapBuffer = 0xC01C0009,
+ IocMapBufferEx = 0xC03C0009,
+ IocUnmapBufferEx = 0xC03C000A,
};
struct IoctlSetNvmapFD {
@@ -30,9 +37,65 @@ private:
};
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
+ struct IoctlSubmitCommandBuffer {
+ u32 id;
+ u32 offset;
+ u32 count;
+ };
+ static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
+ "IoctlSubmitCommandBuffer is incorrect size");
+
+ struct IoctlSubmit {
+ u32 command_buffer_count;
+ u32 relocations_count;
+ u32 syncpt_count;
+ u32 wait_count;
+ std::array<IoctlSubmitCommandBuffer, 4> command_buffer;
+ };
+ static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit is incorrect size");
+
+ struct IoctlGetSyncpoint {
+ u32 unknown; // seems to be ignored? Nintendo added this
+ u32 value;
+ };
+ static_assert(sizeof(IoctlGetSyncpoint) == 0x8, "IoctlGetSyncpoint is incorrect size");
+
+ struct IoctlGetWaitbase {
+ u32 unknown; // seems to be ignored? Nintendo added this
+ u32 value;
+ };
+ static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
+
+ struct IoctlMapBuffer {
+ u32 unknown;
+ u32 address_1;
+ u32 address_2;
+ INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
+ };
+ static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
+
+ struct IoctlMapBufferEx {
+ u32 unknown;
+ u32 address_1;
+ u32 address_2;
+ INSERT_PADDING_BYTES(0x30); // TODO(DarkLordZach): RE this structure
+ };
+ static_assert(sizeof(IoctlMapBufferEx) == 0x3C, "IoctlMapBufferEx is incorrect size");
+
+ struct IoctlUnmapBufferEx {
+ INSERT_PADDING_BYTES(0x3C); // TODO(DarkLordZach): RE this structure
+ };
+ static_assert(sizeof(IoctlUnmapBufferEx) == 0x3C, "IoctlUnmapBufferEx is incorrect size");
+
u32_le nvmap_fd{};
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index d7a1bef91..7706a5590 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -54,7 +54,7 @@ struct EventInterface {
}
mask = mask >> 1;
}
- return {};
+ return std::nullopt;
}
void SetEventStatus(const u32 event_id, EventState new_status) {
EventState old_status = status[event_id];
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 637b310d7..4f1e210b1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -99,6 +99,20 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
queue_sequence.push_back(slot);
}
+void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) {
+ const auto itr = std::find_if(queue.begin(), queue.end(),
+ [slot](const Buffer& buffer) { return buffer.slot == slot; });
+ ASSERT(itr != queue.end());
+ ASSERT(itr->status != Buffer::Status::Free);
+ itr->status = Buffer::Status::Free;
+ itr->multi_fence = multi_fence;
+ itr->swap_interval = 0;
+
+ free_buffers.push_back(slot);
+
+ buffer_wait_event.writable->Signal();
+}
+
std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
auto itr = queue.end();
// Iterate to find a queued buffer matching the requested slot.
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 8a837e5aa..e7517c7e1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -95,6 +95,7 @@ public:
void QueueBuffer(u32 slot, BufferTransformFlags transform,
const Common::Rectangle<int>& crop_rect, u32 swap_interval,
Service::Nvidia::MultiFence& multi_fence);
+ void CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence);
std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
void ReleaseBuffer(u32 slot);
void Disconnect();
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index f644a460d..c64673dba 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -114,7 +114,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
[&](const VI::Display& display) { return display.GetName() == name; });
if (itr == displays.end()) {
- return {};
+ return std::nullopt;
}
return itr->GetID();
@@ -124,7 +124,7 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
auto* const display = FindDisplay(display_id);
if (display == nullptr) {
- return {};
+ return std::nullopt;
}
const u64 layer_id = next_layer_id++;
@@ -144,7 +144,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co
const auto* const layer = FindLayer(display_id, layer_id);
if (layer == nullptr) {
- return {};
+ return std::nullopt;
}
return layer->GetBufferQueue().GetId();
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index fa5347af9..ba9159ee0 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -89,8 +89,6 @@ namespace Service {
return function_string;
}
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_sessions,
InvokerFn* handler_invoker)
: service_name(service_name), max_sessions(max_sessions), handler_invoker(handler_invoker) {}
@@ -105,10 +103,9 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
port_installed = true;
}
-void ServiceFrameworkBase::InstallAsNamedPort() {
+void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
ASSERT(!port_installed);
- auto& kernel = Core::System::GetInstance().Kernel();
auto [server_port, client_port] =
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
server_port->SetHleHandler(shared_from_this());
@@ -116,10 +113,9 @@ void ServiceFrameworkBase::InstallAsNamedPort() {
port_installed = true;
}
-std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() {
+std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
ASSERT(!port_installed);
- auto& kernel = Core::System::GetInstance().Kernel();
auto [server_port, client_port] =
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
auto port = MakeResult(std::move(server_port)).Unwrap();
@@ -191,9 +187,6 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
return RESULT_SUCCESS;
}
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Module interface
-
/// Initialize ServiceManager
void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
@@ -246,7 +239,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
PSC::InstallInterfaces(*sm);
PSM::InstallInterfaces(*sm);
Set::InstallInterfaces(*sm);
- Sockets::InstallInterfaces(*sm);
+ Sockets::InstallInterfaces(*sm, system);
SPL::InstallInterfaces(*sm);
SSL::InstallInterfaces(*sm);
Time::InstallInterfaces(system);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 022d885b6..a01ef3353 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -63,9 +63,9 @@ public:
/// Creates a port pair and registers this service with the given ServiceManager.
void InstallAsService(SM::ServiceManager& service_manager);
/// Creates a port pair and registers it on the kernel's global port registry.
- void InstallAsNamedPort();
+ void InstallAsNamedPort(Kernel::KernelCore& kernel);
/// Creates and returns an unregistered port for the service.
- std::shared_ptr<Kernel::ClientPort> CreatePort();
+ std::shared_ptr<Kernel::ClientPort> CreatePort(Kernel::KernelCore& kernel);
void InvokeRequest(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index d872de16c..9c1da361b 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -19,7 +19,7 @@ constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6);
constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
-ServiceManager::ServiceManager() = default;
+ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {}
ServiceManager::~ServiceManager() = default;
void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
@@ -27,11 +27,11 @@ void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
}
static ResultCode ValidateServiceName(const std::string& name) {
- if (name.size() <= 0 || name.size() > 8) {
+ if (name.empty() || name.size() > 8) {
LOG_ERROR(Service_SM, "Invalid service name! service={}", name);
return ERR_INVALID_NAME;
}
- if (name.find('\0') != std::string::npos) {
+ if (name.rfind('\0') != std::string::npos) {
LOG_ERROR(Service_SM, "A non null terminated service was passed");
return ERR_INVALID_NAME;
}
@@ -43,13 +43,13 @@ void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self,
ASSERT(self->sm_interface.expired());
auto sm = std::make_shared<SM>(self, kernel);
- sm->InstallAsNamedPort();
+ sm->InstallAsNamedPort(kernel);
self->sm_interface = sm;
self->controller_interface = std::make_unique<Controller>();
}
-ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(
- std::string name, unsigned int max_sessions) {
+ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name,
+ u32 max_sessions) {
CASCADE_CODE(ValidateServiceName(name));
@@ -58,7 +58,6 @@ ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(
return ERR_ALREADY_REGISTERED;
}
- auto& kernel = Core::System::GetInstance().Kernel();
auto [server_port, client_port] =
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name);
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index aabf166b7..6790c86f0 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -48,11 +48,11 @@ class ServiceManager {
public:
static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel);
- ServiceManager();
+ explicit ServiceManager(Kernel::KernelCore& kernel_);
~ServiceManager();
ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name,
- unsigned int max_sessions);
+ u32 max_sessions);
ResultCode UnregisterService(const std::string& name);
ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name);
ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
@@ -79,6 +79,9 @@ private:
/// Map of registered services, retrieved using GetServicePort or ConnectToService.
std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services;
+
+ /// Kernel context
+ Kernel::KernelCore& kernel;
};
} // namespace Service::SM
diff --git a/src/core/hle/service/sockets/blocking_worker.h b/src/core/hle/service/sockets/blocking_worker.h
new file mode 100644
index 000000000..2d53e52b6
--- /dev/null
+++ b/src/core/hle/service/sockets/blocking_worker.h
@@ -0,0 +1,161 @@
+// Copyright 2020 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <thread>
+#include <variant>
+#include <vector>
+
+#include <fmt/format.h>
+
+#include "common/assert.h"
+#include "common/microprofile.h"
+#include "common/thread.h"
+#include "core/core.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/writable_event.h"
+
+namespace Service::Sockets {
+
+/**
+ * Worker abstraction to execute blocking calls on host without blocking the guest thread
+ *
+ * @tparam Service Service where the work is executed
+ * @tparam Types Types of work to execute
+ */
+template <class Service, class... Types>
+class BlockingWorker {
+ using This = BlockingWorker<Service, Types...>;
+ using WorkVariant = std::variant<std::monostate, Types...>;
+
+public:
+ /// Create a new worker
+ static std::unique_ptr<This> Create(Core::System& system, Service* service,
+ std::string_view name) {
+ return std::unique_ptr<This>(new This(system, service, name));
+ }
+
+ ~BlockingWorker() {
+ while (!is_available.load(std::memory_order_relaxed)) {
+ // Busy wait until work is finished
+ std::this_thread::yield();
+ }
+ // Monostate means to exit the thread
+ work = std::monostate{};
+ work_event.Set();
+ thread.join();
+ }
+
+ /**
+ * Try to capture the worker to send work after a success
+ * @returns True when the worker has been successfully captured
+ */
+ bool TryCapture() {
+ bool expected = true;
+ return is_available.compare_exchange_weak(expected, false, std::memory_order_relaxed,
+ std::memory_order_relaxed);
+ }
+
+ /**
+ * Send work to this worker abstraction
+ * @see TryCapture must be called before attempting to call this function
+ */
+ template <class Work>
+ void SendWork(Work new_work) {
+ ASSERT_MSG(!is_available, "Trying to send work on a worker that's not captured");
+ work = std::move(new_work);
+ work_event.Set();
+ }
+
+ /// Generate a callback for @see SleepClientThread
+ template <class Work>
+ auto Callback() {
+ return [this](std::shared_ptr<Kernel::Thread>, Kernel::HLERequestContext& ctx,
+ Kernel::ThreadWakeupReason reason) {
+ ASSERT(reason == Kernel::ThreadWakeupReason::Signal);
+ std::get<Work>(work).Response(ctx);
+ is_available.store(true);
+ };
+ }
+
+ /// Get kernel event that will be signalled by the worker when the host operation finishes
+ std::shared_ptr<Kernel::WritableEvent> KernelEvent() const {
+ return kernel_event;
+ }
+
+private:
+ explicit BlockingWorker(Core::System& system, Service* service, std::string_view name) {
+ auto pair = Kernel::WritableEvent::CreateEventPair(system.Kernel(), std::string(name));
+ kernel_event = std::move(pair.writable);
+ thread = std::thread([this, &system, service, name] { Run(system, service, name); });
+ }
+
+ void Run(Core::System& system, Service* service, std::string_view name) {
+ system.RegisterHostThread();
+
+ const std::string thread_name = fmt::format("yuzu:{}", name);
+ MicroProfileOnThreadCreate(thread_name.c_str());
+ Common::SetCurrentThreadName(thread_name.c_str());
+
+ bool keep_running = true;
+ while (keep_running) {
+ work_event.Wait();
+
+ const auto visit_fn = [service, &keep_running]<typename T>(T&& w) {
+ if constexpr (std::is_same_v<std::decay_t<T>, std::monostate>) {
+ keep_running = false;
+ } else {
+ w.Execute(service);
+ }
+ };
+ std::visit(visit_fn, work);
+
+ kernel_event->Signal();
+ }
+ }
+
+ std::thread thread;
+ WorkVariant work;
+ Common::Event work_event;
+ std::shared_ptr<Kernel::WritableEvent> kernel_event;
+ std::atomic_bool is_available{true};
+};
+
+template <class Service, class... Types>
+class BlockingWorkerPool {
+ using Worker = BlockingWorker<Service, Types...>;
+
+public:
+ explicit BlockingWorkerPool(Core::System& system_, Service* service_)
+ : system{system_}, service{service_} {}
+
+ /// Returns a captured worker thread, creating new ones if necessary
+ Worker* CaptureWorker() {
+ for (auto& worker : workers) {
+ if (worker->TryCapture()) {
+ return worker.get();
+ }
+ }
+ auto new_worker = Worker::Create(system, service, fmt::format("BSD:{}", workers.size()));
+ [[maybe_unused]] const bool success = new_worker->TryCapture();
+ ASSERT(success);
+
+ return workers.emplace_back(std::move(new_worker)).get();
+ }
+
+private:
+ Core::System& system;
+ Service* const service;
+
+ std::vector<std::unique_ptr<Worker>> workers;
+};
+
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 8d4952c0e..a74be9370 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -2,18 +2,138 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <array>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <fmt/format.h>
+
+#include "common/microprofile.h"
+#include "common/thread.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/thread.h"
#include "core/hle/service/sockets/bsd.h"
+#include "core/hle/service/sockets/sockets_translate.h"
+#include "core/network/network.h"
+#include "core/network/sockets.h"
namespace Service::Sockets {
+namespace {
+
+bool IsConnectionBased(Type type) {
+ switch (type) {
+ case Type::STREAM:
+ return true;
+ case Type::DGRAM:
+ return false;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type));
+ return false;
+ }
+}
+
+} // Anonymous namespace
+
+void BSD::PollWork::Execute(BSD* bsd) {
+ std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
+}
+
+void BSD::PollWork::Response(Kernel::HLERequestContext& ctx) {
+ ctx.WriteBuffer(write_buffer);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<s32>(ret);
+ rb.PushEnum(bsd_errno);
+}
+
+void BSD::AcceptWork::Execute(BSD* bsd) {
+ std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
+}
+
+void BSD::AcceptWork::Response(Kernel::HLERequestContext& ctx) {
+ ctx.WriteBuffer(write_buffer);
+
+ IPC::ResponseBuilder rb{ctx, 5};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<s32>(ret);
+ rb.PushEnum(bsd_errno);
+ rb.Push<u32>(static_cast<u32>(write_buffer.size()));
+}
+
+void BSD::ConnectWork::Execute(BSD* bsd) {
+ bsd_errno = bsd->ConnectImpl(fd, addr);
+}
+
+void BSD::ConnectWork::Response(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
+ rb.PushEnum(bsd_errno);
+}
+
+void BSD::RecvWork::Execute(BSD* bsd) {
+ std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
+}
+
+void BSD::RecvWork::Response(Kernel::HLERequestContext& ctx) {
+ ctx.WriteBuffer(message);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<s32>(ret);
+ rb.PushEnum(bsd_errno);
+}
+
+void BSD::RecvFromWork::Execute(BSD* bsd) {
+ std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
+}
+
+void BSD::RecvFromWork::Response(Kernel::HLERequestContext& ctx) {
+ ctx.WriteBuffer(message, 0);
+ if (!addr.empty()) {
+ ctx.WriteBuffer(addr, 1);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 5};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<s32>(ret);
+ rb.PushEnum(bsd_errno);
+ rb.Push<u32>(static_cast<u32>(addr.size()));
+}
+
+void BSD::SendWork::Execute(BSD* bsd) {
+ std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
+}
+
+void BSD::SendWork::Response(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<s32>(ret);
+ rb.PushEnum(bsd_errno);
+}
+
+void BSD::SendToWork::Execute(BSD* bsd) {
+ std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
+}
+
+void BSD::SendToWork::Response(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<s32>(ret);
+ rb.PushEnum(bsd_errno);
+}
+
void BSD::RegisterClient(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0); // bsd errno
+ rb.Push<s32>(0); // bsd errno
}
void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
@@ -26,20 +146,19 @@ void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
void BSD::Socket(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
+ const u32 domain = rp.Pop<u32>();
+ const u32 type = rp.Pop<u32>();
+ const u32 protocol = rp.Pop<u32>();
- u32 domain = rp.Pop<u32>();
- u32 type = rp.Pop<u32>();
- u32 protocol = rp.Pop<u32>();
-
- LOG_WARNING(Service, "(STUBBED) called domain={} type={} protocol={}", domain, type, protocol);
+ LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
- u32 fd = next_fd++;
+ const auto [fd, bsd_errno] = SocketImpl(static_cast<Domain>(domain), static_cast<Type>(type),
+ static_cast<Protocol>(protocol));
IPC::ResponseBuilder rb{ctx, 4};
-
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(fd);
- rb.Push<u32>(0); // bsd errno
+ rb.Push<s32>(fd);
+ rb.PushEnum(bsd_errno);
}
void BSD::Select(Kernel::HLERequestContext& ctx) {
@@ -52,67 +171,664 @@ void BSD::Select(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno
}
+void BSD::Poll(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const s32 nfds = rp.Pop<s32>();
+ const s32 timeout = rp.Pop<s32>();
+
+ LOG_DEBUG(Service, "called. nfds={} timeout={}", nfds, timeout);
+
+ ExecuteWork(ctx, "BSD:Poll", timeout != 0,
+ PollWork{
+ .nfds = nfds,
+ .timeout = timeout,
+ .read_buffer = ctx.ReadBuffer(),
+ .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
+ });
+}
+
+void BSD::Accept(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
+
+ LOG_DEBUG(Service, "called. fd={}", fd);
+
+ ExecuteWork(ctx, "BSD:Accept", IsBlockingSocket(fd),
+ AcceptWork{
+ .fd = fd,
+ .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
+ });
+}
+
void BSD::Bind(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
- IPC::ResponseBuilder rb{ctx, 4};
+ LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
- rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0); // ret
- rb.Push<u32>(0); // bsd errno
+ BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
}
void BSD::Connect(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
- IPC::ResponseBuilder rb{ctx, 4};
+ LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
+
+ ExecuteWork(ctx, "BSD:Connect", IsBlockingSocket(fd),
+ ConnectWork{
+ .fd = fd,
+ .addr = ctx.ReadBuffer(),
+ });
+}
+
+void BSD::GetPeerName(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
+
+ LOG_DEBUG(Service, "called. fd={}", fd);
+ std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
+ const Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
+
+ ctx.WriteBuffer(write_buffer);
+
+ IPC::ResponseBuilder rb{ctx, 5};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0); // ret
- rb.Push<u32>(0); // bsd errno
+ rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
+ rb.PushEnum(bsd_errno);
+ rb.Push<u32>(static_cast<u32>(write_buffer.size()));
+}
+
+void BSD::GetSockName(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
+
+ LOG_DEBUG(Service, "called. fd={}", fd);
+
+ std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
+ const Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
+
+ ctx.WriteBuffer(write_buffer);
+
+ IPC::ResponseBuilder rb{ctx, 5};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
+ rb.PushEnum(bsd_errno);
+ rb.Push<u32>(static_cast<u32>(write_buffer.size()));
}
void BSD::Listen(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
+ const s32 backlog = rp.Pop<s32>();
- IPC::ResponseBuilder rb{ctx, 4};
+ LOG_DEBUG(Service, "called. fd={} backlog={}", fd, backlog);
+
+ BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
+}
+
+void BSD::Fcntl(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
+ const s32 cmd = rp.Pop<s32>();
+ const s32 arg = rp.Pop<s32>();
+ LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg);
+
+ const auto [ret, bsd_errno] = FcntlImpl(fd, static_cast<FcntlCmd>(cmd), arg);
+
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0); // ret
- rb.Push<u32>(0); // bsd errno
+ rb.Push<s32>(ret);
+ rb.PushEnum(bsd_errno);
}
void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
- IPC::ResponseBuilder rb{ctx, 4};
+ const s32 fd = rp.Pop<s32>();
+ const u32 level = rp.Pop<u32>();
+ const OptName optname = static_cast<OptName>(rp.Pop<u32>());
- rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0); // ret
- rb.Push<u32>(0); // bsd errno
+ const std::vector<u8> buffer = ctx.ReadBuffer();
+ const u8* optval = buffer.empty() ? nullptr : buffer.data();
+ size_t optlen = buffer.size();
+
+ std::array<u64, 2> values;
+ if ((optname == OptName::SNDTIMEO || optname == OptName::RCVTIMEO) && buffer.size() == 8) {
+ std::memcpy(values.data(), buffer.data(), sizeof(values));
+ optlen = sizeof(values);
+ optval = reinterpret_cast<const u8*>(values.data());
+ }
+
+ LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level,
+ static_cast<u32>(optname), optlen);
+
+ BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval));
+}
+
+void BSD::Shutdown(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const s32 fd = rp.Pop<s32>();
+ const s32 how = rp.Pop<s32>();
+
+ LOG_DEBUG(Service, "called. fd={} how={}", fd, how);
+
+ BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
+}
+
+void BSD::Recv(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const s32 fd = rp.Pop<s32>();
+ const u32 flags = rp.Pop<u32>();
+
+ LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetWriteBufferSize());
+
+ ExecuteWork(ctx, "BSD:Recv", IsBlockingSocket(fd),
+ RecvWork{
+ .fd = fd,
+ .flags = flags,
+ .message = std::vector<u8>(ctx.GetWriteBufferSize()),
+ });
+}
+
+void BSD::RecvFrom(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const s32 fd = rp.Pop<s32>();
+ const u32 flags = rp.Pop<u32>();
+
+ LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={} addrlen={}", fd, flags,
+ ctx.GetWriteBufferSize(0), ctx.GetWriteBufferSize(1));
+
+ ExecuteWork(ctx, "BSD:RecvFrom", IsBlockingSocket(fd),
+ RecvFromWork{
+ .fd = fd,
+ .flags = flags,
+ .message = std::vector<u8>(ctx.GetWriteBufferSize(0)),
+ .addr = std::vector<u8>(ctx.GetWriteBufferSize(1)),
+ });
+}
+
+void BSD::Send(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const s32 fd = rp.Pop<s32>();
+ const u32 flags = rp.Pop<u32>();
+
+ LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetReadBufferSize());
+
+ ExecuteWork(ctx, "BSD:Send", IsBlockingSocket(fd),
+ SendWork{
+ .fd = fd,
+ .flags = flags,
+ .message = ctx.ReadBuffer(),
+ });
}
void BSD::SendTo(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
+ const u32 flags = rp.Pop<u32>();
+
+ LOG_DEBUG(Service, "called. fd={} flags=0x{} len={} addrlen={}", fd, flags,
+ ctx.GetReadBufferSize(0), ctx.GetReadBufferSize(1));
+
+ ExecuteWork(ctx, "BSD:SendTo", IsBlockingSocket(fd),
+ SendToWork{
+ .fd = fd,
+ .flags = flags,
+ .message = ctx.ReadBuffer(0),
+ .addr = ctx.ReadBuffer(1),
+ });
+}
- IPC::ResponseBuilder rb{ctx, 4};
+void BSD::Write(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
- rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0); // ret
- rb.Push<u32>(0); // bsd errno
+ LOG_DEBUG(Service, "called. fd={} len={}", fd, ctx.GetReadBufferSize());
+
+ ExecuteWork(ctx, "BSD:Write", IsBlockingSocket(fd),
+ SendWork{
+ .fd = fd,
+ .flags = 0,
+ .message = ctx.ReadBuffer(),
+ });
}
void BSD::Close(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ const s32 fd = rp.Pop<s32>();
+
+ LOG_DEBUG(Service, "called. fd={}", fd);
+
+ BuildErrnoResponse(ctx, CloseImpl(fd));
+}
+
+template <typename Work>
+void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason,
+ bool is_blocking, Work work) {
+ if (!is_blocking) {
+ work.Execute(this);
+ work.Response(ctx);
+ return;
+ }
+
+ // Signal a dummy response to make IPC validation happy
+ // This will be overwritten by the SleepClientThread callback
+ work.Response(ctx);
+
+ auto worker = worker_pool.CaptureWorker();
+
+ ctx.SleepClientThread(std::string(sleep_reason), std::numeric_limits<u64>::max(),
+ worker->Callback<Work>(), worker->KernelEvent());
+
+ worker->SendWork(std::move(work));
+}
+
+std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
+ if (type == Type::SEQPACKET) {
+ UNIMPLEMENTED_MSG("SOCK_SEQPACKET errno management");
+ } else if (type == Type::RAW && (domain != Domain::INET || protocol != Protocol::ICMP)) {
+ UNIMPLEMENTED_MSG("SOCK_RAW errno management");
+ }
+
+ [[maybe_unused]] const bool unk_flag = (static_cast<u32>(type) & 0x20000000) != 0;
+ UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type");
+ type = static_cast<Type>(static_cast<u32>(type) & ~0x20000000);
+
+ const s32 fd = FindFreeFileDescriptorHandle();
+ if (fd < 0) {
+ LOG_ERROR(Service, "No more file descriptors available");
+ return {-1, Errno::MFILE};
+ }
+
+ FileDescriptor& descriptor = file_descriptors[fd].emplace();
+ // ENONMEM might be thrown here
+
+ LOG_INFO(Service, "New socket fd={}", fd);
+
+ descriptor.socket = std::make_unique<Network::Socket>();
+ descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol));
+ descriptor.is_connection_based = IsConnectionBased(type);
+
+ return {fd, Errno::SUCCESS};
+}
+std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
+ s32 nfds, s32 timeout) {
+ if (write_buffer.size() < nfds * sizeof(PollFD)) {
+ return {-1, Errno::INVAL};
+ }
+
+ if (nfds == 0) {
+ // When no entries are provided, -1 is returned with errno zero
+ return {-1, Errno::SUCCESS};
+ }
+
+ const size_t length = std::min(read_buffer.size(), write_buffer.size());
+ std::vector<PollFD> fds(nfds);
+ std::memcpy(fds.data(), read_buffer.data(), length);
+
+ if (timeout >= 0) {
+ const s64 seconds = timeout / 1000;
+ const u64 nanoseconds = 1'000'000 * (static_cast<u64>(timeout) % 1000);
+
+ if (seconds < 0) {
+ return {-1, Errno::INVAL};
+ }
+ if (nanoseconds > 999'999'999) {
+ return {-1, Errno::INVAL};
+ }
+ } else if (timeout != -1) {
+ return {-1, Errno::INVAL};
+ }
+
+ for (PollFD& pollfd : fds) {
+ ASSERT(pollfd.revents == 0);
+
+ if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) {
+ LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd);
+ pollfd.revents = 0;
+ return {0, Errno::SUCCESS};
+ }
+
+ const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
+ if (!descriptor) {
+ LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd);
+ pollfd.revents = POLL_NVAL;
+ return {0, Errno::SUCCESS};
+ }
+ }
+
+ std::vector<Network::PollFD> host_pollfds(fds.size());
+ std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) {
+ Network::PollFD result;
+ result.socket = file_descriptors[pollfd.fd]->socket.get();
+ result.events = TranslatePollEventsToHost(pollfd.events);
+ result.revents = 0;
+ return result;
+ });
+
+ const auto result = Network::Poll(host_pollfds, timeout);
+
+ const size_t num = host_pollfds.size();
+ for (size_t i = 0; i < num; ++i) {
+ fds[i].revents = TranslatePollEventsToGuest(host_pollfds[i].revents);
+ }
+ std::memcpy(write_buffer.data(), fds.data(), length);
+
+ return Translate(result);
+}
+
+std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
+ if (!IsFileDescriptorValid(fd)) {
+ return {-1, Errno::BADF};
+ }
+
+ const s32 new_fd = FindFreeFileDescriptorHandle();
+ if (new_fd < 0) {
+ LOG_ERROR(Service, "No more file descriptors available");
+ return {-1, Errno::MFILE};
+ }
+
+ FileDescriptor& descriptor = *file_descriptors[fd];
+ auto [result, bsd_errno] = descriptor.socket->Accept();
+ if (bsd_errno != Network::Errno::SUCCESS) {
+ return {-1, Translate(bsd_errno)};
+ }
+
+ FileDescriptor& new_descriptor = file_descriptors[new_fd].emplace();
+ new_descriptor.socket = std::move(result.socket);
+ new_descriptor.is_connection_based = descriptor.is_connection_based;
+
+ ASSERT(write_buffer.size() == sizeof(SockAddrIn));
+ const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
+ std::memcpy(write_buffer.data(), &guest_addr_in, sizeof(guest_addr_in));
+
+ return {new_fd, Errno::SUCCESS};
+}
+
+Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) {
+ if (!IsFileDescriptorValid(fd)) {
+ return Errno::BADF;
+ }
+ ASSERT(addr.size() == sizeof(SockAddrIn));
+ SockAddrIn addr_in;
+ std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
+
+ return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
+}
+
+Errno BSD::ConnectImpl(s32 fd, const std::vector<u8>& addr) {
+ if (!IsFileDescriptorValid(fd)) {
+ return Errno::BADF;
+ }
+
+ UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn));
+ SockAddrIn addr_in;
+ std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
+
+ return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
+}
+
+Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
+ if (!IsFileDescriptorValid(fd)) {
+ return Errno::BADF;
+ }
+
+ const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName();
+ if (bsd_errno != Network::Errno::SUCCESS) {
+ return Translate(bsd_errno);
+ }
+ const SockAddrIn guest_addrin = Translate(addr_in);
+
+ ASSERT(write_buffer.size() == sizeof(guest_addrin));
+ std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
+ return Translate(bsd_errno);
+}
+
+Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
+ if (!IsFileDescriptorValid(fd)) {
+ return Errno::BADF;
+ }
+
+ const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName();
+ if (bsd_errno != Network::Errno::SUCCESS) {
+ return Translate(bsd_errno);
+ }
+ const SockAddrIn guest_addrin = Translate(addr_in);
+
+ ASSERT(write_buffer.size() == sizeof(guest_addrin));
+ std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
+ return Translate(bsd_errno);
+}
+
+Errno BSD::ListenImpl(s32 fd, s32 backlog) {
+ if (!IsFileDescriptorValid(fd)) {
+ return Errno::BADF;
+ }
+ return Translate(file_descriptors[fd]->socket->Listen(backlog));
+}
+
+std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
+ if (!IsFileDescriptorValid(fd)) {
+ return {-1, Errno::BADF};
+ }
+
+ FileDescriptor& descriptor = *file_descriptors[fd];
+
+ switch (cmd) {
+ case FcntlCmd::GETFL:
+ ASSERT(arg == 0);
+ return {descriptor.flags, Errno::SUCCESS};
+ case FcntlCmd::SETFL: {
+ const bool enable = (arg & FLAG_O_NONBLOCK) != 0;
+ const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
+ if (bsd_errno != Errno::SUCCESS) {
+ return {-1, bsd_errno};
+ }
+ descriptor.flags = arg;
+ return {0, Errno::SUCCESS};
+ }
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented cmd={}", static_cast<int>(cmd));
+ return {-1, Errno::SUCCESS};
+ }
+}
+
+Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) {
+ UNIMPLEMENTED_IF(level != 0xffff); // SOL_SOCKET
+
+ if (!IsFileDescriptorValid(fd)) {
+ return Errno::BADF;
+ }
+
+ Network::Socket* const socket = file_descriptors[fd]->socket.get();
+
+ if (optname == OptName::LINGER) {
+ ASSERT(optlen == sizeof(Linger));
+ Linger linger;
+ std::memcpy(&linger, optval, sizeof(linger));
+ ASSERT(linger.onoff == 0 || linger.onoff == 1);
+
+ return Translate(socket->SetLinger(linger.onoff != 0, linger.linger));
+ }
+
+ ASSERT(optlen == sizeof(u32));
+ u32 value;
+ std::memcpy(&value, optval, sizeof(value));
+
+ switch (optname) {
+ case OptName::REUSEADDR:
+ ASSERT(value == 0 || value == 1);
+ return Translate(socket->SetReuseAddr(value != 0));
+ case OptName::BROADCAST:
+ ASSERT(value == 0 || value == 1);
+ return Translate(socket->SetBroadcast(value != 0));
+ case OptName::SNDBUF:
+ return Translate(socket->SetSndBuf(value));
+ case OptName::RCVBUF:
+ return Translate(socket->SetRcvBuf(value));
+ case OptName::SNDTIMEO:
+ return Translate(socket->SetSndTimeo(value));
+ case OptName::RCVTIMEO:
+ return Translate(socket->SetRcvTimeo(value));
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented optname={}", static_cast<int>(optname));
+ return Errno::SUCCESS;
+ }
+}
+
+Errno BSD::ShutdownImpl(s32 fd, s32 how) {
+ if (!IsFileDescriptorValid(fd)) {
+ return Errno::BADF;
+ }
+ const Network::ShutdownHow host_how = Translate(static_cast<ShutdownHow>(how));
+ return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
+}
+
+std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
+ if (!IsFileDescriptorValid(fd)) {
+ return {-1, Errno::BADF};
+ }
+ return Translate(file_descriptors[fd]->socket->Recv(flags, message));
+}
+
+std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
+ std::vector<u8>& addr) {
+ if (!IsFileDescriptorValid(fd)) {
+ return {-1, Errno::BADF};
+ }
+
+ FileDescriptor& descriptor = *file_descriptors[fd];
+
+ Network::SockAddrIn addr_in{};
+ Network::SockAddrIn* p_addr_in = nullptr;
+ if (descriptor.is_connection_based) {
+ // Connection based file descriptors (e.g. TCP) zero addr
+ addr.clear();
+ } else {
+ p_addr_in = &addr_in;
+ }
+
+ // Apply flags
+ if ((flags & FLAG_MSG_DONTWAIT) != 0) {
+ flags &= ~FLAG_MSG_DONTWAIT;
+ if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
+ descriptor.socket->SetNonBlock(true);
+ }
+ }
+
+ const auto [ret, bsd_errno] = Translate(descriptor.socket->RecvFrom(flags, message, p_addr_in));
+
+ // Restore original state
+ if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
+ descriptor.socket->SetNonBlock(false);
+ }
+
+ if (p_addr_in) {
+ if (ret < 0) {
+ addr.clear();
+ } else {
+ ASSERT(addr.size() == sizeof(SockAddrIn));
+ const SockAddrIn result = Translate(addr_in);
+ std::memcpy(addr.data(), &result, sizeof(result));
+ }
+ }
+
+ return {ret, bsd_errno};
+}
+
+std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, const std::vector<u8>& message) {
+ if (!IsFileDescriptorValid(fd)) {
+ return {-1, Errno::BADF};
+ }
+ return Translate(file_descriptors[fd]->socket->Send(message, flags));
+}
+
+std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
+ const std::vector<u8>& addr) {
+ if (!IsFileDescriptorValid(fd)) {
+ return {-1, Errno::BADF};
+ }
+
+ Network::SockAddrIn addr_in;
+ Network::SockAddrIn* p_addr_in = nullptr;
+ if (!addr.empty()) {
+ ASSERT(addr.size() == sizeof(SockAddrIn));
+ SockAddrIn guest_addr_in;
+ std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in));
+ addr_in = Translate(guest_addr_in);
+ p_addr_in = &addr_in;
+ }
+
+ return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
+}
+
+Errno BSD::CloseImpl(s32 fd) {
+ if (!IsFileDescriptorValid(fd)) {
+ return Errno::BADF;
+ }
+
+ const Errno bsd_errno = Translate(file_descriptors[fd]->socket->Close());
+ if (bsd_errno != Errno::SUCCESS) {
+ return bsd_errno;
+ }
+
+ LOG_INFO(Service, "Close socket fd={}", fd);
+
+ file_descriptors[fd].reset();
+ return bsd_errno;
+}
+
+s32 BSD::FindFreeFileDescriptorHandle() noexcept {
+ for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
+ if (!file_descriptors[fd]) {
+ return fd;
+ }
+ }
+ return -1;
+}
+
+bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
+ if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
+ LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
+ return false;
+ }
+ if (!file_descriptors[fd]) {
+ LOG_ERROR(Service, "File descriptor handle={} is not allocated", fd);
+ return false;
+ }
+ return true;
+}
+
+bool BSD::IsBlockingSocket(s32 fd) const noexcept {
+ // Inform invalid sockets as non-blocking
+ // This way we avoid using a worker thread as it will fail without blocking host
+ if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
+ return false;
+ }
+ if (!file_descriptors[fd]) {
+ return false;
+ }
+ return (file_descriptors[fd]->flags & FLAG_O_NONBLOCK) != 0;
+}
+
+void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0); // ret
- rb.Push<u32>(0); // bsd errno
+ rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
+ rb.PushEnum(bsd_errno);
}
-BSD::BSD(const char* name) : ServiceFramework(name) {
+BSD::BSD(Core::System& system, const char* name)
+ : ServiceFramework(name), worker_pool{system, this} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &BSD::RegisterClient, "RegisterClient"},
@@ -121,25 +837,25 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
{3, nullptr, "SocketExempt"},
{4, nullptr, "Open"},
{5, &BSD::Select, "Select"},
- {6, nullptr, "Poll"},
+ {6, &BSD::Poll, "Poll"},
{7, nullptr, "Sysctl"},
- {8, nullptr, "Recv"},
- {9, nullptr, "RecvFrom"},
- {10, nullptr, "Send"},
+ {8, &BSD::Recv, "Recv"},
+ {9, &BSD::RecvFrom, "RecvFrom"},
+ {10, &BSD::Send, "Send"},
{11, &BSD::SendTo, "SendTo"},
- {12, nullptr, "Accept"},
+ {12, &BSD::Accept, "Accept"},
{13, &BSD::Bind, "Bind"},
{14, &BSD::Connect, "Connect"},
- {15, nullptr, "GetPeerName"},
- {16, nullptr, "GetSockName"},
+ {15, &BSD::GetPeerName, "GetPeerName"},
+ {16, &BSD::GetSockName, "GetSockName"},
{17, nullptr, "GetSockOpt"},
{18, &BSD::Listen, "Listen"},
{19, nullptr, "Ioctl"},
- {20, nullptr, "Fcntl"},
+ {20, &BSD::Fcntl, "Fcntl"},
{21, &BSD::SetSockOpt, "SetSockOpt"},
- {22, nullptr, "Shutdown"},
+ {22, &BSD::Shutdown, "Shutdown"},
{23, nullptr, "ShutdownAllSockets"},
- {24, nullptr, "Write"},
+ {24, &BSD::Write, "Write"},
{25, nullptr, "Read"},
{26, &BSD::Close, "Close"},
{27, nullptr, "DuplicateSocket"},
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 3098e3baf..357531951 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -4,30 +4,174 @@
#pragma once
+#include <memory>
+#include <string_view>
+#include <vector>
+
+#include "common/common_types.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/service.h"
+#include "core/hle/service/sockets/blocking_worker.h"
+#include "core/hle/service/sockets/sockets.h"
+
+namespace Core {
+class System;
+}
+
+namespace Network {
+class Socket;
+}
namespace Service::Sockets {
class BSD final : public ServiceFramework<BSD> {
public:
- explicit BSD(const char* name);
+ explicit BSD(Core::System& system, const char* name);
~BSD() override;
private:
+ /// Maximum number of file descriptors
+ static constexpr size_t MAX_FD = 128;
+
+ struct FileDescriptor {
+ std::unique_ptr<Network::Socket> socket;
+ s32 flags = 0;
+ bool is_connection_based = false;
+ };
+
+ struct PollWork {
+ void Execute(BSD* bsd);
+ void Response(Kernel::HLERequestContext& ctx);
+
+ s32 nfds;
+ s32 timeout;
+ std::vector<u8> read_buffer;
+ std::vector<u8> write_buffer;
+ s32 ret{};
+ Errno bsd_errno{};
+ };
+
+ struct AcceptWork {
+ void Execute(BSD* bsd);
+ void Response(Kernel::HLERequestContext& ctx);
+
+ s32 fd;
+ std::vector<u8> write_buffer;
+ s32 ret{};
+ Errno bsd_errno{};
+ };
+
+ struct ConnectWork {
+ void Execute(BSD* bsd);
+ void Response(Kernel::HLERequestContext& ctx);
+
+ s32 fd;
+ std::vector<u8> addr;
+ Errno bsd_errno{};
+ };
+
+ struct RecvWork {
+ void Execute(BSD* bsd);
+ void Response(Kernel::HLERequestContext& ctx);
+
+ s32 fd;
+ u32 flags;
+ std::vector<u8> message;
+ s32 ret{};
+ Errno bsd_errno{};
+ };
+
+ struct RecvFromWork {
+ void Execute(BSD* bsd);
+ void Response(Kernel::HLERequestContext& ctx);
+
+ s32 fd;
+ u32 flags;
+ std::vector<u8> message;
+ std::vector<u8> addr;
+ s32 ret{};
+ Errno bsd_errno{};
+ };
+
+ struct SendWork {
+ void Execute(BSD* bsd);
+ void Response(Kernel::HLERequestContext& ctx);
+
+ s32 fd;
+ u32 flags;
+ std::vector<u8> message;
+ s32 ret{};
+ Errno bsd_errno{};
+ };
+
+ struct SendToWork {
+ void Execute(BSD* bsd);
+ void Response(Kernel::HLERequestContext& ctx);
+
+ s32 fd;
+ u32 flags;
+ std::vector<u8> message;
+ std::vector<u8> addr;
+ s32 ret{};
+ Errno bsd_errno{};
+ };
+
void RegisterClient(Kernel::HLERequestContext& ctx);
void StartMonitoring(Kernel::HLERequestContext& ctx);
void Socket(Kernel::HLERequestContext& ctx);
void Select(Kernel::HLERequestContext& ctx);
+ void Poll(Kernel::HLERequestContext& ctx);
+ void Accept(Kernel::HLERequestContext& ctx);
void Bind(Kernel::HLERequestContext& ctx);
void Connect(Kernel::HLERequestContext& ctx);
+ void GetPeerName(Kernel::HLERequestContext& ctx);
+ void GetSockName(Kernel::HLERequestContext& ctx);
void Listen(Kernel::HLERequestContext& ctx);
+ void Fcntl(Kernel::HLERequestContext& ctx);
void SetSockOpt(Kernel::HLERequestContext& ctx);
+ void Shutdown(Kernel::HLERequestContext& ctx);
+ void Recv(Kernel::HLERequestContext& ctx);
+ void RecvFrom(Kernel::HLERequestContext& ctx);
+ void Send(Kernel::HLERequestContext& ctx);
void SendTo(Kernel::HLERequestContext& ctx);
+ void Write(Kernel::HLERequestContext& ctx);
void Close(Kernel::HLERequestContext& ctx);
- /// Id to use for the next open file descriptor.
- u32 next_fd = 1;
+ template <typename Work>
+ void ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason,
+ bool is_blocking, Work work);
+
+ std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
+ std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
+ s32 nfds, s32 timeout);
+ std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
+ Errno BindImpl(s32 fd, const std::vector<u8>& addr);
+ Errno ConnectImpl(s32 fd, const std::vector<u8>& addr);
+ Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
+ Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
+ Errno ListenImpl(s32 fd, s32 backlog);
+ std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
+ Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval);
+ Errno ShutdownImpl(s32 fd, s32 how);
+ std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
+ std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
+ std::vector<u8>& addr);
+ std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, const std::vector<u8>& message);
+ std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
+ const std::vector<u8>& addr);
+ Errno CloseImpl(s32 fd);
+
+ s32 FindFreeFileDescriptorHandle() noexcept;
+ bool IsFileDescriptorValid(s32 fd) const noexcept;
+ bool IsBlockingSocket(s32 fd) const noexcept;
+
+ void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept;
+
+ std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
+
+ BlockingWorkerPool<BSD, PollWork, AcceptWork, ConnectWork, RecvWork, RecvFromWork, SendWork,
+ SendToWork>
+ worker_pool;
};
class BSDCFG final : public ServiceFramework<BSDCFG> {
diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp
index 08d2d306a..1d27f7906 100644
--- a/src/core/hle/service/sockets/sockets.cpp
+++ b/src/core/hle/service/sockets/sockets.cpp
@@ -10,9 +10,9 @@
namespace Service::Sockets {
-void InstallInterfaces(SM::ServiceManager& service_manager) {
- std::make_shared<BSD>("bsd:s")->InstallAsService(service_manager);
- std::make_shared<BSD>("bsd:u")->InstallAsService(service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+ std::make_shared<BSD>(system, "bsd:s")->InstallAsService(service_manager);
+ std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager);
std::make_shared<BSDCFG>()->InstallAsService(service_manager);
std::make_shared<ETHC_C>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index ca8a6a7e0..89a410076 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -4,11 +4,94 @@
#pragma once
+#include "common/common_types.h"
#include "core/hle/service/service.h"
+namespace Core {
+class System;
+}
+
namespace Service::Sockets {
+enum class Errno : u32 {
+ SUCCESS = 0,
+ BADF = 9,
+ AGAIN = 11,
+ INVAL = 22,
+ MFILE = 24,
+ NOTCONN = 107,
+};
+
+enum class Domain : u32 {
+ INET = 2,
+};
+
+enum class Type : u32 {
+ STREAM = 1,
+ DGRAM = 2,
+ RAW = 3,
+ SEQPACKET = 5,
+};
+
+enum class Protocol : u32 {
+ UNSPECIFIED = 0,
+ ICMP = 1,
+ TCP = 6,
+ UDP = 17,
+};
+
+enum class OptName : u32 {
+ REUSEADDR = 0x4,
+ BROADCAST = 0x20,
+ LINGER = 0x80,
+ SNDBUF = 0x1001,
+ RCVBUF = 0x1002,
+ SNDTIMEO = 0x1005,
+ RCVTIMEO = 0x1006,
+};
+
+enum class ShutdownHow : s32 {
+ RD = 0,
+ WR = 1,
+ RDWR = 2,
+};
+
+enum class FcntlCmd : s32 {
+ GETFL = 3,
+ SETFL = 4,
+};
+
+struct SockAddrIn {
+ u8 len;
+ u8 family;
+ u16 portno;
+ std::array<u8, 4> ip;
+ std::array<u8, 8> zeroes;
+};
+
+struct PollFD {
+ s32 fd;
+ u16 events;
+ u16 revents;
+};
+
+struct Linger {
+ u32 onoff;
+ u32 linger;
+};
+
+constexpr u16 POLL_IN = 0x01;
+constexpr u16 POLL_PRI = 0x02;
+constexpr u16 POLL_OUT = 0x04;
+constexpr u16 POLL_ERR = 0x08;
+constexpr u16 POLL_HUP = 0x10;
+constexpr u16 POLL_NVAL = 0x20;
+
+constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
+
+constexpr u32 FLAG_O_NONBLOCK = 0x800;
+
/// Registers all Sockets services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
new file mode 100644
index 000000000..2e626fd86
--- /dev/null
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -0,0 +1,165 @@
+// Copyright 2020 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <utility>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "core/hle/service/sockets/sockets.h"
+#include "core/hle/service/sockets/sockets_translate.h"
+#include "core/network/network.h"
+
+namespace Service::Sockets {
+
+Errno Translate(Network::Errno value) {
+ switch (value) {
+ case Network::Errno::SUCCESS:
+ return Errno::SUCCESS;
+ case Network::Errno::BADF:
+ return Errno::BADF;
+ case Network::Errno::AGAIN:
+ return Errno::AGAIN;
+ case Network::Errno::INVAL:
+ return Errno::INVAL;
+ case Network::Errno::MFILE:
+ return Errno::MFILE;
+ case Network::Errno::NOTCONN:
+ return Errno::NOTCONN;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented errno={}", static_cast<int>(value));
+ return Errno::SUCCESS;
+ }
+}
+
+std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) {
+ return {value.first, Translate(value.second)};
+}
+
+Network::Domain Translate(Domain domain) {
+ switch (domain) {
+ case Domain::INET:
+ return Network::Domain::INET;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain));
+ return {};
+ }
+}
+
+Domain Translate(Network::Domain domain) {
+ switch (domain) {
+ case Network::Domain::INET:
+ return Domain::INET;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain));
+ return {};
+ }
+}
+
+Network::Type Translate(Type type) {
+ switch (type) {
+ case Type::STREAM:
+ return Network::Type::STREAM;
+ case Type::DGRAM:
+ return Network::Type::DGRAM;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type));
+ }
+}
+
+Network::Protocol Translate(Type type, Protocol protocol) {
+ switch (protocol) {
+ case Protocol::UNSPECIFIED:
+ LOG_WARNING(Service, "Unspecified protocol, assuming protocol from type");
+ switch (type) {
+ case Type::DGRAM:
+ return Network::Protocol::UDP;
+ case Type::STREAM:
+ return Network::Protocol::TCP;
+ default:
+ return Network::Protocol::TCP;
+ }
+ case Protocol::TCP:
+ return Network::Protocol::TCP;
+ case Protocol::UDP:
+ return Network::Protocol::UDP;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol));
+ return Network::Protocol::TCP;
+ }
+}
+
+u16 TranslatePollEventsToHost(u32 flags) {
+ u32 result = 0;
+ const auto translate = [&result, &flags](u32 from, u32 to) {
+ if ((flags & from) != 0) {
+ flags &= ~from;
+ result |= to;
+ }
+ };
+ translate(POLL_IN, Network::POLL_IN);
+ translate(POLL_PRI, Network::POLL_PRI);
+ translate(POLL_OUT, Network::POLL_OUT);
+ translate(POLL_ERR, Network::POLL_ERR);
+ translate(POLL_HUP, Network::POLL_HUP);
+ translate(POLL_NVAL, Network::POLL_NVAL);
+
+ UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags);
+ return static_cast<u16>(result);
+}
+
+u16 TranslatePollEventsToGuest(u32 flags) {
+ u32 result = 0;
+ const auto translate = [&result, &flags](u32 from, u32 to) {
+ if ((flags & from) != 0) {
+ flags &= ~from;
+ result |= to;
+ }
+ };
+
+ translate(Network::POLL_IN, POLL_IN);
+ translate(Network::POLL_PRI, POLL_PRI);
+ translate(Network::POLL_OUT, POLL_OUT);
+ translate(Network::POLL_ERR, POLL_ERR);
+ translate(Network::POLL_HUP, POLL_HUP);
+ translate(Network::POLL_NVAL, POLL_NVAL);
+
+ UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags);
+ return static_cast<u16>(result);
+}
+
+Network::SockAddrIn Translate(SockAddrIn value) {
+ ASSERT(value.len == 0 || value.len == sizeof(value));
+
+ return {
+ .family = Translate(static_cast<Domain>(value.family)),
+ .ip = value.ip,
+ .portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
+ };
+}
+
+SockAddrIn Translate(Network::SockAddrIn value) {
+ return {
+ .len = sizeof(SockAddrIn),
+ .family = static_cast<u8>(Translate(value.family)),
+ .portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
+ .ip = value.ip,
+ .zeroes = {},
+ };
+}
+
+Network::ShutdownHow Translate(ShutdownHow how) {
+ switch (how) {
+ case ShutdownHow::RD:
+ return Network::ShutdownHow::RD;
+ case ShutdownHow::WR:
+ return Network::ShutdownHow::WR;
+ case ShutdownHow::RDWR:
+ return Network::ShutdownHow::RDWR;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented how={}", static_cast<int>(how));
+ return {};
+ }
+}
+
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets_translate.h b/src/core/hle/service/sockets/sockets_translate.h
new file mode 100644
index 000000000..e498913d4
--- /dev/null
+++ b/src/core/hle/service/sockets/sockets_translate.h
@@ -0,0 +1,48 @@
+// Copyright 2020 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <utility>
+
+#include "common/common_types.h"
+#include "core/hle/service/sockets/sockets.h"
+#include "core/network/network.h"
+
+namespace Service::Sockets {
+
+/// Translate abstract errno to guest errno
+Errno Translate(Network::Errno value);
+
+/// Translate abstract return value errno pair to guest return value errno pair
+std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value);
+
+/// Translate guest domain to abstract domain
+Network::Domain Translate(Domain domain);
+
+/// Translate abstract domain to guest domain
+Domain Translate(Network::Domain domain);
+
+/// Translate guest type to abstract type
+Network::Type Translate(Type type);
+
+/// Translate guest protocol to abstract protocol
+Network::Protocol Translate(Type type, Protocol protocol);
+
+/// Translate abstract poll event flags to guest poll event flags
+u16 TranslatePollEventsToHost(u32 flags);
+
+/// Translate guest poll event flags to abstract poll event flags
+u16 TranslatePollEventsToGuest(u32 flags);
+
+/// Translate guest socket address structure to abstract socket address structure
+Network::SockAddrIn Translate(SockAddrIn value);
+
+/// Translate abstract socket address structure to guest socket address structure
+SockAddrIn Translate(Network::SockAddrIn value);
+
+/// Translate guest shutdown mode to abstract shutdown mode
+Network::ShutdownHow Translate(ShutdownHow how);
+
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
index 69152d0ac..bdf0439f2 100644
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -820,7 +820,10 @@ static ResultCode ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, Calend
const ResultCode result{
ToCalendarTimeInternal(rules, time, calendar_time, calendar.additiona_info)};
calendar.time.year = static_cast<s16>(calendar_time.year);
- calendar.time.month = calendar_time.month + 1; // Internal impl. uses 0-indexed month
+
+ // Internal impl. uses 0-indexed month
+ calendar.time.month = static_cast<s8>(calendar_time.month + 1);
+
calendar.time.day = calendar_time.day;
calendar.time.hour = calendar_time.hour;
calendar.time.minute = calendar_time.minute;
@@ -872,13 +875,15 @@ ResultCode TimeZoneManager::ToPosixTime(const TimeZoneRule& rules,
const CalendarTime& calendar_time, s64& posix_time) const {
posix_time = 0;
- CalendarTimeInternal internal_time{};
- internal_time.year = calendar_time.year;
- internal_time.month = calendar_time.month - 1; // Internal impl. uses 0-indexed month
- internal_time.day = calendar_time.day;
- internal_time.hour = calendar_time.hour;
- internal_time.minute = calendar_time.minute;
- internal_time.second = calendar_time.second;
+ CalendarTimeInternal internal_time{
+ .year = calendar_time.year,
+ // Internal impl. uses 0-indexed month
+ .month = static_cast<s8>(calendar_time.month - 1),
+ .day = calendar_time.day,
+ .hour = calendar_time.hour,
+ .minute = calendar_time.minute,
+ .second = calendar_time.second,
+ };
s32 hour{internal_time.hour};
s32 minute{internal_time.minute};
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 480d34725..5b0e371fe 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -159,7 +159,7 @@ public:
header.data_size = static_cast<u32_le>(write_index - sizeof(Header));
header.data_offset = sizeof(Header);
header.objects_size = 4;
- header.objects_offset = sizeof(Header) + header.data_size;
+ header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
std::memcpy(buffer.data(), &header, sizeof(Header));
return buffer;
@@ -215,10 +215,9 @@ public:
explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
Deserialize();
}
- ~IGBPConnectRequestParcel() override = default;
void DeserializeData() override {
- std::u16string token = ReadInterfaceToken();
+ [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
data = Read<Data>();
}
@@ -279,10 +278,9 @@ public:
: Parcel(std::move(buffer)) {
Deserialize();
}
- ~IGBPSetPreallocatedBufferRequestParcel() override = default;
void DeserializeData() override {
- std::u16string token = ReadInterfaceToken();
+ [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
data = Read<Data>();
buffer = Read<NVFlinger::IGBPBuffer>();
}
@@ -306,15 +304,40 @@ protected:
}
};
+class IGBPCancelBufferRequestParcel : public Parcel {
+public:
+ explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
+ Deserialize();
+ }
+
+ void DeserializeData() override {
+ [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
+ data = Read<Data>();
+ }
+
+ struct Data {
+ u32_le slot;
+ Service::Nvidia::MultiFence multi_fence;
+ };
+
+ Data data;
+};
+
+class IGBPCancelBufferResponseParcel : public Parcel {
+protected:
+ void SerializeData() override {
+ Write<u32>(0); // Success
+ }
+};
+
class IGBPDequeueBufferRequestParcel : public Parcel {
public:
explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
Deserialize();
}
- ~IGBPDequeueBufferRequestParcel() override = default;
void DeserializeData() override {
- std::u16string token = ReadInterfaceToken();
+ [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
data = Read<Data>();
}
@@ -333,7 +356,6 @@ class IGBPDequeueBufferResponseParcel : public Parcel {
public:
explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence)
: slot(slot), multi_fence(multi_fence) {}
- ~IGBPDequeueBufferResponseParcel() override = default;
protected:
void SerializeData() override {
@@ -352,10 +374,9 @@ public:
explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
Deserialize();
}
- ~IGBPRequestBufferRequestParcel() override = default;
void DeserializeData() override {
- std::u16string token = ReadInterfaceToken();
+ [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
slot = Read<u32_le>();
}
@@ -384,10 +405,9 @@ public:
explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
Deserialize();
}
- ~IGBPQueueBufferRequestParcel() override = default;
void DeserializeData() override {
- std::u16string token = ReadInterfaceToken();
+ [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
data = Read<Data>();
}
@@ -447,10 +467,9 @@ public:
explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
Deserialize();
}
- ~IGBPQueryRequestParcel() override = default;
void DeserializeData() override {
- std::u16string token = ReadInterfaceToken();
+ [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
type = Read<u32_le>();
}
@@ -596,7 +615,12 @@ private:
break;
}
case TransactionId::CancelBuffer: {
- LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
+ IGBPCancelBufferRequestParcel request{ctx.ReadBuffer()};
+
+ buffer_queue.CancelBuffer(request.data.slot, request.data.multi_fence);
+
+ IGBPCancelBufferResponseParcel response{};
+ ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::Disconnect: {
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 134e83412..394a1bf26 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -89,7 +89,7 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua
}
AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirectory::Load(
- Kernel::Process& process) {
+ Kernel::Process& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -141,9 +141,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
continue;
}
- const bool should_pass_arguments{std::strcmp(module, "rtld") == 0};
- const auto tentative_next_load_addr{AppLoader_NSO::LoadModule(
- process, *module_file, code_size, should_pass_arguments, false)};
+ const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
+ const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
+ process, system, *module_file, code_size, should_pass_arguments, false);
if (!tentative_next_load_addr) {
return {ResultStatus::ErrorLoadingNSO, {}};
}
@@ -168,9 +168,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
}
const VAddr load_addr{next_load_addr};
- const bool should_pass_arguments{std::strcmp(module, "rtld") == 0};
- const auto tentative_next_load_addr{AppLoader_NSO::LoadModule(
- process, *module_file, load_addr, should_pass_arguments, true, pm)};
+ const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
+ const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
+ process, system, *module_file, load_addr, should_pass_arguments, true, pm);
if (!tentative_next_load_addr) {
return {ResultStatus::ErrorLoadingNSO, {}};
}
@@ -192,8 +192,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
// Register the RomFS if a ".romfs" file was found
if (romfs_iter != files.end() && *romfs_iter != nullptr) {
romfs = *romfs_iter;
- Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
- std::make_unique<FileSys::RomFSFactory>(*this));
+ system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(
+ *this, system.GetContentProvider(), system.GetFileSystemController()));
}
is_loaded = true;
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index 1c0a354a4..35d340317 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -9,6 +9,10 @@
#include "core/file_sys/program_metadata.h"
#include "core/loader/loader.h"
+namespace Core {
+class System;
+}
+
namespace Loader {
/**
@@ -37,7 +41,7 @@ public:
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process) override;
+ LoadResult Load(Kernel::Process& process, Core::System& system) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 8f7615115..dca1fcb18 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -383,7 +383,8 @@ FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process) {
+AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process,
+ [[maybe_unused]] Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 7ef7770a6..3527933ad 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -8,6 +8,10 @@
#include "common/common_types.h"
#include "core/loader/loader.h"
+namespace Core {
+class System;
+}
+
namespace Loader {
/// Loads an ELF/AXF file
@@ -26,7 +30,7 @@ public:
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process) override;
+ LoadResult Load(Kernel::Process& process, Core::System& system) override;
};
} // namespace Loader
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index 40fa03ad1..2a905d3e4 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -16,7 +16,7 @@ namespace Loader {
namespace {
constexpr u32 PageAlignSize(u32 size) {
- return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK;
+ return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
}
} // Anonymous namespace
@@ -43,7 +43,8 @@ FileType AppLoader_KIP::GetFileType() const {
: FileType::Error;
}
-AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process) {
+AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process,
+ [[maybe_unused]] Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
diff --git a/src/core/loader/kip.h b/src/core/loader/kip.h
index 12ca40269..dee05a7b5 100644
--- a/src/core/loader/kip.h
+++ b/src/core/loader/kip.h
@@ -6,6 +6,10 @@
#include "core/loader/loader.h"
+namespace Core {
+class System;
+}
+
namespace FileSys {
class KIP;
}
@@ -26,7 +30,7 @@ public:
FileType GetFileType() const override;
- LoadResult Load(Kernel::Process& process) override;
+ LoadResult Load(Kernel::Process& process, Core::System& system) override;
private:
std::unique_ptr<FileSys::KIP> kip;
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 227ecc704..ac60b097a 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -15,6 +15,10 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/vfs.h"
+namespace Core {
+class System;
+}
+
namespace FileSys {
class NACP;
} // namespace FileSys
@@ -154,9 +158,10 @@ public:
/**
* Load the application and return the created Process instance
* @param process The newly created process.
+ * @param system The system that this process is being loaded under.
* @return The status result of the operation.
*/
- virtual LoadResult Load(Kernel::Process& process) = 0;
+ virtual LoadResult Load(Kernel::Process& process, Core::System& system) = 0;
/**
* Get the code (typically .code section) of the application
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index a152981a0..49028177b 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -41,7 +41,8 @@ FileType AppLoader_NAX::GetFileType() const {
return IdentifyTypeImpl(*nax);
}
-AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process) {
+AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process,
+ [[maybe_unused]] Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -65,7 +66,7 @@ AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process) {
return {nca_status, {}};
}
- const auto result = nca_loader->Load(process);
+ const auto result = nca_loader->Load(process, system);
if (result.first != ResultStatus::Success) {
return result;
}
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index eaec9bf58..c2b7722b5 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -8,10 +8,12 @@
#include "common/common_types.h"
#include "core/loader/loader.h"
-namespace FileSys {
+namespace Core {
+class System;
+}
+namespace FileSys {
class NAX;
-
} // namespace FileSys
namespace Loader {
@@ -33,7 +35,7 @@ public:
FileType GetFileType() const override;
- LoadResult Load(Kernel::Process& process) override;
+ LoadResult Load(Kernel::Process& process, Core::System& system) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 5a0469978..fa694de37 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -31,7 +31,7 @@ FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process) {
+AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -52,14 +52,14 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process) {
directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs, true);
- const auto load_result = directory_loader->Load(process);
+ const auto load_result = directory_loader->Load(process, system);
if (load_result.first != ResultStatus::Success) {
return load_result;
}
if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) {
- Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
- std::make_unique<FileSys::RomFSFactory>(*this));
+ system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(
+ *this, system.GetContentProvider(), system.GetFileSystemController()));
}
is_loaded = true;
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index e47dc0e47..711070294 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -8,6 +8,10 @@
#include "core/file_sys/vfs.h"
#include "core/loader/loader.h"
+namespace Core {
+class System;
+}
+
namespace FileSys {
class NCA;
}
@@ -33,7 +37,7 @@ public:
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process) override;
+ LoadResult Load(Kernel::Process& process, Core::System& system) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 906544bc9..5f4b3104b 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -127,7 +127,7 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) {
}
static constexpr u32 PageAlignSize(u32 size) {
- return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK;
+ return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
}
static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
@@ -208,7 +208,7 @@ bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& fi
return LoadNroImpl(process, file.ReadAllBytes(), file.GetName());
}
-AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
+AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -218,8 +218,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
}
if (romfs != nullptr) {
- Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
- std::make_unique<FileSys::RomFSFactory>(*this));
+ system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(
+ *this, system.GetContentProvider(), system.GetFileSystemController()));
}
is_loaded = true;
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 4593d48fb..a2aab2ecc 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -10,6 +10,10 @@
#include "common/common_types.h"
#include "core/loader/loader.h"
+namespace Core {
+class System;
+}
+
namespace FileSys {
class NACP;
}
@@ -37,7 +41,7 @@ public:
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process) override;
+ LoadResult Load(Kernel::Process& process, Core::System& system) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 575330a86..497f438a1 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -47,7 +47,7 @@ std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
}
constexpr u32 PageAlignSize(u32 size) {
- return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK;
+ return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
}
} // Anonymous namespace
@@ -71,21 +71,21 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::NSO;
}
-std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
+std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::System& system,
const FileSys::VfsFile& file, VAddr load_base,
bool should_pass_arguments, bool load_into_process,
std::optional<FileSys::PatchManager> pm) {
if (file.GetSize() < sizeof(NSOHeader)) {
- return {};
+ return std::nullopt;
}
NSOHeader nso_header{};
if (sizeof(NSOHeader) != file.ReadObject(&nso_header)) {
- return {};
+ return std::nullopt;
}
if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) {
- return {};
+ return std::nullopt;
}
// Build program image
@@ -148,7 +148,6 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
// Apply cheats if they exist and the program has a valid title ID
if (pm) {
- auto& system = Core::System::GetInstance();
system.SetCurrentProcessBuildID(nso_header.build_id);
const auto cheats = pm->CreateCheatList(system, nso_header.build_id);
if (!cheats.empty()) {
@@ -166,7 +165,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
return load_base + image_size;
}
-AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) {
+AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -175,7 +174,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) {
// Load module
const VAddr base_address = process.PageTable().GetCodeRegionStart();
- if (!LoadModule(process, *file, base_address, true, true)) {
+ if (!LoadModule(process, system, *file, base_address, true, true)) {
return {ResultStatus::ErrorLoadingNSO, {}};
}
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index b210830f0..d331096ae 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -12,6 +12,10 @@
#include "core/file_sys/patch_manager.h"
#include "core/loader/loader.h"
+namespace Core {
+class System;
+}
+
namespace Kernel {
class Process;
}
@@ -55,7 +59,7 @@ struct NSOHeader {
static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
-constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
+constexpr u32 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
struct NSOArgumentHeader {
u32_le allocated_size;
@@ -80,12 +84,12 @@ public:
return IdentifyType(file);
}
- static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file,
- VAddr load_base, bool should_pass_arguments,
- bool load_into_process,
+ static std::optional<VAddr> LoadModule(Kernel::Process& process, Core::System& system,
+ const FileSys::VfsFile& file, VAddr load_base,
+ bool should_pass_arguments, bool load_into_process,
std::optional<FileSys::PatchManager> pm = {});
- LoadResult Load(Kernel::Process& process) override;
+ LoadResult Load(Kernel::Process& process, Core::System& system) override;
ResultStatus ReadNSOModules(Modules& modules) override;
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 13950fc08..15e528fa8 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -71,7 +71,7 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process) {
+AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -99,15 +99,14 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process) {
return {ResultStatus::ErrorNSPMissingProgramNCA, {}};
}
- const auto result = secondary_loader->Load(process);
+ const auto result = secondary_loader->Load(process, system);
if (result.first != ResultStatus::Success) {
return result;
}
FileSys::VirtualFile update_raw;
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
- Core::System::GetInstance().GetFileSystemController().SetPackedUpdate(
- std::move(update_raw));
+ system.GetFileSystemController().SetPackedUpdate(std::move(update_raw));
}
is_loaded = true;
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 868b028d3..b27deb686 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -9,6 +9,10 @@
#include "core/file_sys/vfs.h"
#include "core/loader/loader.h"
+namespace Core {
+class System;
+}
+
namespace FileSys {
class NACP;
class NSP;
@@ -35,7 +39,7 @@ public:
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process) override;
+ LoadResult Load(Kernel::Process& process, Core::System& system) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 7186ad1ff..25e83af0f 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -49,7 +49,7 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process) {
+AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -66,15 +66,14 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process) {
return {ResultStatus::ErrorMissingProductionKeyFile, {}};
}
- const auto result = nca_loader->Load(process);
+ const auto result = nca_loader->Load(process, system);
if (result.first != ResultStatus::Success) {
return result;
}
FileSys::VirtualFile update_raw;
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
- Core::System::GetInstance().GetFileSystemController().SetPackedUpdate(
- std::move(update_raw));
+ system.GetFileSystemController().SetPackedUpdate(std::move(update_raw));
}
is_loaded = true;
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 618ae2f47..04aea286f 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -9,6 +9,10 @@
#include "core/file_sys/vfs.h"
#include "core/loader/loader.h"
+namespace Core {
+class System;
+}
+
namespace FileSys {
class NACP;
class XCI;
@@ -35,7 +39,7 @@ public:
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process) override;
+ LoadResult Load(Kernel::Process& process, Core::System& system) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 86d17c6cb..b88aa5c40 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -120,9 +120,9 @@ struct Memory::Impl {
if ((addr & 1) == 0) {
return Read<u16_le>(addr);
} else {
- const u8 a{Read<u8>(addr)};
- const u8 b{Read<u8>(addr + sizeof(u8))};
- return (static_cast<u16>(b) << 8) | a;
+ const u32 a{Read<u8>(addr)};
+ const u32 b{Read<u8>(addr + sizeof(u8))};
+ return static_cast<u16>((b << 8) | a);
}
}
@@ -130,9 +130,9 @@ struct Memory::Impl {
if ((addr & 3) == 0) {
return Read<u32_le>(addr);
} else {
- const u16 a{Read16(addr)};
- const u16 b{Read16(addr + sizeof(u16))};
- return (static_cast<u32>(b) << 16) | a;
+ const u32 a{Read16(addr)};
+ const u32 b{Read16(addr + sizeof(u16))};
+ return (b << 16) | a;
}
}
@@ -567,7 +567,7 @@ struct Memory::Impl {
* @param page_table The page table to use to perform the mapping.
* @param base The base address to begin mapping at.
* @param size The total size of the range in bytes.
- * @param memory The memory to map.
+ * @param target The target address to begin mapping from.
* @param type The page type to map the memory as.
*/
void MapPages(Common::PageTable& page_table, VAddr base, u64 size, PAddr target,
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index e503118dd..2dd0eb0f8 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -19,10 +19,24 @@
#include "core/memory/cheat_engine.h"
namespace Core::Memory {
-
+namespace {
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
+std::string_view ExtractName(std::string_view data, std::size_t start_index, char match) {
+ auto end_index = start_index;
+ while (data[end_index] != match) {
+ ++end_index;
+ if (end_index > data.size() ||
+ (end_index - start_index - 1) > sizeof(CheatDefinition::readable_name)) {
+ return {};
+ }
+ }
+
+ return data.substr(start_index, end_index - start_index);
+}
+} // Anonymous namespace
+
StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
: metadata(metadata), system(system) {}
@@ -82,26 +96,9 @@ CheatParser::~CheatParser() = default;
TextCheatParser::~TextCheatParser() = default;
-namespace {
-template <char match>
-std::string_view ExtractName(std::string_view data, std::size_t start_index) {
- auto end_index = start_index;
- while (data[end_index] != match) {
- ++end_index;
- if (end_index > data.size() ||
- (end_index - start_index - 1) > sizeof(CheatDefinition::readable_name)) {
- return {};
- }
- }
-
- return data.substr(start_index, end_index - start_index);
-}
-} // Anonymous namespace
-
-std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system,
- std::string_view data) const {
+std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
std::vector<CheatEntry> out(1);
- std::optional<u64> current_entry = std::nullopt;
+ std::optional<u64> current_entry;
for (std::size_t i = 0; i < data.size(); ++i) {
if (::isspace(data[i])) {
@@ -115,7 +112,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system,
return {};
}
- const auto name = ExtractName<'}'>(data, i + 1);
+ const auto name = ExtractName(data, i + 1, '}');
if (name.empty()) {
return {};
}
@@ -132,7 +129,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system,
current_entry = out.size();
out.emplace_back();
- const auto name = ExtractName<']'>(data, i + 1);
+ const auto name = ExtractName(data, i + 1, ']');
if (name.empty()) {
return {};
}
@@ -156,8 +153,9 @@ std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system,
return {};
}
+ const auto value = static_cast<u32>(std::stoul(hex, nullptr, 0x10));
out[*current_entry].definition.opcodes[out[*current_entry].definition.num_opcodes++] =
- std::stoul(hex, nullptr, 0x10);
+ value;
i += 8;
} else {
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index fa039a831..a31002346 100644
--- a/src/core/memory/cheat_engine.h
+++ b/src/core/memory/cheat_engine.h
@@ -47,8 +47,7 @@ class CheatParser {
public:
virtual ~CheatParser();
- virtual std::vector<CheatEntry> Parse(const Core::System& system,
- std::string_view data) const = 0;
+ [[nodiscard]] virtual std::vector<CheatEntry> Parse(std::string_view data) const = 0;
};
// CheatParser implementation that parses text files
@@ -56,7 +55,7 @@ class TextCheatParser final : public CheatParser {
public:
~TextCheatParser() override;
- std::vector<CheatEntry> Parse(const Core::System& system, std::string_view data) const override;
+ [[nodiscard]] std::vector<CheatEntry> Parse(std::string_view data) const override;
};
// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index 56d173b5e..4b3bb4366 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -238,14 +238,14 @@ SockAddrIn TranslateToSockAddrIn(sockaddr input_) {
return result;
}
-u16 TranslatePollEvents(u16 events) {
- u16 result = 0;
+u16 TranslatePollEvents(u32 events) {
+ u32 result = 0;
- if (events & POLL_IN) {
+ if ((events & POLL_IN) != 0) {
events &= ~POLL_IN;
result |= POLLIN;
}
- if (events & POLL_PRI) {
+ if ((events & POLL_PRI) != 0) {
events &= ~POLL_PRI;
#ifdef _WIN32
LOG_WARNING(Service, "Winsock doesn't support POLLPRI");
@@ -253,20 +253,20 @@ u16 TranslatePollEvents(u16 events) {
result |= POLL_PRI;
#endif
}
- if (events & POLL_OUT) {
+ if ((events & POLL_OUT) != 0) {
events &= ~POLL_OUT;
result |= POLLOUT;
}
UNIMPLEMENTED_IF_MSG(events != 0, "Unhandled guest events=0x{:x}", events);
- return result;
+ return static_cast<u16>(result);
}
-u16 TranslatePollRevents(u16 revents) {
- u16 result = 0;
- const auto translate = [&result, &revents](int host, unsigned guest) {
- if (revents & host) {
+u16 TranslatePollRevents(u32 revents) {
+ u32 result = 0;
+ const auto translate = [&result, &revents](u32 host, u32 guest) {
+ if ((revents & host) != 0) {
revents &= ~host;
result |= guest;
}
@@ -280,7 +280,7 @@ u16 TranslatePollRevents(u16 revents) {
UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents);
- return result;
+ return static_cast<u16>(result);
}
template <typename T>
@@ -350,7 +350,7 @@ std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
}
for (size_t i = 0; i < num; ++i) {
- pollfds[i].revents = TranslatePollRevents(host_pollfds[i].revents);
+ pollfds[i].revents = TranslatePollRevents(static_cast<u32>(host_pollfds[i].revents));
}
if (result > 0) {
@@ -408,7 +408,7 @@ std::pair<Socket::AcceptResult, Errno> Socket::Accept() {
Errno Socket::Connect(SockAddrIn addr_in) {
const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in);
- if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != INVALID_SOCKET) {
+ if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != SOCKET_ERROR) {
return Errno::SUCCESS;
}
@@ -503,10 +503,10 @@ std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
ASSERT(flags == 0);
ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
- const int result =
+ const auto result =
recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0);
if (result != SOCKET_ERROR) {
- return {result, Errno::SUCCESS};
+ return {static_cast<s32>(result), Errno::SUCCESS};
}
switch (const int ec = LastError()) {
@@ -531,14 +531,14 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock
socklen_t* const p_addrlen = addr ? &addrlen : nullptr;
sockaddr* const p_addr_in = addr ? &addr_in : nullptr;
- const int result = recvfrom(fd, reinterpret_cast<char*>(message.data()),
- static_cast<int>(message.size()), 0, p_addr_in, p_addrlen);
+ const auto result = recvfrom(fd, reinterpret_cast<char*>(message.data()),
+ static_cast<int>(message.size()), 0, p_addr_in, p_addrlen);
if (result != SOCKET_ERROR) {
if (addr) {
ASSERT(addrlen == sizeof(addr_in));
*addr = TranslateToSockAddrIn(addr_in);
}
- return {result, Errno::SUCCESS};
+ return {static_cast<s32>(result), Errno::SUCCESS};
}
switch (const int ec = LastError()) {
@@ -558,10 +558,10 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
ASSERT(flags == 0);
- const int result = send(fd, reinterpret_cast<const char*>(message.data()),
- static_cast<int>(message.size()), 0);
+ const auto result = send(fd, reinterpret_cast<const char*>(message.data()),
+ static_cast<int>(message.size()), 0);
if (result != SOCKET_ERROR) {
- return {result, Errno::SUCCESS};
+ return {static_cast<s32>(result), Errno::SUCCESS};
}
const int ec = LastError();
@@ -591,10 +591,10 @@ std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
to = &host_addr_in;
}
- const int result = sendto(fd, reinterpret_cast<const char*>(message.data()),
- static_cast<int>(message.size()), 0, to, tolen);
+ const auto result = sendto(fd, reinterpret_cast<const char*>(message.data()),
+ static_cast<int>(message.size()), 0, to, tolen);
if (result != SOCKET_ERROR) {
- return {result, Errno::SUCCESS};
+ return {static_cast<s32>(result), Errno::SUCCESS};
}
const int ec = LastError();
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index d328fb8b7..28d3f9099 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -13,56 +13,6 @@
namespace Settings {
-namespace NativeButton {
-const std::array<const char*, NumButtons> mapping = {{
- "button_a",
- "button_b",
- "button_x",
- "button_y",
- "button_lstick",
- "button_rstick",
- "button_l",
- "button_r",
- "button_zl",
- "button_zr",
- "button_plus",
- "button_minus",
- "button_dleft",
- "button_dup",
- "button_dright",
- "button_ddown",
- "button_lstick_left",
- "button_lstick_up",
- "button_lstick_right",
- "button_lstick_down",
- "button_rstick_left",
- "button_rstick_up",
- "button_rstick_right",
- "button_rstick_down",
- "button_sl",
- "button_sr",
- "button_home",
- "button_screenshot",
-}};
-}
-
-namespace NativeAnalog {
-const std::array<const char*, NumAnalogs> mapping = {{
- "lstick",
- "rstick",
-}};
-}
-
-namespace NativeMouseButton {
-const std::array<const char*, NumMouseButtons> mapping = {{
- "left",
- "right",
- "middle",
- "forward",
- "back",
-}};
-}
-
Values values = {};
bool configuring_global = true;
diff --git a/src/core/settings.h b/src/core/settings.h
index bb145f193..9834f44bb 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -12,340 +12,10 @@
#include <string>
#include <vector>
#include "common/common_types.h"
+#include "input_common/settings.h"
namespace Settings {
-namespace NativeButton {
-enum Values {
- A,
- B,
- X,
- Y,
- LStick,
- RStick,
- L,
- R,
- ZL,
- ZR,
- Plus,
- Minus,
-
- DLeft,
- DUp,
- DRight,
- DDown,
-
- LStick_Left,
- LStick_Up,
- LStick_Right,
- LStick_Down,
-
- RStick_Left,
- RStick_Up,
- RStick_Right,
- RStick_Down,
-
- SL,
- SR,
-
- Home,
- Screenshot,
-
- NumButtons,
-};
-
-constexpr int BUTTON_HID_BEGIN = A;
-constexpr int BUTTON_NS_BEGIN = Home;
-
-constexpr int BUTTON_HID_END = BUTTON_NS_BEGIN;
-constexpr int BUTTON_NS_END = NumButtons;
-
-constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
-constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
-
-extern const std::array<const char*, NumButtons> mapping;
-
-} // namespace NativeButton
-
-namespace NativeAnalog {
-enum Values {
- LStick,
- RStick,
-
- NumAnalogs,
-};
-
-constexpr int STICK_HID_BEGIN = LStick;
-constexpr int STICK_HID_END = NumAnalogs;
-constexpr int NUM_STICKS_HID = NumAnalogs;
-
-extern const std::array<const char*, NumAnalogs> mapping;
-} // namespace NativeAnalog
-
-namespace NativeMouseButton {
-enum Values {
- Left,
- Right,
- Middle,
- Forward,
- Back,
-
- NumMouseButtons,
-};
-
-constexpr int MOUSE_HID_BEGIN = Left;
-constexpr int MOUSE_HID_END = NumMouseButtons;
-constexpr int NUM_MOUSE_HID = NumMouseButtons;
-
-extern const std::array<const char*, NumMouseButtons> mapping;
-} // namespace NativeMouseButton
-
-namespace NativeKeyboard {
-enum Keys {
- None,
- Error,
-
- A = 4,
- B,
- C,
- D,
- E,
- F,
- G,
- H,
- I,
- J,
- K,
- L,
- M,
- N,
- O,
- P,
- Q,
- R,
- S,
- T,
- U,
- V,
- W,
- X,
- Y,
- Z,
- N1,
- N2,
- N3,
- N4,
- N5,
- N6,
- N7,
- N8,
- N9,
- N0,
- Enter,
- Escape,
- Backspace,
- Tab,
- Space,
- Minus,
- Equal,
- LeftBrace,
- RightBrace,
- Backslash,
- Tilde,
- Semicolon,
- Apostrophe,
- Grave,
- Comma,
- Dot,
- Slash,
- CapsLockKey,
-
- F1,
- F2,
- F3,
- F4,
- F5,
- F6,
- F7,
- F8,
- F9,
- F10,
- F11,
- F12,
-
- SystemRequest,
- ScrollLockKey,
- Pause,
- Insert,
- Home,
- PageUp,
- Delete,
- End,
- PageDown,
- Right,
- Left,
- Down,
- Up,
-
- NumLockKey,
- KPSlash,
- KPAsterisk,
- KPMinus,
- KPPlus,
- KPEnter,
- KP1,
- KP2,
- KP3,
- KP4,
- KP5,
- KP6,
- KP7,
- KP8,
- KP9,
- KP0,
- KPDot,
-
- Key102,
- Compose,
- Power,
- KPEqual,
-
- F13,
- F14,
- F15,
- F16,
- F17,
- F18,
- F19,
- F20,
- F21,
- F22,
- F23,
- F24,
-
- Open,
- Help,
- Properties,
- Front,
- Stop,
- Repeat,
- Undo,
- Cut,
- Copy,
- Paste,
- Find,
- Mute,
- VolumeUp,
- VolumeDown,
- CapsLockActive,
- NumLockActive,
- ScrollLockActive,
- KPComma,
-
- KPLeftParenthesis,
- KPRightParenthesis,
-
- LeftControlKey = 0xE0,
- LeftShiftKey,
- LeftAltKey,
- LeftMetaKey,
- RightControlKey,
- RightShiftKey,
- RightAltKey,
- RightMetaKey,
-
- MediaPlayPause,
- MediaStopCD,
- MediaPrevious,
- MediaNext,
- MediaEject,
- MediaVolumeUp,
- MediaVolumeDown,
- MediaMute,
- MediaWebsite,
- MediaBack,
- MediaForward,
- MediaStop,
- MediaFind,
- MediaScrollUp,
- MediaScrollDown,
- MediaEdit,
- MediaSleep,
- MediaCoffee,
- MediaRefresh,
- MediaCalculator,
-
- NumKeyboardKeys,
-};
-
-static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
-
-enum Modifiers {
- LeftControl,
- LeftShift,
- LeftAlt,
- LeftMeta,
- RightControl,
- RightShift,
- RightAlt,
- RightMeta,
- CapsLock,
- ScrollLock,
- NumLock,
-
- NumKeyboardMods,
-};
-
-constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
-constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
-constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
-
-constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
-constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
-constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
-
-} // namespace NativeKeyboard
-
-using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
-using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
-using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
-using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
-using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
-
-constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
-constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
-constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
-constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
-
-enum class ControllerType {
- ProController,
- DualJoycon,
- RightJoycon,
- LeftJoycon,
-};
-
-struct PlayerInput {
- bool connected;
- ControllerType type;
- ButtonsRaw buttons;
- AnalogsRaw analogs;
-
- u32 body_color_right;
- u32 button_color_right;
- u32 body_color_left;
- u32 button_color_left;
-};
-
-struct TouchscreenInput {
- bool enabled;
- std::string device;
-
- u32 finger;
- u32 diameter_x;
- u32 diameter_y;
- u32 rotation_angle;
-};
-
enum class RendererBackend {
OpenGL = 0,
Vulkan = 1,
@@ -359,7 +29,8 @@ enum class GPUAccuracy : u32 {
enum class CPUAccuracy {
Accurate = 0,
- DebugMode = 1,
+ Unsafe = 1,
+ DebugMode = 2,
};
extern bool configuring_global;
@@ -396,6 +67,11 @@ private:
Type local{};
};
+struct TouchFromButtonMap {
+ std::string name;
+ std::vector<std::string> buttons;
+};
+
struct Values {
// Audio
std::string audio_device_id;
@@ -419,6 +95,9 @@ struct Values {
bool cpuopt_misc_ir;
bool cpuopt_reduce_misalign_checks;
+ bool cpuopt_unsafe_unfuse_fma;
+ bool cpuopt_unsafe_reduce_fp_error;
+
// Renderer
Setting<RendererBackend> renderer_backend;
bool renderer_debug;
@@ -457,6 +136,8 @@ struct Values {
// Controls
std::array<PlayerInput, 10> players;
+ bool use_docked_mode;
+
bool mouse_enabled;
std::string mouse_device;
MouseButtonsRaw mouse_buttons;
@@ -469,14 +150,19 @@ struct Values {
ButtonsRaw debug_pad_buttons;
AnalogsRaw debug_pad_analogs;
+ bool vibration_enabled;
+
+ bool motion_enabled;
std::string motion_device;
+ std::string touch_device;
TouchscreenInput touchscreen;
std::atomic_bool is_device_reload_pending{true};
+ bool use_touch_from_button;
+ int touch_from_button_map_index;
std::string udp_input_address;
u16 udp_input_port;
u8 udp_pad_index;
-
- bool use_docked_mode;
+ std::vector<TouchFromButtonMap> touch_from_button_maps;
// Data Storage
bool use_virtual_sd;
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 317c25bad..7b39a38c1 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -7,6 +7,14 @@ add_library(input_common STATIC
main.h
motion_emu.cpp
motion_emu.h
+ motion_from_button.cpp
+ motion_from_button.h
+ motion_input.cpp
+ motion_input.h
+ settings.cpp
+ settings.h
+ touch_from_button.cpp
+ touch_from_button.h
gcadapter/gc_adapter.cpp
gcadapter/gc_adapter.h
gcadapter/gc_poller.cpp
@@ -21,6 +29,35 @@ add_library(input_common STATIC
udp/udp.h
)
+if (MSVC)
+ target_compile_options(input_common PRIVATE
+ # 'expression' : signed/unsigned mismatch
+ /we4018
+ # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
+ /we4244
+ # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
+ /we4245
+ # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
+ /we4254
+ # 'var' : conversion from 'size_t' to 'type', possible loss of data
+ /we4267
+ # 'context' : truncation from 'type1' to 'type2'
+ /we4305
+ )
+else()
+ target_compile_options(input_common PRIVATE
+ -Werror=conversion
+ -Werror=ignored-qualifiers
+ -Werror=implicit-fallthrough
+ -Werror=reorder
+ -Werror=shadow
+ -Werror=sign-compare
+ -Werror=unused-but-set-parameter
+ -Werror=unused-but-set-variable
+ -Werror=unused-variable
+ )
+endif()
+
if(SDL2_FOUND)
target_sources(input_common PRIVATE
sdl/sdl_impl.cpp
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp
index 6cabdaa3c..74744d7f3 100755
--- a/src/input_common/analog_from_button.cpp
+++ b/src/input_common/analog_from_button.cpp
@@ -20,18 +20,22 @@ public:
constexpr float SQRT_HALF = 0.707106781f;
int x = 0, y = 0;
- if (right->GetStatus())
+ if (right->GetStatus()) {
++x;
- if (left->GetStatus())
+ }
+ if (left->GetStatus()) {
--x;
- if (up->GetStatus())
+ }
+ if (up->GetStatus()) {
++y;
- if (down->GetStatus())
+ }
+ if (down->GetStatus()) {
--y;
+ }
- float coef = modifier->GetStatus() ? modifier_scale : 1.0f;
- return std::make_tuple(x * coef * (y == 0 ? 1.0f : SQRT_HALF),
- y * coef * (x == 0 ? 1.0f : SQRT_HALF));
+ const float coef = modifier->GetStatus() ? modifier_scale : 1.0f;
+ return std::make_tuple(static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF),
+ static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF));
}
bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index 74759ea7d..c95feb0d7 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -4,13 +4,24 @@
#include <chrono>
#include <thread>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4200) // nonstandard extension used : zero-sized array in struct/union
+#endif
#include <libusb.h>
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
#include "common/logging/log.h"
+#include "common/param_package.h"
#include "input_common/gcadapter/gc_adapter.h"
+#include "input_common/settings.h"
namespace GCAdapter {
-/// Used to loop through and assign button in poller
+// Used to loop through and assign button in poller
constexpr std::array<PadButton, 12> PadButtonArray{
PadButton::PAD_BUTTON_LEFT, PadButton::PAD_BUTTON_RIGHT, PadButton::PAD_BUTTON_DOWN,
PadButton::PAD_BUTTON_UP, PadButton::PAD_TRIGGER_Z, PadButton::PAD_TRIGGER_R,
@@ -18,6 +29,18 @@ constexpr std::array<PadButton, 12> PadButtonArray{
PadButton::PAD_BUTTON_X, PadButton::PAD_BUTTON_Y, PadButton::PAD_BUTTON_START,
};
+static void PadToState(const GCPadStatus& pad, GCState& out_state) {
+ for (const auto& button : PadButtonArray) {
+ const auto button_key = static_cast<u16>(button);
+ const auto button_value = (pad.button & button_key) != 0;
+ out_state.buttons.insert_or_assign(static_cast<s32>(button_key), button_value);
+ }
+
+ for (std::size_t i = 0; i < pad.axis_values.size(); ++i) {
+ out_state.axes.insert_or_assign(static_cast<u32>(i), pad.axis_values[i]);
+ }
+}
+
Adapter::Adapter() {
if (usb_adapter_handle != nullptr) {
return;
@@ -67,17 +90,17 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad
for (std::size_t i = 0; i < b1_buttons.size(); ++i) {
if ((b1 & (1U << i)) != 0) {
- pad.button |= static_cast<u16>(b1_buttons[i]);
+ pad.button = static_cast<u16>(pad.button | static_cast<u16>(b1_buttons[i]));
}
}
for (std::size_t j = 0; j < b2_buttons.size(); ++j) {
if ((b2 & (1U << j)) != 0) {
- pad.button |= static_cast<u16>(b2_buttons[j]);
+ pad.button = static_cast<u16>(pad.button | static_cast<u16>(b2_buttons[j]));
}
}
for (PadAxes axis : axes) {
- const std::size_t index = static_cast<std::size_t>(axis);
+ const auto index = static_cast<std::size_t>(axis);
pad.axis_values[index] = adapter_payload[offset + 3 + index];
}
@@ -89,17 +112,6 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad
return pad;
}
-void Adapter::PadToState(const GCPadStatus& pad, GCState& state) {
- for (const auto& button : PadButtonArray) {
- const u16 button_value = static_cast<u16>(button);
- state.buttons.insert_or_assign(button_value, pad.button & button_value);
- }
-
- for (size_t i = 0; i < pad.axis_values.size(); ++i) {
- state.axes.insert_or_assign(static_cast<u8>(i), pad.axis_values[i]);
- }
-}
-
void Adapter::Read() {
LOG_DEBUG(Input, "GC Adapter Read() thread started");
@@ -239,7 +251,7 @@ void Adapter::GetGCEndpoint(libusb_device* device) {
const libusb_interface_descriptor* interface = &interfaceContainer->altsetting[i];
for (u8 e = 0; e < interface->bNumEndpoints; e++) {
const libusb_endpoint_descriptor* endpoint = &interface->endpoint[e];
- if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
+ if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) != 0) {
input_endpoint = endpoint->bEndpointAddress;
} else {
output_endpoint = endpoint->bEndpointAddress;
@@ -283,7 +295,93 @@ void Adapter::Reset() {
}
}
-bool Adapter::DeviceConnected(std::size_t port) {
+std::vector<Common::ParamPackage> Adapter::GetInputDevices() const {
+ std::vector<Common::ParamPackage> devices;
+ for (std::size_t port = 0; port < state.size(); ++port) {
+ if (!DeviceConnected(port)) {
+ continue;
+ }
+ std::string name = fmt::format("Gamecube Controller {}", port);
+ devices.emplace_back(Common::ParamPackage{
+ {"class", "gcpad"},
+ {"display", std::move(name)},
+ {"port", std::to_string(port)},
+ });
+ }
+ return devices;
+}
+
+InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice(
+ const Common::ParamPackage& params) const {
+ // This list is missing ZL/ZR since those are not considered buttons.
+ // We will add those afterwards
+ // This list also excludes any button that can't be really mapped
+ static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 12>
+ switch_to_gcadapter_button = {
+ std::pair{Settings::NativeButton::A, PadButton::PAD_BUTTON_A},
+ {Settings::NativeButton::B, PadButton::PAD_BUTTON_B},
+ {Settings::NativeButton::X, PadButton::PAD_BUTTON_X},
+ {Settings::NativeButton::Y, PadButton::PAD_BUTTON_Y},
+ {Settings::NativeButton::Plus, PadButton::PAD_BUTTON_START},
+ {Settings::NativeButton::DLeft, PadButton::PAD_BUTTON_LEFT},
+ {Settings::NativeButton::DUp, PadButton::PAD_BUTTON_UP},
+ {Settings::NativeButton::DRight, PadButton::PAD_BUTTON_RIGHT},
+ {Settings::NativeButton::DDown, PadButton::PAD_BUTTON_DOWN},
+ {Settings::NativeButton::SL, PadButton::PAD_TRIGGER_L},
+ {Settings::NativeButton::SR, PadButton::PAD_TRIGGER_R},
+ {Settings::NativeButton::R, PadButton::PAD_TRIGGER_Z},
+ };
+ if (!params.Has("port")) {
+ return {};
+ }
+
+ InputCommon::ButtonMapping mapping{};
+ for (const auto& [switch_button, gcadapter_button] : switch_to_gcadapter_button) {
+ Common::ParamPackage button_params({{"engine", "gcpad"}});
+ button_params.Set("port", params.Get("port", 0));
+ button_params.Set("button", static_cast<int>(gcadapter_button));
+ mapping.insert_or_assign(switch_button, std::move(button_params));
+ }
+
+ // Add the missing bindings for ZL/ZR
+ static constexpr std::array<std::pair<Settings::NativeButton::Values, PadAxes>, 2>
+ switch_to_gcadapter_axis = {
+ std::pair{Settings::NativeButton::ZL, PadAxes::TriggerLeft},
+ {Settings::NativeButton::ZR, PadAxes::TriggerRight},
+ };
+ for (const auto& [switch_button, gcadapter_axis] : switch_to_gcadapter_axis) {
+ Common::ParamPackage button_params({{"engine", "gcpad"}});
+ button_params.Set("port", params.Get("port", 0));
+ button_params.Set("button", static_cast<int>(PadButton::PAD_STICK));
+ button_params.Set("axis", static_cast<int>(gcadapter_axis));
+ mapping.insert_or_assign(switch_button, std::move(button_params));
+ }
+ return mapping;
+}
+
+InputCommon::AnalogMapping Adapter::GetAnalogMappingForDevice(
+ const Common::ParamPackage& params) const {
+ if (!params.Has("port")) {
+ return {};
+ }
+
+ InputCommon::AnalogMapping mapping = {};
+ Common::ParamPackage left_analog_params;
+ left_analog_params.Set("engine", "gcpad");
+ left_analog_params.Set("port", params.Get("port", 0));
+ left_analog_params.Set("axis_x", static_cast<int>(PadAxes::StickX));
+ left_analog_params.Set("axis_y", static_cast<int>(PadAxes::StickY));
+ mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params));
+ Common::ParamPackage right_analog_params;
+ right_analog_params.Set("engine", "gcpad");
+ right_analog_params.Set("port", params.Get("port", 0));
+ right_analog_params.Set("axis_x", static_cast<int>(PadAxes::SubstickX));
+ right_analog_params.Set("axis_y", static_cast<int>(PadAxes::SubstickY));
+ mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params));
+ return mapping;
+}
+
+bool Adapter::DeviceConnected(std::size_t port) const {
return adapter_controllers_status[port] != ControllerTypes::None;
}
@@ -322,7 +420,7 @@ const std::array<GCState, 4>& Adapter::GetPadState() const {
return state;
}
-int Adapter::GetOriginValue(int port, int axis) const {
+int Adapter::GetOriginValue(u32 port, u32 axis) const {
return origin_status[port].axis_values[axis];
}
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
index bed81915c..4f5f3de8e 100644
--- a/src/input_common/gcadapter/gc_adapter.h
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -10,6 +10,7 @@
#include <unordered_map>
#include "common/common_types.h"
#include "common/threadsafe_queue.h"
+#include "input_common/main.h"
struct libusb_context;
struct libusb_device;
@@ -59,7 +60,7 @@ struct GCPadStatus {
struct GCState {
std::unordered_map<int, bool> buttons;
- std::unordered_map<int, u16> axes;
+ std::unordered_map<u32, u16> axes;
};
enum class ControllerTypes { None, Wired, Wireless };
@@ -75,8 +76,12 @@ public:
void BeginConfiguration();
void EndConfiguration();
+ std::vector<Common::ParamPackage> GetInputDevices() const;
+ InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const;
+ InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const;
+
/// Returns true if there is a device connected to port
- bool DeviceConnected(std::size_t port);
+ bool DeviceConnected(std::size_t port) const;
std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue();
const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const;
@@ -84,13 +89,11 @@ public:
std::array<GCState, 4>& GetPadState();
const std::array<GCState, 4>& GetPadState() const;
- int GetOriginValue(int port, int axis) const;
+ int GetOriginValue(u32 port, u32 axis) const;
private:
GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload);
- void PadToState(const GCPadStatus& pad, GCState& state);
-
void Read();
/// Resets status of device connected to port
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index b346fdf8e..893556916 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -15,7 +15,7 @@ namespace InputCommon {
class GCButton final : public Input::ButtonDevice {
public:
- explicit GCButton(int port_, int button_, GCAdapter::Adapter* adapter)
+ explicit GCButton(u32 port_, int button_, const GCAdapter::Adapter* adapter)
: port(port_), button(button_), gcadapter(adapter) {}
~GCButton() override;
@@ -28,17 +28,18 @@ public:
}
private:
- const int port;
+ const u32 port;
const int button;
- GCAdapter::Adapter* gcadapter;
+ const GCAdapter::Adapter* gcadapter;
};
class GCAxisButton final : public Input::ButtonDevice {
public:
- explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_,
- GCAdapter::Adapter* adapter)
+ explicit GCAxisButton(u32 port_, u32 axis_, float threshold_, bool trigger_if_greater_,
+ const GCAdapter::Adapter* adapter)
: port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_),
- gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {}
+ gcadapter(adapter),
+ origin_value(static_cast<float>(adapter->GetOriginValue(port_, axis_))) {}
bool GetStatus() const override {
if (gcadapter->DeviceConnected(port)) {
@@ -55,11 +56,11 @@ public:
}
private:
- const int port;
- const int axis;
+ const u32 port;
+ const u32 axis;
float threshold;
bool trigger_if_greater;
- GCAdapter::Adapter* gcadapter;
+ const GCAdapter::Adapter* gcadapter;
const float origin_value;
};
@@ -69,8 +70,8 @@ GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
GCButton::~GCButton() = default;
std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::ParamPackage& params) {
- const int button_id = params.Get("button", 0);
- const int port = params.Get("port", 0);
+ const auto button_id = params.Get("button", 0);
+ const auto port = static_cast<u32>(params.Get("port", 0));
constexpr int PAD_STICK_ID = static_cast<u16>(GCAdapter::PadButton::PAD_STICK);
@@ -148,24 +149,27 @@ void GCButtonFactory::EndConfiguration() {
class GCAnalog final : public Input::AnalogDevice {
public:
- GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter,
- float range_)
+ explicit GCAnalog(u32 port_, u32 axis_x_, u32 axis_y_, float deadzone_,
+ const GCAdapter::Adapter* adapter, float range_)
: port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
- origin_value_x(adapter->GetOriginValue(port_, axis_x_)),
- origin_value_y(adapter->GetOriginValue(port_, axis_y_)), range(range_) {}
+ origin_value_x(static_cast<float>(adapter->GetOriginValue(port_, axis_x_))),
+ origin_value_y(static_cast<float>(adapter->GetOriginValue(port_, axis_y_))),
+ range(range_) {}
- float GetAxis(int axis) const {
+ float GetAxis(u32 axis) const {
if (gcadapter->DeviceConnected(port)) {
std::lock_guard lock{mutex};
const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
- return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / (100.0f * range);
+ const auto axis_value =
+ static_cast<float>(gcadapter->GetPadState()[port].axes.at(axis));
+ return (axis_value - origin_value) / (100.0f * range);
}
return 0.0f;
}
- std::pair<float, float> GetAnalog(int axis_x, int axis_y) const {
- float x = GetAxis(axis_x);
- float y = GetAxis(axis_y);
+ std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
+ float x = GetAxis(analog_axis_x);
+ float y = GetAxis(analog_axis_y);
// Make sure the coordinates are in the unit circle,
// otherwise normalize it.
@@ -191,7 +195,7 @@ public:
bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
const auto [x, y] = GetStatus();
- const float directional_deadzone = 0.4f;
+ const float directional_deadzone = 0.5f;
switch (direction) {
case Input::AnalogDirection::RIGHT:
return x > directional_deadzone;
@@ -206,11 +210,11 @@ public:
}
private:
- const int port;
- const int axis_x;
- const int axis_y;
+ const u32 port;
+ const u32 axis_x;
+ const u32 axis_y;
const float deadzone;
- GCAdapter::Adapter* gcadapter;
+ const GCAdapter::Adapter* gcadapter;
const float origin_value_x;
const float origin_value_y;
const float range;
@@ -229,11 +233,11 @@ GCAnalogFactory::GCAnalogFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
* - "axis_y": the index of the axis to be bind as y-axis
*/
std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::ParamPackage& params) {
- const int port = params.Get("port", 0);
- const int axis_x = params.Get("axis_x", 0);
- const int axis_y = params.Get("axis_y", 1);
- const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
- const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
+ const auto port = static_cast<u32>(params.Get("port", 0));
+ const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
+ const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
+ const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
+ const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
}
@@ -254,7 +258,7 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() {
for (std::size_t port = 0; port < queue.size(); ++port) {
while (queue[port].Pop(pad)) {
if (pad.axis == GCAdapter::PadAxes::Undefined ||
- std::abs((pad.axis_value - 128.0f) / 128.0f) < 0.1) {
+ std::abs((static_cast<float>(pad.axis_value) - 128.0f) / 128.0f) < 0.1f) {
continue;
}
// An analog device needs two axes, so we need to store the axis for later and wait for
diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp
index afb8e6612..24a6f7a33 100644
--- a/src/input_common/keyboard.cpp
+++ b/src/input_common/keyboard.cpp
@@ -49,8 +49,9 @@ public:
void ChangeKeyStatus(int key_code, bool pressed) {
std::lock_guard guard{mutex};
for (const KeyButtonPair& pair : list) {
- if (pair.key_code == key_code)
+ if (pair.key_code == key_code) {
pair.key_button->status.store(pressed);
+ }
}
}
@@ -73,7 +74,7 @@ KeyButton::~KeyButton() {
}
std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) {
- int key_code = params.Get("code", 0);
+ const int key_code = params.Get("code", 0);
std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list);
key_button_list->AddKeyButton(key_code, button.get());
return button;
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index b9d5d0ec3..d32fd8b81 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -11,6 +11,9 @@
#include "input_common/keyboard.h"
#include "input_common/main.h"
#include "input_common/motion_emu.h"
+#include "input_common/motion_from_button.h"
+#include "input_common/touch_from_button.h"
+#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
#ifdef HAVE_SDL2
#include "input_common/sdl/sdl.h"
@@ -18,67 +21,231 @@
namespace InputCommon {
-static std::shared_ptr<Keyboard> keyboard;
-static std::shared_ptr<MotionEmu> motion_emu;
+struct InputSubsystem::Impl {
+ void Initialize() {
+ gcadapter = std::make_shared<GCAdapter::Adapter>();
+ gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
+ Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
+ gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
+ Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
+
+ keyboard = std::make_shared<Keyboard>();
+ Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
+ Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
+ std::make_shared<AnalogFromButton>());
+ Input::RegisterFactory<Input::MotionDevice>("keyboard",
+ std::make_shared<MotionFromButton>());
+ motion_emu = std::make_shared<MotionEmu>();
+ Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
+ Input::RegisterFactory<Input::TouchDevice>("touch_from_button",
+ std::make_shared<TouchFromButtonFactory>());
+
#ifdef HAVE_SDL2
-static std::unique_ptr<SDL::State> sdl;
+ sdl = SDL::Init();
#endif
-static std::unique_ptr<CemuhookUDP::State> udp;
-static std::shared_ptr<GCButtonFactory> gcbuttons;
-static std::shared_ptr<GCAnalogFactory> gcanalog;
-
-void Init() {
- auto gcadapter = std::make_shared<GCAdapter::Adapter>();
- gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
- Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
- gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
- Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
-
- keyboard = std::make_shared<Keyboard>();
- Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
- Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
- std::make_shared<AnalogFromButton>());
- motion_emu = std::make_shared<MotionEmu>();
- Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
+ udp = std::make_shared<InputCommon::CemuhookUDP::Client>();
+ udpmotion = std::make_shared<UDPMotionFactory>(udp);
+ Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", udpmotion);
+ udptouch = std::make_shared<UDPTouchFactory>(udp);
+ Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", udptouch);
+ }
+
+ void Shutdown() {
+ Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
+ Input::UnregisterFactory<Input::MotionDevice>("keyboard");
+ keyboard.reset();
+ Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
+ Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
+ motion_emu.reset();
+ Input::UnregisterFactory<Input::TouchDevice>("touch_from_button");
#ifdef HAVE_SDL2
- sdl = SDL::Init();
+ sdl.reset();
#endif
+ Input::UnregisterFactory<Input::ButtonDevice>("gcpad");
+ Input::UnregisterFactory<Input::AnalogDevice>("gcpad");
- udp = CemuhookUDP::Init();
-}
+ gcbuttons.reset();
+ gcanalog.reset();
-void Shutdown() {
- Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
- keyboard.reset();
- Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
- Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
- motion_emu.reset();
+ Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
+ Input::UnregisterFactory<Input::TouchDevice>("cemuhookudp");
+
+ udpmotion.reset();
+ udptouch.reset();
+ }
+
+ [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
+ std::vector<Common::ParamPackage> devices = {
+ Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
+ Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
+ };
#ifdef HAVE_SDL2
- sdl.reset();
+ auto sdl_devices = sdl->GetInputDevices();
+ devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
#endif
- udp.reset();
- Input::UnregisterFactory<Input::ButtonDevice>("gcpad");
- Input::UnregisterFactory<Input::AnalogDevice>("gcpad");
+ auto udp_devices = udp->GetInputDevices();
+ devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
+ auto gcpad_devices = gcadapter->GetInputDevices();
+ devices.insert(devices.end(), gcpad_devices.begin(), gcpad_devices.end());
+ return devices;
+ }
+
+ [[nodiscard]] AnalogMapping GetAnalogMappingForDevice(
+ const Common::ParamPackage& params) const {
+ if (!params.Has("class") || params.Get("class", "") == "any") {
+ return {};
+ }
+ if (params.Get("class", "") == "key") {
+ // TODO consider returning the SDL key codes for the default keybindings
+ return {};
+ }
+ if (params.Get("class", "") == "gcpad") {
+ return gcadapter->GetAnalogMappingForDevice(params);
+ }
+#ifdef HAVE_SDL2
+ if (params.Get("class", "") == "sdl") {
+ return sdl->GetAnalogMappingForDevice(params);
+ }
+#endif
+ return {};
+ }
+
+ [[nodiscard]] ButtonMapping GetButtonMappingForDevice(
+ const Common::ParamPackage& params) const {
+ if (!params.Has("class") || params.Get("class", "") == "any") {
+ return {};
+ }
+ if (params.Get("class", "") == "key") {
+ // TODO consider returning the SDL key codes for the default keybindings
+ return {};
+ }
+ if (params.Get("class", "") == "gcpad") {
+ return gcadapter->GetButtonMappingForDevice(params);
+ }
+#ifdef HAVE_SDL2
+ if (params.Get("class", "") == "sdl") {
+ return sdl->GetButtonMappingForDevice(params);
+ }
+#endif
+ return {};
+ }
+
+ [[nodiscard]] MotionMapping GetMotionMappingForDevice(
+ const Common::ParamPackage& params) const {
+ if (!params.Has("class") || params.Get("class", "") == "any") {
+ return {};
+ }
+ if (params.Get("class", "") == "cemuhookudp") {
+ // TODO return the correct motion device
+ return {};
+ }
+ return {};
+ }
+
+ std::shared_ptr<Keyboard> keyboard;
+ std::shared_ptr<MotionEmu> motion_emu;
+#ifdef HAVE_SDL2
+ std::unique_ptr<SDL::State> sdl;
+#endif
+ std::shared_ptr<GCButtonFactory> gcbuttons;
+ std::shared_ptr<GCAnalogFactory> gcanalog;
+ std::shared_ptr<UDPMotionFactory> udpmotion;
+ std::shared_ptr<UDPTouchFactory> udptouch;
+ std::shared_ptr<CemuhookUDP::Client> udp;
+ std::shared_ptr<GCAdapter::Adapter> gcadapter;
+};
+
+InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {}
+
+InputSubsystem::~InputSubsystem() = default;
+
+void InputSubsystem::Initialize() {
+ impl->Initialize();
+}
+
+void InputSubsystem::Shutdown() {
+ impl->Shutdown();
+}
+
+Keyboard* InputSubsystem::GetKeyboard() {
+ return impl->keyboard.get();
+}
+
+const Keyboard* InputSubsystem::GetKeyboard() const {
+ return impl->keyboard.get();
+}
+
+MotionEmu* InputSubsystem::GetMotionEmu() {
+ return impl->motion_emu.get();
+}
+
+const MotionEmu* InputSubsystem::GetMotionEmu() const {
+ return impl->motion_emu.get();
+}
+
+std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
+ return impl->GetInputDevices();
+}
+
+AnalogMapping InputSubsystem::GetAnalogMappingForDevice(const Common::ParamPackage& device) const {
+ return impl->GetAnalogMappingForDevice(device);
+}
+
+ButtonMapping InputSubsystem::GetButtonMappingForDevice(const Common::ParamPackage& device) const {
+ return impl->GetButtonMappingForDevice(device);
+}
+
+MotionMapping InputSubsystem::GetMotionMappingForDevice(const Common::ParamPackage& device) const {
+ return impl->GetMotionMappingForDevice(device);
+}
+
+GCAnalogFactory* InputSubsystem::GetGCAnalogs() {
+ return impl->gcanalog.get();
+}
+
+const GCAnalogFactory* InputSubsystem::GetGCAnalogs() const {
+ return impl->gcanalog.get();
+}
+
+GCButtonFactory* InputSubsystem::GetGCButtons() {
+ return impl->gcbuttons.get();
+}
- gcbuttons.reset();
- gcanalog.reset();
+const GCButtonFactory* InputSubsystem::GetGCButtons() const {
+ return impl->gcbuttons.get();
}
-Keyboard* GetKeyboard() {
- return keyboard.get();
+UDPMotionFactory* InputSubsystem::GetUDPMotions() {
+ return impl->udpmotion.get();
}
-MotionEmu* GetMotionEmu() {
- return motion_emu.get();
+const UDPMotionFactory* InputSubsystem::GetUDPMotions() const {
+ return impl->udpmotion.get();
}
-GCButtonFactory* GetGCButtons() {
- return gcbuttons.get();
+UDPTouchFactory* InputSubsystem::GetUDPTouch() {
+ return impl->udptouch.get();
}
-GCAnalogFactory* GetGCAnalogs() {
- return gcanalog.get();
+const UDPTouchFactory* InputSubsystem::GetUDPTouch() const {
+ return impl->udptouch.get();
+}
+
+void InputSubsystem::ReloadInputDevices() {
+ if (!impl->udp) {
+ return;
+ }
+ impl->udp->ReloadUDPClient();
+}
+
+std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
+ Polling::DeviceType type) const {
+#ifdef HAVE_SDL2
+ return impl->sdl->GetPollers(type);
+#else
+ return {};
+#endif
}
std::string GenerateKeyboardParam(int key_code) {
@@ -102,18 +269,4 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
};
return circle_pad_param.Serialize();
}
-
-namespace Polling {
-
-std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
- std::vector<std::unique_ptr<DevicePoller>> pollers;
-
-#ifdef HAVE_SDL2
- pollers = sdl->GetPollers(type);
-#endif
-
- return pollers;
-}
-
-} // namespace Polling
} // namespace InputCommon
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 0e32856f6..dded3f1ef 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -6,45 +6,29 @@
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
-#include "input_common/gcadapter/gc_poller.h"
namespace Common {
class ParamPackage;
}
-namespace InputCommon {
-
-/// Initializes and registers all built-in input device factories.
-void Init();
-
-/// Deregisters all built-in input device factories and shuts them down.
-void Shutdown();
-
-class Keyboard;
-
-/// Gets the keyboard button device factory.
-Keyboard* GetKeyboard();
-
-class MotionEmu;
-
-/// Gets the motion emulation factory.
-MotionEmu* GetMotionEmu();
-
-GCButtonFactory* GetGCButtons();
-
-GCAnalogFactory* GetGCAnalogs();
+namespace Settings::NativeAnalog {
+enum Values : int;
+}
-/// Generates a serialized param package for creating a keyboard button device
-std::string GenerateKeyboardParam(int key_code);
+namespace Settings::NativeButton {
+enum Values : int;
+}
-/// Generates a serialized param package for creating an analog device taking input from keyboard
-std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
- int key_modifier, float modifier_scale);
+namespace Settings::NativeMotion {
+enum Values : int;
+}
+namespace InputCommon {
namespace Polling {
-enum class DeviceType { Button, Analog };
+enum class DeviceType { Button, AnalogPreferred, Motion };
/**
* A class that can be used to get inputs from an input device like controllers without having to
@@ -54,7 +38,9 @@ class DevicePoller {
public:
virtual ~DevicePoller() = default;
/// Setup and start polling for inputs, should be called before GetNextInput
- virtual void Start() = 0;
+ /// If a device_id is provided, events should be filtered to only include events from this
+ /// device id
+ virtual void Start(const std::string& device_id = "") = 0;
/// Stop polling
virtual void Stop() = 0;
/**
@@ -64,8 +50,110 @@ public:
*/
virtual Common::ParamPackage GetNextInput() = 0;
};
-
-// Get all DevicePoller from all backends for a specific device type
-std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type);
} // namespace Polling
+
+class GCAnalogFactory;
+class GCButtonFactory;
+class UDPMotionFactory;
+class UDPTouchFactory;
+class Keyboard;
+class MotionEmu;
+
+/**
+ * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
+ * mapping for the device. This is currently only implemented for the SDL backend devices.
+ */
+using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
+using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
+using MotionMapping = std::unordered_map<Settings::NativeMotion::Values, Common::ParamPackage>;
+
+class InputSubsystem {
+public:
+ explicit InputSubsystem();
+ ~InputSubsystem();
+
+ InputSubsystem(const InputSubsystem&) = delete;
+ InputSubsystem& operator=(const InputSubsystem&) = delete;
+
+ InputSubsystem(InputSubsystem&&) = delete;
+ InputSubsystem& operator=(InputSubsystem&&) = delete;
+
+ /// Initializes and registers all built-in input device factories.
+ void Initialize();
+
+ /// Unregisters all built-in input device factories and shuts them down.
+ void Shutdown();
+
+ /// Retrieves the underlying keyboard device.
+ [[nodiscard]] Keyboard* GetKeyboard();
+
+ /// Retrieves the underlying keyboard device.
+ [[nodiscard]] const Keyboard* GetKeyboard() const;
+
+ /// Retrieves the underlying motion emulation factory.
+ [[nodiscard]] MotionEmu* GetMotionEmu();
+
+ /// Retrieves the underlying motion emulation factory.
+ [[nodiscard]] const MotionEmu* GetMotionEmu() const;
+
+ /**
+ * Returns all available input devices that this Factory can create a new device with.
+ * Each returned ParamPackage should have a `display` field used for display, a class field for
+ * backends to determine if this backend is meant to service the request and any other
+ * information needed to identify this in the backend later.
+ */
+ [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const;
+
+ /// Retrieves the analog mappings for the given device.
+ [[nodiscard]] AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& device) const;
+
+ /// Retrieves the button mappings for the given device.
+ [[nodiscard]] ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& device) const;
+
+ /// Retrieves the motion mappings for the given device.
+ [[nodiscard]] MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& device) const;
+
+ /// Retrieves the underlying GameCube analog handler.
+ [[nodiscard]] GCAnalogFactory* GetGCAnalogs();
+
+ /// Retrieves the underlying GameCube analog handler.
+ [[nodiscard]] const GCAnalogFactory* GetGCAnalogs() const;
+
+ /// Retrieves the underlying GameCube button handler.
+ [[nodiscard]] GCButtonFactory* GetGCButtons();
+
+ /// Retrieves the underlying GameCube button handler.
+ [[nodiscard]] const GCButtonFactory* GetGCButtons() const;
+
+ /// Retrieves the underlying udp motion handler.
+ [[nodiscard]] UDPMotionFactory* GetUDPMotions();
+
+ /// Retrieves the underlying udp motion handler.
+ [[nodiscard]] const UDPMotionFactory* GetUDPMotions() const;
+
+ /// Retrieves the underlying udp touch handler.
+ [[nodiscard]] UDPTouchFactory* GetUDPTouch();
+
+ /// Retrieves the underlying udp touch handler.
+ [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const;
+
+ /// Reloads the input devices
+ void ReloadInputDevices();
+
+ /// Get all DevicePoller from all backends for a specific device type
+ [[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers(
+ Polling::DeviceType type) const;
+
+private:
+ struct Impl;
+ std::unique_ptr<Impl> impl;
+};
+
+/// Generates a serialized param package for creating a keyboard button device
+std::string GenerateKeyboardParam(int key_code);
+
+/// Generates a serialized param package for creating an analog device taking input from keyboard
+std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
+ int key_modifier, float modifier_scale);
+
} // namespace InputCommon
diff --git a/src/input_common/motion_emu.cpp b/src/input_common/motion_emu.cpp
index d4cdf76a3..d4da5596b 100644
--- a/src/input_common/motion_emu.cpp
+++ b/src/input_common/motion_emu.cpp
@@ -18,11 +18,11 @@ namespace InputCommon {
// Implementation class of the motion emulation device
class MotionEmuDevice {
public:
- MotionEmuDevice(int update_millisecond, float sensitivity)
- : update_millisecond(update_millisecond),
+ explicit MotionEmuDevice(int update_millisecond_, float sensitivity_)
+ : update_millisecond(update_millisecond_),
update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>(
std::chrono::milliseconds(update_millisecond))),
- sensitivity(sensitivity), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {}
+ sensitivity(sensitivity_), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {}
~MotionEmuDevice() {
if (motion_emu_thread.joinable()) {
@@ -37,16 +37,18 @@ public:
}
void Tilt(int x, int y) {
- auto mouse_move = Common::MakeVec(x, y) - mouse_origin;
- if (is_tilting) {
- std::lock_guard guard{tilt_mutex};
- if (mouse_move.x == 0 && mouse_move.y == 0) {
- tilt_angle = 0;
- } else {
- tilt_direction = mouse_move.Cast<float>();
- tilt_angle =
- std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f, Common::PI * 0.5f);
- }
+ if (!is_tilting) {
+ return;
+ }
+
+ std::lock_guard guard{tilt_mutex};
+ const auto mouse_move = Common::MakeVec(x, y) - mouse_origin;
+ if (mouse_move.x == 0 && mouse_move.y == 0) {
+ tilt_angle = 0;
+ } else {
+ tilt_direction = mouse_move.Cast<float>();
+ tilt_angle =
+ std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f, Common::PI * 0.5f);
}
}
@@ -56,7 +58,7 @@ public:
is_tilting = false;
}
- std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() {
+ Input::MotionStatus GetStatus() {
std::lock_guard guard{status_mutex};
return status;
}
@@ -76,7 +78,7 @@ private:
Common::Event shutdown_event;
- std::tuple<Common::Vec3<float>, Common::Vec3<float>> status;
+ Input::MotionStatus status;
std::mutex status_mutex;
// Note: always keep the thread declaration at the end so that other objects are initialized
@@ -86,11 +88,10 @@ private:
void MotionEmuThread() {
auto update_time = std::chrono::steady_clock::now();
Common::Quaternion<float> q = Common::MakeQuaternion(Common::Vec3<float>(), 0);
- Common::Quaternion<float> old_q;
while (!shutdown_event.WaitUntil(update_time)) {
update_time += update_duration;
- old_q = q;
+ const Common::Quaternion<float> old_q = q;
{
std::lock_guard guard{tilt_mutex};
@@ -100,23 +101,32 @@ private:
Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle);
}
- auto inv_q = q.Inverse();
+ const auto inv_q = q.Inverse();
// Set the gravity vector in world space
auto gravity = Common::MakeVec(0.0f, -1.0f, 0.0f);
// Find the angular rate vector in world space
auto angular_rate = ((q - old_q) * inv_q).xyz * 2;
- angular_rate *= 1000 / update_millisecond / Common::PI * 180;
+ angular_rate *= static_cast<float>(1000 / update_millisecond) / Common::PI * 180.0f;
// Transform the two vectors from world space to 3DS space
gravity = QuaternionRotate(inv_q, gravity);
angular_rate = QuaternionRotate(inv_q, angular_rate);
+ // TODO: Calculate the correct rotation vector and orientation matrix
+ const auto matrix4x4 = q.ToMatrix();
+ const auto rotation = Common::MakeVec(0.0f, 0.0f, 0.0f);
+ const std::array orientation{
+ Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]),
+ Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]),
+ Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10]),
+ };
+
// Update the sensor state
{
std::lock_guard guard{status_mutex};
- status = std::make_tuple(gravity, angular_rate);
+ status = std::make_tuple(gravity, angular_rate, rotation, orientation);
}
}
}
@@ -127,11 +137,11 @@ private:
// can forward all the inputs to the implementation only when it is valid.
class MotionEmuDeviceWrapper : public Input::MotionDevice {
public:
- MotionEmuDeviceWrapper(int update_millisecond, float sensitivity) {
+ explicit MotionEmuDeviceWrapper(int update_millisecond, float sensitivity) {
device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity);
}
- std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const override {
+ Input::MotionStatus GetStatus() const override {
return device->GetStatus();
}
@@ -139,8 +149,8 @@ public:
};
std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackage& params) {
- int update_period = params.Get("update_period", 100);
- float sensitivity = params.Get("sensitivity", 0.01f);
+ const int update_period = params.Get("update_period", 100);
+ const float sensitivity = params.Get("sensitivity", 0.01f);
auto device_wrapper = std::make_unique<MotionEmuDeviceWrapper>(update_period, sensitivity);
// Previously created device is disconnected here. Having two motion devices for 3DS is not
// expected.
diff --git a/src/input_common/motion_from_button.cpp b/src/input_common/motion_from_button.cpp
new file mode 100644
index 000000000..29045a673
--- /dev/null
+++ b/src/input_common/motion_from_button.cpp
@@ -0,0 +1,34 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "input_common/motion_from_button.h"
+#include "input_common/motion_input.h"
+
+namespace InputCommon {
+
+class MotionKey final : public Input::MotionDevice {
+public:
+ using Button = std::unique_ptr<Input::ButtonDevice>;
+
+ explicit MotionKey(Button key_) : key(std::move(key_)) {}
+
+ Input::MotionStatus GetStatus() const override {
+
+ if (key->GetStatus()) {
+ return motion.GetRandomMotion(2, 6);
+ }
+ return motion.GetRandomMotion(0, 0);
+ }
+
+private:
+ Button key;
+ InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
+};
+
+std::unique_ptr<Input::MotionDevice> MotionFromButton::Create(const Common::ParamPackage& params) {
+ auto key = Input::CreateDevice<Input::ButtonDevice>(params.Serialize());
+ return std::make_unique<MotionKey>(std::move(key));
+}
+
+} // namespace InputCommon
diff --git a/src/input_common/motion_from_button.h b/src/input_common/motion_from_button.h
new file mode 100644
index 000000000..a959046fb
--- /dev/null
+++ b/src/input_common/motion_from_button.h
@@ -0,0 +1,25 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/frontend/input.h"
+
+namespace InputCommon {
+
+/**
+ * An motion device factory that takes a keyboard button and uses it as a random
+ * motion device.
+ */
+class MotionFromButton final : public Input::Factory<Input::MotionDevice> {
+public:
+ /**
+ * Creates an motion device from button devices
+ * @param params contains parameters for creating the device:
+ * - "key": a serialized ParamPackage for creating a button device
+ */
+ std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override;
+};
+
+} // namespace InputCommon
diff --git a/src/input_common/motion_input.cpp b/src/input_common/motion_input.cpp
new file mode 100644
index 000000000..f77ba535d
--- /dev/null
+++ b/src/input_common/motion_input.cpp
@@ -0,0 +1,301 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#include <random>
+#include "common/math_util.h"
+#include "input_common/motion_input.h"
+
+namespace InputCommon {
+
+MotionInput::MotionInput(f32 new_kp, f32 new_ki, f32 new_kd) : kp(new_kp), ki(new_ki), kd(new_kd) {}
+
+void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
+ accel = acceleration;
+}
+
+void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
+ gyro = gyroscope - gyro_drift;
+
+ // Auto adjust drift to minimize drift
+ if (!IsMoving(0.1f)) {
+ gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f);
+ }
+
+ if (gyro.Length2() < gyro_threshold) {
+ gyro = {};
+ } else {
+ only_accelerometer = false;
+ }
+}
+
+void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
+ quat = quaternion;
+}
+
+void MotionInput::SetGyroDrift(const Common::Vec3f& drift) {
+ gyro_drift = drift;
+}
+
+void MotionInput::SetGyroThreshold(f32 threshold) {
+ gyro_threshold = threshold;
+}
+
+void MotionInput::EnableReset(bool reset) {
+ reset_enabled = reset;
+}
+
+void MotionInput::ResetRotations() {
+ rotations = {};
+}
+
+bool MotionInput::IsMoving(f32 sensitivity) const {
+ return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f;
+}
+
+bool MotionInput::IsCalibrated(f32 sensitivity) const {
+ return real_error.Length() < sensitivity;
+}
+
+void MotionInput::UpdateRotation(u64 elapsed_time) {
+ const auto sample_period = static_cast<f32>(elapsed_time) / 1000000.0f;
+ if (sample_period > 0.1f) {
+ return;
+ }
+ rotations += gyro * sample_period;
+}
+
+void MotionInput::UpdateOrientation(u64 elapsed_time) {
+ if (!IsCalibrated(0.1f)) {
+ ResetOrientation();
+ }
+ // Short name local variable for readability
+ f32 q1 = quat.w;
+ f32 q2 = quat.xyz[0];
+ f32 q3 = quat.xyz[1];
+ f32 q4 = quat.xyz[2];
+ const auto sample_period = static_cast<f32>(elapsed_time) / 1000000.0f;
+
+ // Ignore invalid elapsed time
+ if (sample_period > 0.1f) {
+ return;
+ }
+
+ const auto normal_accel = accel.Normalized();
+ auto rad_gyro = gyro * Common::PI * 2;
+ const f32 swap = rad_gyro.x;
+ rad_gyro.x = rad_gyro.y;
+ rad_gyro.y = -swap;
+ rad_gyro.z = -rad_gyro.z;
+
+ // Clear gyro values if there is no gyro present
+ if (only_accelerometer) {
+ rad_gyro.x = 0;
+ rad_gyro.y = 0;
+ rad_gyro.z = 0;
+ }
+
+ // Ignore drift correction if acceleration is not reliable
+ if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) {
+ const f32 ax = -normal_accel.x;
+ const f32 ay = normal_accel.y;
+ const f32 az = -normal_accel.z;
+
+ // Estimated direction of gravity
+ const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
+ const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
+ const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
+
+ // Error is cross product between estimated direction and measured direction of gravity
+ const Common::Vec3f new_real_error = {
+ az * vx - ax * vz,
+ ay * vz - az * vy,
+ ax * vy - ay * vx,
+ };
+
+ derivative_error = new_real_error - real_error;
+ real_error = new_real_error;
+
+ // Prevent integral windup
+ if (ki != 0.0f && !IsCalibrated(0.05f)) {
+ integral_error += real_error;
+ } else {
+ integral_error = {};
+ }
+
+ // Apply feedback terms
+ if (!only_accelerometer) {
+ rad_gyro += kp * real_error;
+ rad_gyro += ki * integral_error;
+ rad_gyro += kd * derivative_error;
+ } else {
+ // Give more weight to acelerometer values to compensate for the lack of gyro
+ rad_gyro += 35.0f * kp * real_error;
+ rad_gyro += 10.0f * ki * integral_error;
+ rad_gyro += 10.0f * kd * derivative_error;
+
+ // Emulate gyro values for games that need them
+ gyro.x = -rad_gyro.y;
+ gyro.y = rad_gyro.x;
+ gyro.z = -rad_gyro.z;
+ UpdateRotation(elapsed_time);
+ }
+ }
+
+ const f32 gx = rad_gyro.y;
+ const f32 gy = rad_gyro.x;
+ const f32 gz = rad_gyro.z;
+
+ // Integrate rate of change of quaternion
+ const f32 pa = q2;
+ const f32 pb = q3;
+ const f32 pc = q4;
+ q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
+ q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
+ q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
+ q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
+
+ quat.w = q1;
+ quat.xyz[0] = q2;
+ quat.xyz[1] = q3;
+ quat.xyz[2] = q4;
+ quat = quat.Normalized();
+}
+
+std::array<Common::Vec3f, 3> MotionInput::GetOrientation() const {
+ const Common::Quaternion<float> quad{
+ .xyz = {-quat.xyz[1], -quat.xyz[0], -quat.w},
+ .w = -quat.xyz[2],
+ };
+ const std::array<float, 16> matrix4x4 = quad.ToMatrix();
+
+ return {Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]),
+ Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]),
+ Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10])};
+}
+
+Common::Vec3f MotionInput::GetAcceleration() const {
+ return accel;
+}
+
+Common::Vec3f MotionInput::GetGyroscope() const {
+ return gyro;
+}
+
+Common::Quaternion<f32> MotionInput::GetQuaternion() const {
+ return quat;
+}
+
+Common::Vec3f MotionInput::GetRotations() const {
+ return rotations;
+}
+
+Input::MotionStatus MotionInput::GetMotion() const {
+ const Common::Vec3f gyroscope = GetGyroscope();
+ const Common::Vec3f accelerometer = GetAcceleration();
+ const Common::Vec3f rotation = GetRotations();
+ const std::array<Common::Vec3f, 3> orientation = GetOrientation();
+ return {accelerometer, gyroscope, rotation, orientation};
+}
+
+Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_magnitude) const {
+ std::random_device device;
+ std::mt19937 gen(device());
+ std::uniform_int_distribution<s16> distribution(-1000, 1000);
+ const Common::Vec3f gyroscope{
+ static_cast<f32>(distribution(gen)) * 0.001f,
+ static_cast<f32>(distribution(gen)) * 0.001f,
+ static_cast<f32>(distribution(gen)) * 0.001f,
+ };
+ const Common::Vec3f accelerometer{
+ static_cast<f32>(distribution(gen)) * 0.001f,
+ static_cast<f32>(distribution(gen)) * 0.001f,
+ static_cast<f32>(distribution(gen)) * 0.001f,
+ };
+ constexpr Common::Vec3f rotation;
+ constexpr std::array orientation{
+ Common::Vec3f{1.0f, 0.0f, 0.0f},
+ Common::Vec3f{0.0f, 1.0f, 0.0f},
+ Common::Vec3f{0.0f, 0.0f, 1.0f},
+ };
+ return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation};
+}
+
+void MotionInput::ResetOrientation() {
+ if (!reset_enabled || only_accelerometer) {
+ return;
+ }
+ if (!IsMoving(0.5f) && accel.z <= -0.9f) {
+ ++reset_counter;
+ if (reset_counter > 900) {
+ quat.w = 0;
+ quat.xyz[0] = 0;
+ quat.xyz[1] = 0;
+ quat.xyz[2] = -1;
+ SetOrientationFromAccelerometer();
+ integral_error = {};
+ reset_counter = 0;
+ }
+ } else {
+ reset_counter = 0;
+ }
+}
+
+void MotionInput::SetOrientationFromAccelerometer() {
+ int iterations = 0;
+ const f32 sample_period = 0.015f;
+
+ const auto normal_accel = accel.Normalized();
+
+ while (!IsCalibrated(0.01f) && ++iterations < 100) {
+ // Short name local variable for readability
+ f32 q1 = quat.w;
+ f32 q2 = quat.xyz[0];
+ f32 q3 = quat.xyz[1];
+ f32 q4 = quat.xyz[2];
+
+ Common::Vec3f rad_gyro;
+ const f32 ax = -normal_accel.x;
+ const f32 ay = normal_accel.y;
+ const f32 az = -normal_accel.z;
+
+ // Estimated direction of gravity
+ const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
+ const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
+ const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
+
+ // Error is cross product between estimated direction and measured direction of gravity
+ const Common::Vec3f new_real_error = {
+ az * vx - ax * vz,
+ ay * vz - az * vy,
+ ax * vy - ay * vx,
+ };
+
+ derivative_error = new_real_error - real_error;
+ real_error = new_real_error;
+
+ rad_gyro += 10.0f * kp * real_error;
+ rad_gyro += 5.0f * ki * integral_error;
+ rad_gyro += 10.0f * kd * derivative_error;
+
+ const f32 gx = rad_gyro.y;
+ const f32 gy = rad_gyro.x;
+ const f32 gz = rad_gyro.z;
+
+ // Integrate rate of change of quaternion
+ const f32 pa = q2;
+ const f32 pb = q3;
+ const f32 pc = q4;
+ q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
+ q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
+ q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
+ q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
+
+ quat.w = q1;
+ quat.xyz[0] = q2;
+ quat.xyz[1] = q3;
+ quat.xyz[2] = q4;
+ quat = quat.Normalized();
+ }
+}
+} // namespace InputCommon
diff --git a/src/input_common/motion_input.h b/src/input_common/motion_input.h
new file mode 100644
index 000000000..abb957f04
--- /dev/null
+++ b/src/input_common/motion_input.h
@@ -0,0 +1,73 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#pragma once
+
+#include "common/common_types.h"
+#include "common/quaternion.h"
+#include "common/vector_math.h"
+#include "core/frontend/input.h"
+
+namespace InputCommon {
+
+class MotionInput {
+public:
+ MotionInput(f32 new_kp, f32 new_ki, f32 new_kd);
+
+ MotionInput(const MotionInput&) = default;
+ MotionInput& operator=(const MotionInput&) = default;
+
+ MotionInput(MotionInput&&) = default;
+ MotionInput& operator=(MotionInput&&) = default;
+
+ void SetAcceleration(const Common::Vec3f& acceleration);
+ void SetGyroscope(const Common::Vec3f& gyroscope);
+ void SetQuaternion(const Common::Quaternion<f32>& quaternion);
+ void SetGyroDrift(const Common::Vec3f& drift);
+ void SetGyroThreshold(f32 threshold);
+
+ void EnableReset(bool reset);
+ void ResetRotations();
+
+ void UpdateRotation(u64 elapsed_time);
+ void UpdateOrientation(u64 elapsed_time);
+
+ std::array<Common::Vec3f, 3> GetOrientation() const;
+ Common::Vec3f GetAcceleration() const;
+ Common::Vec3f GetGyroscope() const;
+ Common::Vec3f GetRotations() const;
+ Common::Quaternion<f32> GetQuaternion() const;
+ Input::MotionStatus GetMotion() const;
+ Input::MotionStatus GetRandomMotion(int accel_magnitude, int gyro_magnitude) const;
+
+ bool IsMoving(f32 sensitivity) const;
+ bool IsCalibrated(f32 sensitivity) const;
+
+private:
+ void ResetOrientation();
+ void SetOrientationFromAccelerometer();
+
+ // PID constants
+ f32 kp;
+ f32 ki;
+ f32 kd;
+
+ // PID errors
+ Common::Vec3f real_error;
+ Common::Vec3f integral_error;
+ Common::Vec3f derivative_error;
+
+ Common::Quaternion<f32> quat{{0.0f, 0.0f, -1.0f}, 0.0f};
+ Common::Vec3f rotations;
+ Common::Vec3f accel;
+ Common::Vec3f gyro;
+ Common::Vec3f gyro_drift;
+
+ f32 gyro_threshold = 0.0f;
+ u32 reset_counter = 0;
+ bool reset_enabled = true;
+ bool only_accelerometer = true;
+};
+
+} // namespace InputCommon
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h
index 5306daa70..f3554be9a 100644
--- a/src/input_common/sdl/sdl.h
+++ b/src/input_common/sdl/sdl.h
@@ -6,6 +6,7 @@
#include <memory>
#include <vector>
+#include "common/param_package.h"
#include "input_common/main.h"
namespace InputCommon::Polling {
@@ -22,14 +23,24 @@ public:
/// Unregisters SDL device factories and shut them down.
virtual ~State() = default;
- virtual Pollers GetPollers(Polling::DeviceType type) = 0;
+ virtual Pollers GetPollers(Polling::DeviceType type) {
+ return {};
+ }
+
+ virtual std::vector<Common::ParamPackage> GetInputDevices() {
+ return {};
+ }
+
+ virtual ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&) {
+ return {};
+ }
+ virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) {
+ return {};
+ }
};
class NullState : public State {
public:
- Pollers GetPollers(Polling::DeviceType type) override {
- return {};
- }
};
std::unique_ptr<State> Init();
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index d76c279d3..8c2cef35d 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -3,10 +3,14 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <array>
#include <atomic>
+#include <chrono>
#include <cmath>
#include <functional>
#include <mutex>
+#include <optional>
+#include <sstream>
#include <string>
#include <thread>
#include <tuple>
@@ -15,15 +19,17 @@
#include <vector>
#include <SDL.h>
#include "common/logging/log.h"
-#include "common/math_util.h"
#include "common/param_package.h"
#include "common/threadsafe_queue.h"
#include "core/frontend/input.h"
+#include "input_common/motion_input.h"
#include "input_common/sdl/sdl_impl.h"
+#include "input_common/settings.h"
namespace InputCommon::SDL {
-static std::string GetGUID(SDL_Joystick* joystick) {
+namespace {
+std::string GetGUID(SDL_Joystick* joystick) {
const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
char guid_str[33];
SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
@@ -31,7 +37,8 @@ static std::string GetGUID(SDL_Joystick* joystick) {
}
/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
-static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
+Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
+} // Anonymous namespace
static int SDLEventWatcher(void* user_data, SDL_Event* event) {
auto* const sdl_state = static_cast<SDLState*>(user_data);
@@ -48,8 +55,10 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
class SDLJoystick {
public:
- SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick)
- : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {}
+ SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
+ SDL_GameController* game_controller)
+ : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
+ sdl_controller{game_controller, &SDL_GameControllerClose} {}
void SetButton(int button, bool value) {
std::lock_guard lock{mutex};
@@ -68,7 +77,34 @@ public:
float GetAxis(int axis, float range) const {
std::lock_guard lock{mutex};
- return state.axes.at(axis) / (32767.0f * range);
+ return static_cast<float>(state.axes.at(axis)) / (32767.0f * range);
+ }
+
+ bool RumblePlay(f32 amp_low, f32 amp_high, u32 time) {
+ const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF);
+ const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF);
+ // Lower drastically the number of state changes
+ if (raw_amp_low >> 11 == last_state_rumble_low >> 11 &&
+ raw_amp_high >> 11 == last_state_rumble_high >> 11) {
+ if (raw_amp_low + raw_amp_high != 0 ||
+ last_state_rumble_low + last_state_rumble_high == 0) {
+ return false;
+ }
+ }
+ // Don't change state if last vibration was < 20ms
+ const auto now = std::chrono::system_clock::now();
+ if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_vibration) <
+ std::chrono::milliseconds(20)) {
+ return raw_amp_low + raw_amp_high == 0;
+ }
+
+ last_vibration = now;
+ last_state_rumble_low = raw_amp_low;
+ last_state_rumble_high = raw_amp_high;
+ if (sdl_joystick) {
+ SDL_JoystickRumble(sdl_joystick.get(), raw_amp_low, raw_amp_high, time);
+ }
+ return false;
}
std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
@@ -88,6 +124,10 @@ public:
return std::make_tuple(x, y);
}
+ const MotionInput& GetMotion() const {
+ return motion;
+ }
+
void SetHat(int hat, Uint8 direction) {
std::lock_guard lock{mutex};
state.hats.insert_or_assign(hat, direction);
@@ -115,10 +155,15 @@ public:
return sdl_joystick.get();
}
- void SetSDLJoystick(SDL_Joystick* joystick) {
+ void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
+ sdl_controller.reset(controller);
sdl_joystick.reset(joystick);
}
+ SDL_GameController* GetSDLGameController() const {
+ return sdl_controller.get();
+ }
+
private:
struct State {
std::unordered_map<int, bool> buttons;
@@ -127,8 +172,15 @@ private:
} state;
std::string guid;
int port;
+ u16 last_state_rumble_high = 0;
+ u16 last_state_rumble_low = 0;
+ std::chrono::time_point<std::chrono::system_clock> last_vibration;
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
+ std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
mutable std::mutex mutex;
+
+ // Motion is initialized without PID values as motion input is not aviable for SDL2
+ MotionInput motion{0.0f, 0.0f, 0.0f};
};
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -136,18 +188,19 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& g
const auto it = joystick_map.find(guid);
if (it != joystick_map.end()) {
while (it->second.size() <= static_cast<std::size_t>(port)) {
- auto joystick =
- std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), nullptr);
+ auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
+ nullptr, nullptr);
it->second.emplace_back(std::move(joystick));
}
- return it->second[port];
+ return it->second[static_cast<std::size_t>(port)];
}
- auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr);
+ auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
return joystick_map[guid].emplace_back(std::move(joystick));
}
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
+ auto sdl_controller = SDL_GameControllerFromInstanceID(sdl_id);
const std::string guid = GetGUID(sdl_joystick);
std::lock_guard lock{joystick_map_mutex};
@@ -159,7 +212,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
return sdl_joystick == joystick->GetSDLJoystick();
});
if (vec_it != map_it->second.end()) {
- // This is the common case: There is already an existing SDL_Joystick maped to a
+ // This is the common case: There is already an existing SDL_Joystick mapped to a
// SDLJoystick. return the SDLJoystick
return *vec_it;
}
@@ -167,36 +220,40 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
// Search for a SDLJoystick without a mapped SDL_Joystick...
const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
[](const std::shared_ptr<SDLJoystick>& joystick) {
- return !joystick->GetSDLJoystick();
+ return joystick->GetSDLJoystick() == nullptr;
});
if (nullptr_it != map_it->second.end()) {
// ... and map it
- (*nullptr_it)->SetSDLJoystick(sdl_joystick);
+ (*nullptr_it)->SetSDLJoystick(sdl_joystick, sdl_controller);
return *nullptr_it;
}
// There is no SDLJoystick without a mapped SDL_Joystick
// Create a new SDLJoystick
const int port = static_cast<int>(map_it->second.size());
- auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
+ auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_controller);
return map_it->second.emplace_back(std::move(joystick));
}
- auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
+ auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_controller);
return joystick_map[guid].emplace_back(std::move(joystick));
}
void SDLState::InitJoystick(int joystick_index) {
SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
+ SDL_GameController* sdl_gamecontroller = nullptr;
+ if (SDL_IsGameController(joystick_index)) {
+ sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
+ }
if (!sdl_joystick) {
- LOG_ERROR(Input, "failed to open joystick {}", joystick_index);
+ LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
return;
}
const std::string guid = GetGUID(sdl_joystick);
std::lock_guard lock{joystick_map_mutex};
if (joystick_map.find(guid) == joystick_map.end()) {
- auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
+ auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
joystick_map[guid].emplace_back(std::move(joystick));
return;
}
@@ -205,33 +262,32 @@ void SDLState::InitJoystick(int joystick_index) {
joystick_guid_list.begin(), joystick_guid_list.end(),
[](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); });
if (it != joystick_guid_list.end()) {
- (*it)->SetSDLJoystick(sdl_joystick);
+ (*it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
return;
}
const int port = static_cast<int>(joystick_guid_list.size());
- auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
+ auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
joystick_guid_list.emplace_back(std::move(joystick));
}
void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
const std::string guid = GetGUID(sdl_joystick);
- std::shared_ptr<SDLJoystick> joystick;
+ std::shared_ptr<SDLJoystick> found_joystick;
{
std::lock_guard lock{joystick_map_mutex};
// This call to guid is safe since the joystick is guaranteed to be in the map
const auto& joystick_guid_list = joystick_map[guid];
- const auto joystick_it =
- std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
- [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
- return joystick->GetSDLJoystick() == sdl_joystick;
- });
- joystick = *joystick_it;
+ const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
+ [&sdl_joystick](const auto& joystick) {
+ return joystick->GetSDLJoystick() == sdl_joystick;
+ });
+ found_joystick = *joystick_it;
}
// Destruct SDL_Joystick outside the lock guard because SDL can internally call the
// event callback which locks the mutex again.
- joystick->SetSDLJoystick(nullptr);
+ found_joystick->SetSDLJoystick(nullptr, nullptr);
}
void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -285,6 +341,12 @@ public:
return joystick->GetButton(button);
}
+ bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override {
+ const f32 new_amp_low = pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f));
+ const f32 new_amp_high = pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f));
+ return joystick->RumblePlay(new_amp_low, new_amp_high, 250);
+ }
+
private:
std::shared_ptr<SDLJoystick> joystick;
int button;
@@ -329,8 +391,8 @@ private:
class SDLAnalog final : public Input::AnalogDevice {
public:
- SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_,
- float range_)
+ explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_,
+ float deadzone_, float range_)
: joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
range(range_) {}
@@ -341,12 +403,12 @@ public:
return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
y / r * (r - deadzone) / (1 - deadzone));
}
- return std::make_tuple<float, float>(0.0f, 0.0f);
+ return {};
}
bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
const auto [x, y] = GetStatus();
- const float directional_deadzone = 0.4f;
+ const float directional_deadzone = 0.5f;
switch (direction) {
case Input::AnalogDirection::RIGHT:
return x > directional_deadzone;
@@ -368,6 +430,68 @@ private:
const float range;
};
+class SDLDirectionMotion final : public Input::MotionDevice {
+public:
+ explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
+ : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
+
+ Input::MotionStatus GetStatus() const override {
+ if (joystick->GetHatDirection(hat, direction)) {
+ return joystick->GetMotion().GetRandomMotion(2, 6);
+ }
+ return joystick->GetMotion().GetRandomMotion(0, 0);
+ }
+
+private:
+ std::shared_ptr<SDLJoystick> joystick;
+ int hat;
+ Uint8 direction;
+};
+
+class SDLAxisMotion final : public Input::MotionDevice {
+public:
+ explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
+ bool trigger_if_greater_)
+ : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
+ trigger_if_greater(trigger_if_greater_) {}
+
+ Input::MotionStatus GetStatus() const override {
+ const float axis_value = joystick->GetAxis(axis, 1.0f);
+ bool trigger = axis_value < threshold;
+ if (trigger_if_greater) {
+ trigger = axis_value > threshold;
+ }
+
+ if (trigger) {
+ return joystick->GetMotion().GetRandomMotion(2, 6);
+ }
+ return joystick->GetMotion().GetRandomMotion(0, 0);
+ }
+
+private:
+ std::shared_ptr<SDLJoystick> joystick;
+ int axis;
+ float threshold;
+ bool trigger_if_greater;
+};
+
+class SDLButtonMotion final : public Input::MotionDevice {
+public:
+ explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
+ : joystick(std::move(joystick_)), button(button_) {}
+
+ Input::MotionStatus GetStatus() const override {
+ if (joystick->GetButton(button)) {
+ return joystick->GetMotion().GetRandomMotion(2, 6);
+ }
+ return joystick->GetMotion().GetRandomMotion(0, 0);
+ }
+
+private:
+ std::shared_ptr<SDLJoystick> joystick;
+ int button;
+};
+
/// A button device factory that creates button devices from SDL joystick
class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
public:
@@ -460,7 +584,7 @@ public:
const int port = params.Get("port", 0);
const int axis_x = params.Get("axis_x", 0);
const int axis_y = params.Get("axis_y", 1);
- const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
+ const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
auto joystick = state.GetSDLJoystickByGUID(guid, port);
@@ -474,17 +598,86 @@ private:
SDLState& state;
};
+/// A motion device factory that creates motion devices from SDL joystick
+class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
+public:
+ explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
+ /**
+ * Creates motion device from joystick axes
+ * @param params contains parameters for creating the device:
+ * - "guid": the guid of the joystick to bind
+ * - "port": the nth joystick of the same type
+ */
+ std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
+ const std::string guid = params.Get("guid", "0");
+ const int port = params.Get("port", 0);
+
+ auto joystick = state.GetSDLJoystickByGUID(guid, port);
+
+ if (params.Has("hat")) {
+ const int hat = params.Get("hat", 0);
+ const std::string direction_name = params.Get("direction", "");
+ Uint8 direction;
+ if (direction_name == "up") {
+ direction = SDL_HAT_UP;
+ } else if (direction_name == "down") {
+ direction = SDL_HAT_DOWN;
+ } else if (direction_name == "left") {
+ direction = SDL_HAT_LEFT;
+ } else if (direction_name == "right") {
+ direction = SDL_HAT_RIGHT;
+ } else {
+ direction = 0;
+ }
+ // This is necessary so accessing GetHat with hat won't crash
+ joystick->SetHat(hat, SDL_HAT_CENTERED);
+ return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
+ }
+
+ if (params.Has("axis")) {
+ const int axis = params.Get("axis", 0);
+ const float threshold = params.Get("threshold", 0.5f);
+ const std::string direction_name = params.Get("direction", "");
+ bool trigger_if_greater;
+ if (direction_name == "+") {
+ trigger_if_greater = true;
+ } else if (direction_name == "-") {
+ trigger_if_greater = false;
+ } else {
+ trigger_if_greater = true;
+ LOG_ERROR(Input, "Unknown direction {}", direction_name);
+ }
+ // This is necessary so accessing GetAxis with axis won't crash
+ joystick->SetAxis(axis, 0);
+ return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
+ }
+
+ const int button = params.Get("button", 0);
+ // This is necessary so accessing GetButton with button won't crash
+ joystick->SetButton(button, false);
+ return std::make_unique<SDLButtonMotion>(joystick, button);
+ }
+
+private:
+ SDLState& state;
+};
+
SDLState::SDLState() {
using namespace Input;
- RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this));
- RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this));
-
- // If the frontend is going to manage the event loop, then we dont start one here
- start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
+ analog_factory = std::make_shared<SDLAnalogFactory>(*this);
+ button_factory = std::make_shared<SDLButtonFactory>(*this);
+ motion_factory = std::make_shared<SDLMotionFactory>(*this);
+ RegisterFactory<AnalogDevice>("sdl", analog_factory);
+ RegisterFactory<ButtonDevice>("sdl", button_factory);
+ RegisterFactory<MotionDevice>("sdl", motion_factory);
+
+ // If the frontend is going to manage the event loop, then we don't start one here
+ start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
return;
}
+ has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0;
if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
}
@@ -497,7 +690,7 @@ SDLState::SDLState() {
using namespace std::chrono_literals;
while (initialized) {
SDL_PumpEvents();
- std::this_thread::sleep_for(10ms);
+ std::this_thread::sleep_for(5ms);
}
});
}
@@ -512,6 +705,7 @@ SDLState::~SDLState() {
using namespace Input;
UnregisterFactory<ButtonDevice>("sdl");
UnregisterFactory<AnalogDevice>("sdl");
+ UnregisterFactory<MotionDevice>("sdl");
CloseJoysticks();
SDL_DelEventWatch(&SDLEventWatcher, this);
@@ -523,65 +717,255 @@ SDLState::~SDLState() {
}
}
-static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
+std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
+ std::scoped_lock lock(joystick_map_mutex);
+ std::vector<Common::ParamPackage> devices;
+ for (const auto& [key, value] : joystick_map) {
+ for (const auto& joystick : value) {
+ auto* joy = joystick->GetSDLJoystick();
+ if (auto* controller = joystick->GetSDLGameController()) {
+ std::string name =
+ fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
+ devices.emplace_back(Common::ParamPackage{
+ {"class", "sdl"},
+ {"display", std::move(name)},
+ {"guid", joystick->GetGUID()},
+ {"port", std::to_string(joystick->GetPort())},
+ });
+ } else if (joy) {
+ std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
+ devices.emplace_back(Common::ParamPackage{
+ {"class", "sdl"},
+ {"display", std::move(name)},
+ {"guid", joystick->GetGUID()},
+ {"port", std::to_string(joystick->GetPort())},
+ });
+ }
+ }
+ }
+ return devices;
+}
+
+namespace {
+Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
+ float value = 0.1f) {
+ Common::ParamPackage params({{"engine", "sdl"}});
+ params.Set("port", port);
+ params.Set("guid", std::move(guid));
+ params.Set("axis", axis);
+ if (value > 0) {
+ params.Set("direction", "+");
+ params.Set("threshold", "0.5");
+ } else {
+ params.Set("direction", "-");
+ params.Set("threshold", "-0.5");
+ }
+ return params;
+}
+
+Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, s32 button) {
Common::ParamPackage params({{"engine", "sdl"}});
+ params.Set("port", port);
+ params.Set("guid", std::move(guid));
+ params.Set("button", button);
+ return params;
+}
+
+Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, s32 value) {
+ Common::ParamPackage params({{"engine", "sdl"}});
+
+ params.Set("port", port);
+ params.Set("guid", std::move(guid));
+ params.Set("hat", hat);
+ switch (value) {
+ case SDL_HAT_UP:
+ params.Set("direction", "up");
+ break;
+ case SDL_HAT_DOWN:
+ params.Set("direction", "down");
+ break;
+ case SDL_HAT_LEFT:
+ params.Set("direction", "left");
+ break;
+ case SDL_HAT_RIGHT:
+ params.Set("direction", "right");
+ break;
+ default:
+ return {};
+ }
+ return params;
+}
+Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
switch (event.type) {
case SDL_JOYAXISMOTION: {
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
- params.Set("port", joystick->GetPort());
- params.Set("guid", joystick->GetGUID());
- params.Set("axis", event.jaxis.axis);
- if (event.jaxis.value > 0) {
- params.Set("direction", "+");
- params.Set("threshold", "0.5");
- } else {
- params.Set("direction", "-");
- params.Set("threshold", "-0.5");
- }
- break;
+ return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
+ static_cast<s32>(event.jaxis.axis),
+ event.jaxis.value);
}
case SDL_JOYBUTTONUP: {
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
- params.Set("port", joystick->GetPort());
- params.Set("guid", joystick->GetGUID());
- params.Set("button", event.jbutton.button);
- break;
+ return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
+ static_cast<s32>(event.jbutton.button));
}
case SDL_JOYHATMOTION: {
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
- params.Set("port", joystick->GetPort());
- params.Set("guid", joystick->GetGUID());
- params.Set("hat", event.jhat.hat);
- switch (event.jhat.value) {
- case SDL_HAT_UP:
- params.Set("direction", "up");
- break;
- case SDL_HAT_DOWN:
- params.Set("direction", "down");
- break;
- case SDL_HAT_LEFT:
- params.Set("direction", "left");
- break;
- case SDL_HAT_RIGHT:
- params.Set("direction", "right");
- break;
- default:
- return {};
- }
- break;
+ return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
+ static_cast<s32>(event.jhat.hat),
+ static_cast<s32>(event.jhat.value));
}
}
+ return {};
+}
+
+Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
+ switch (event.type) {
+ case SDL_JOYAXISMOTION: {
+ const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
+ return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
+ static_cast<s32>(event.jaxis.axis),
+ event.jaxis.value);
+ }
+ case SDL_JOYBUTTONUP: {
+ const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
+ return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
+ static_cast<s32>(event.jbutton.button));
+ }
+ case SDL_JOYHATMOTION: {
+ const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
+ return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
+ static_cast<s32>(event.jhat.hat),
+ static_cast<s32>(event.jhat.value));
+ }
+ }
+ return {};
+}
+
+Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
+ const SDL_GameControllerButtonBind& binding) {
+ switch (binding.bindType) {
+ case SDL_CONTROLLER_BINDTYPE_AXIS:
+ return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
+ case SDL_CONTROLLER_BINDTYPE_BUTTON:
+ return BuildButtonParamPackageForButton(port, guid, binding.value.button);
+ case SDL_CONTROLLER_BINDTYPE_HAT:
+ return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
+ binding.value.hat.hat_mask);
+ }
+ return {};
+}
+
+Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
+ int axis_y) {
+ Common::ParamPackage params;
+ params.Set("engine", "sdl");
+ params.Set("port", port);
+ params.Set("guid", guid);
+ params.Set("axis_x", axis_x);
+ params.Set("axis_y", axis_y);
return params;
}
+} // Anonymous namespace
-namespace Polling {
+ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
+ if (!params.Has("guid") || !params.Has("port")) {
+ return {};
+ }
+ const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
+ auto* controller = joystick->GetSDLGameController();
+ if (controller == nullptr) {
+ return {};
+ }
+
+ // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
+ // We will add those afterwards
+ // This list also excludes Screenshot since theres not really a mapping for that
+ using ButtonBindings =
+ std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
+ static constexpr ButtonBindings switch_to_sdl_button{{
+ {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
+ {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
+ {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
+ {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
+ {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
+ {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
+ {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
+ {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
+ {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
+ {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
+ {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
+ {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
+ {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
+ {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
+ {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
+ {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
+ {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
+ }};
+
+ // Add the missing bindings for ZL/ZR
+ using ZBindings =
+ std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
+ static constexpr ZBindings switch_to_sdl_axis{{
+ {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
+ {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
+ }};
+
+ ButtonMapping mapping;
+ mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
+
+ for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
+ const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
+ mapping.insert_or_assign(
+ switch_button,
+ BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
+ }
+ for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
+ const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
+ mapping.insert_or_assign(
+ switch_button,
+ BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
+ }
+
+ return mapping;
+}
+AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
+ if (!params.Has("guid") || !params.Has("port")) {
+ return {};
+ }
+ const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
+ auto* controller = joystick->GetSDLGameController();
+ if (controller == nullptr) {
+ return {};
+ }
+
+ AnalogMapping mapping = {};
+ const auto& binding_left_x =
+ SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
+ const auto& binding_left_y =
+ SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
+ mapping.insert_or_assign(Settings::NativeAnalog::LStick,
+ BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
+ binding_left_x.value.axis,
+ binding_left_y.value.axis));
+ const auto& binding_right_x =
+ SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
+ const auto& binding_right_y =
+ SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
+ mapping.insert_or_assign(Settings::NativeAnalog::RStick,
+ BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
+ binding_right_x.value.axis,
+ binding_right_y.value.axis));
+ return mapping;
+}
+
+namespace Polling {
class SDLPoller : public InputCommon::Polling::DevicePoller {
public:
explicit SDLPoller(SDLState& state_) : state(state_) {}
- void Start() override {
+ void Start(const std::string& device_id) override {
state.event_queue.Clear();
state.polling = true;
}
@@ -601,71 +985,135 @@ public:
Common::ParamPackage GetNextInput() override {
SDL_Event event;
while (state.event_queue.Pop(event)) {
- switch (event.type) {
- case SDL_JOYAXISMOTION:
- if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
- break;
- }
- [[fallthrough]];
- case SDL_JOYBUTTONUP:
- case SDL_JOYHATMOTION:
- return SDLEventToButtonParamPackage(state, event);
+ const auto package = FromEvent(event);
+ if (package) {
+ return *package;
}
}
return {};
}
+ [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
+ switch (event.type) {
+ case SDL_JOYAXISMOTION:
+ if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
+ break;
+ }
+ [[fallthrough]];
+ case SDL_JOYBUTTONUP:
+ case SDL_JOYHATMOTION:
+ return {SDLEventToButtonParamPackage(state, event)};
+ }
+ return std::nullopt;
+ }
};
-class SDLAnalogPoller final : public SDLPoller {
+class SDLMotionPoller final : public SDLPoller {
public:
- explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {}
+ explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
- void Start() override {
- SDLPoller::Start();
+ Common::ParamPackage GetNextInput() override {
+ SDL_Event event;
+ while (state.event_queue.Pop(event)) {
+ const auto package = FromEvent(event);
+ if (package) {
+ return *package;
+ }
+ }
+ return {};
+ }
+ [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
+ switch (event.type) {
+ case SDL_JOYAXISMOTION:
+ if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
+ break;
+ }
+ [[fallthrough]];
+ case SDL_JOYBUTTONUP:
+ case SDL_JOYHATMOTION:
+ return {SDLEventToMotionParamPackage(state, event)};
+ }
+ return std::nullopt;
+ }
+};
+
+/**
+ * Attempts to match the press to a controller joy axis (left/right stick) and if a match
+ * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
+ * instead
+ */
+class SDLAnalogPreferredPoller final : public SDLPoller {
+public:
+ explicit SDLAnalogPreferredPoller(SDLState& state_)
+ : SDLPoller(state_), button_poller(state_) {}
+ void Start(const std::string& device_id) override {
+ SDLPoller::Start(device_id);
+ // Load the game controller
// Reset stored axes
analog_x_axis = -1;
analog_y_axis = -1;
- analog_axes_joystick = -1;
}
Common::ParamPackage GetNextInput() override {
SDL_Event event;
while (state.event_queue.Pop(event)) {
- if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) {
+ // Filter out axis events that are below a threshold
+ if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
continue;
}
- // An analog device needs two axes, so we need to store the axis for later and wait for
- // a second SDL event. The axes also must be from the same joystick.
- const int axis = event.jaxis.axis;
- if (analog_x_axis == -1) {
- analog_x_axis = axis;
- analog_axes_joystick = event.jaxis.which;
- } else if (analog_y_axis == -1 && analog_x_axis != axis &&
- analog_axes_joystick == event.jaxis.which) {
- analog_y_axis = axis;
+ // Simplify controller config by testing if game controller support is enabled.
+ if (event.type == SDL_JOYAXISMOTION) {
+ const auto axis = event.jaxis.axis;
+ const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
+ auto* const controller = joystick->GetSDLGameController();
+ if (controller) {
+ const auto axis_left_x =
+ SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
+ .value.axis;
+ const auto axis_left_y =
+ SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)
+ .value.axis;
+ const auto axis_right_x =
+ SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX)
+ .value.axis;
+ const auto axis_right_y =
+ SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY)
+ .value.axis;
+
+ if (axis == axis_left_x || axis == axis_left_y) {
+ analog_x_axis = axis_left_x;
+ analog_y_axis = axis_left_y;
+ break;
+ } else if (axis == axis_right_x || axis == axis_right_y) {
+ analog_x_axis = axis_right_x;
+ analog_y_axis = axis_right_y;
+ break;
+ }
+ }
+ }
+
+ // If the press wasn't accepted as a joy axis, check for a button press
+ auto button_press = button_poller.FromEvent(event);
+ if (button_press) {
+ return *button_press;
}
}
- Common::ParamPackage params;
+
if (analog_x_axis != -1 && analog_y_axis != -1) {
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
- params.Set("engine", "sdl");
- params.Set("port", joystick->GetPort());
- params.Set("guid", joystick->GetGUID());
- params.Set("axis_x", analog_x_axis);
- params.Set("axis_y", analog_y_axis);
+ auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
+ analog_x_axis, analog_y_axis);
analog_x_axis = -1;
analog_y_axis = -1;
- analog_axes_joystick = -1;
return params;
}
- return params;
+ return {};
}
private:
int analog_x_axis = -1;
int analog_y_axis = -1;
- SDL_JoystickID analog_axes_joystick = -1;
+ SDLButtonPoller button_poller;
};
} // namespace Polling
@@ -673,12 +1121,15 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
Pollers pollers;
switch (type) {
- case InputCommon::Polling::DeviceType::Analog:
- pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this));
+ case InputCommon::Polling::DeviceType::AnalogPreferred:
+ pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
break;
case InputCommon::Polling::DeviceType::Button:
pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
break;
+ case InputCommon::Polling::DeviceType::Motion:
+ pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
+ break;
}
return pollers;
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index 606a32c5b..b9bb4dc56 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -21,6 +21,7 @@ namespace InputCommon::SDL {
class SDLAnalogFactory;
class SDLButtonFactory;
+class SDLMotionFactory;
class SDLJoystick;
class SDLState : public State {
@@ -50,6 +51,11 @@ public:
std::atomic<bool> polling = false;
Common::SPSCQueue<SDL_Event> event_queue;
+ std::vector<Common::ParamPackage> GetInputDevices() override;
+
+ ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
+ AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
+
private:
void InitJoystick(int joystick_index);
void CloseJoystick(SDL_Joystick* sdl_joystick);
@@ -57,12 +63,16 @@ private:
/// Needs to be called before SDL_QuitSubSystem.
void CloseJoysticks();
+ // Set to true if SDL supports game controller subsystem
+ bool has_gamecontroller = false;
+
/// Map of GUID of a list of corresponding virtual Joysticks
std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
std::mutex joystick_map_mutex;
std::shared_ptr<SDLButtonFactory> button_factory;
std::shared_ptr<SDLAnalogFactory> analog_factory;
+ std::shared_ptr<SDLMotionFactory> motion_factory;
bool start_thread = false;
std::atomic<bool> initialized = false;
diff --git a/src/input_common/settings.cpp b/src/input_common/settings.cpp
new file mode 100644
index 000000000..b66c05856
--- /dev/null
+++ b/src/input_common/settings.cpp
@@ -0,0 +1,40 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "input_common/settings.h"
+
+namespace Settings {
+namespace NativeButton {
+const std::array<const char*, NumButtons> mapping = {{
+ "button_a", "button_b", "button_x", "button_y", "button_lstick",
+ "button_rstick", "button_l", "button_r", "button_zl", "button_zr",
+ "button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
+ "button_ddown", "button_sl", "button_sr", "button_home", "button_screenshot",
+}};
+}
+
+namespace NativeMotion {
+const std::array<const char*, NumMotions> mapping = {{
+ "motionleft",
+ "motionright",
+}};
+}
+
+namespace NativeAnalog {
+const std::array<const char*, NumAnalogs> mapping = {{
+ "lstick",
+ "rstick",
+}};
+}
+
+namespace NativeMouseButton {
+const std::array<const char*, NumMouseButtons> mapping = {{
+ "left",
+ "right",
+ "middle",
+ "forward",
+ "back",
+}};
+}
+} // namespace Settings
diff --git a/src/input_common/settings.h b/src/input_common/settings.h
new file mode 100644
index 000000000..ab0b95cf1
--- /dev/null
+++ b/src/input_common/settings.h
@@ -0,0 +1,352 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <string>
+#include "common/common_types.h"
+
+namespace Settings {
+namespace NativeButton {
+enum Values : int {
+ A,
+ B,
+ X,
+ Y,
+ LStick,
+ RStick,
+ L,
+ R,
+ ZL,
+ ZR,
+ Plus,
+ Minus,
+
+ DLeft,
+ DUp,
+ DRight,
+ DDown,
+
+ SL,
+ SR,
+
+ Home,
+ Screenshot,
+
+ NumButtons,
+};
+
+constexpr int BUTTON_HID_BEGIN = A;
+constexpr int BUTTON_NS_BEGIN = Home;
+
+constexpr int BUTTON_HID_END = BUTTON_NS_BEGIN;
+constexpr int BUTTON_NS_END = NumButtons;
+
+constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
+constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
+
+extern const std::array<const char*, NumButtons> mapping;
+
+} // namespace NativeButton
+
+namespace NativeAnalog {
+enum Values : int {
+ LStick,
+ RStick,
+
+ NumAnalogs,
+};
+
+constexpr int STICK_HID_BEGIN = LStick;
+constexpr int STICK_HID_END = NumAnalogs;
+constexpr int NUM_STICKS_HID = NumAnalogs;
+
+extern const std::array<const char*, NumAnalogs> mapping;
+} // namespace NativeAnalog
+
+namespace NativeMotion {
+enum Values : int {
+ MOTIONLEFT,
+ MOTIONRIGHT,
+
+ NumMotions,
+};
+
+constexpr int MOTION_HID_BEGIN = MOTIONLEFT;
+constexpr int MOTION_HID_END = NumMotions;
+constexpr int NUM_MOTION_HID = NumMotions;
+
+extern const std::array<const char*, NumMotions> mapping;
+} // namespace NativeMotion
+
+namespace NativeMouseButton {
+enum Values {
+ Left,
+ Right,
+ Middle,
+ Forward,
+ Back,
+
+ NumMouseButtons,
+};
+
+constexpr int MOUSE_HID_BEGIN = Left;
+constexpr int MOUSE_HID_END = NumMouseButtons;
+constexpr int NUM_MOUSE_HID = NumMouseButtons;
+
+extern const std::array<const char*, NumMouseButtons> mapping;
+} // namespace NativeMouseButton
+
+namespace NativeKeyboard {
+enum Keys {
+ None,
+ Error,
+
+ A = 4,
+ B,
+ C,
+ D,
+ E,
+ F,
+ G,
+ H,
+ I,
+ J,
+ K,
+ L,
+ M,
+ N,
+ O,
+ P,
+ Q,
+ R,
+ S,
+ T,
+ U,
+ V,
+ W,
+ X,
+ Y,
+ Z,
+ N1,
+ N2,
+ N3,
+ N4,
+ N5,
+ N6,
+ N7,
+ N8,
+ N9,
+ N0,
+ Enter,
+ Escape,
+ Backspace,
+ Tab,
+ Space,
+ Minus,
+ Equal,
+ LeftBrace,
+ RightBrace,
+ Backslash,
+ Tilde,
+ Semicolon,
+ Apostrophe,
+ Grave,
+ Comma,
+ Dot,
+ Slash,
+ CapsLockKey,
+
+ F1,
+ F2,
+ F3,
+ F4,
+ F5,
+ F6,
+ F7,
+ F8,
+ F9,
+ F10,
+ F11,
+ F12,
+
+ SystemRequest,
+ ScrollLockKey,
+ Pause,
+ Insert,
+ Home,
+ PageUp,
+ Delete,
+ End,
+ PageDown,
+ Right,
+ Left,
+ Down,
+ Up,
+
+ NumLockKey,
+ KPSlash,
+ KPAsterisk,
+ KPMinus,
+ KPPlus,
+ KPEnter,
+ KP1,
+ KP2,
+ KP3,
+ KP4,
+ KP5,
+ KP6,
+ KP7,
+ KP8,
+ KP9,
+ KP0,
+ KPDot,
+
+ Key102,
+ Compose,
+ Power,
+ KPEqual,
+
+ F13,
+ F14,
+ F15,
+ F16,
+ F17,
+ F18,
+ F19,
+ F20,
+ F21,
+ F22,
+ F23,
+ F24,
+
+ Open,
+ Help,
+ Properties,
+ Front,
+ Stop,
+ Repeat,
+ Undo,
+ Cut,
+ Copy,
+ Paste,
+ Find,
+ Mute,
+ VolumeUp,
+ VolumeDown,
+ CapsLockActive,
+ NumLockActive,
+ ScrollLockActive,
+ KPComma,
+
+ KPLeftParenthesis,
+ KPRightParenthesis,
+
+ LeftControlKey = 0xE0,
+ LeftShiftKey,
+ LeftAltKey,
+ LeftMetaKey,
+ RightControlKey,
+ RightShiftKey,
+ RightAltKey,
+ RightMetaKey,
+
+ MediaPlayPause,
+ MediaStopCD,
+ MediaPrevious,
+ MediaNext,
+ MediaEject,
+ MediaVolumeUp,
+ MediaVolumeDown,
+ MediaMute,
+ MediaWebsite,
+ MediaBack,
+ MediaForward,
+ MediaStop,
+ MediaFind,
+ MediaScrollUp,
+ MediaScrollDown,
+ MediaEdit,
+ MediaSleep,
+ MediaCoffee,
+ MediaRefresh,
+ MediaCalculator,
+
+ NumKeyboardKeys,
+};
+
+static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
+
+enum Modifiers {
+ LeftControl,
+ LeftShift,
+ LeftAlt,
+ LeftMeta,
+ RightControl,
+ RightShift,
+ RightAlt,
+ RightMeta,
+ CapsLock,
+ ScrollLock,
+ NumLock,
+
+ NumKeyboardMods,
+};
+
+constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
+constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
+constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
+
+constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
+constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
+constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
+
+} // namespace NativeKeyboard
+
+using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
+using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
+using MotionRaw = std::array<std::string, NativeMotion::NumMotions>;
+using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
+using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
+using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
+
+constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
+constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
+constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
+constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
+
+enum class ControllerType {
+ ProController,
+ DualJoyconDetached,
+ LeftJoycon,
+ RightJoycon,
+ Handheld,
+};
+
+struct PlayerInput {
+ bool connected;
+ ControllerType controller_type;
+ ButtonsRaw buttons;
+ AnalogsRaw analogs;
+ MotionRaw motions;
+ std::string lstick_mod;
+ std::string rstick_mod;
+
+ u32 body_color_left;
+ u32 body_color_right;
+ u32 button_color_left;
+ u32 button_color_right;
+};
+
+struct TouchscreenInput {
+ bool enabled;
+ std::string device;
+
+ u32 finger;
+ u32 diameter_x;
+ u32 diameter_y;
+ u32 rotation_angle;
+};
+} // namespace Settings
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp
new file mode 100644
index 000000000..c37716aae
--- /dev/null
+++ b/src/input_common/touch_from_button.cpp
@@ -0,0 +1,52 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/frontend/framebuffer_layout.h"
+#include "core/settings.h"
+#include "input_common/touch_from_button.h"
+
+namespace InputCommon {
+
+class TouchFromButtonDevice final : public Input::TouchDevice {
+public:
+ TouchFromButtonDevice() {
+ const auto button_index =
+ static_cast<std::size_t>(Settings::values.touch_from_button_map_index);
+ const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
+
+ for (const auto& config_entry : buttons) {
+ const Common::ParamPackage package{config_entry};
+ map.emplace_back(
+ Input::CreateDevice<Input::ButtonDevice>(config_entry),
+ std::clamp(package.Get("x", 0), 0, static_cast<int>(Layout::ScreenUndocked::Width)),
+ std::clamp(package.Get("y", 0), 0,
+ static_cast<int>(Layout::ScreenUndocked::Height)));
+ }
+ }
+
+ std::tuple<float, float, bool> GetStatus() const override {
+ for (const auto& m : map) {
+ const bool state = std::get<0>(m)->GetStatus();
+ if (state) {
+ const float x = static_cast<float>(std::get<1>(m)) /
+ static_cast<int>(Layout::ScreenUndocked::Width);
+ const float y = static_cast<float>(std::get<2>(m)) /
+ static_cast<int>(Layout::ScreenUndocked::Height);
+ return {x, y, true};
+ }
+ }
+ return {};
+ }
+
+private:
+ // A vector of the mapped button, its x and its y-coordinate
+ std::vector<std::tuple<std::unique_ptr<Input::ButtonDevice>, int, int>> map;
+};
+
+std::unique_ptr<Input::TouchDevice> TouchFromButtonFactory::Create(
+ const Common::ParamPackage& params) {
+ return std::make_unique<TouchFromButtonDevice>();
+}
+
+} // namespace InputCommon
diff --git a/src/input_common/touch_from_button.h b/src/input_common/touch_from_button.h
new file mode 100644
index 000000000..8b4d1aa96
--- /dev/null
+++ b/src/input_common/touch_from_button.h
@@ -0,0 +1,23 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include "core/frontend/input.h"
+
+namespace InputCommon {
+
+/**
+ * A touch device factory that takes a list of button devices and combines them into a touch device.
+ */
+class TouchFromButtonFactory final : public Input::Factory<Input::TouchDevice> {
+public:
+ /**
+ * Creates a touch device from a list of button devices
+ */
+ std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override;
+};
+
+} // namespace InputCommon
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 3f4eaf448..7039d6fc3 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -2,14 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <algorithm>
-#include <array>
#include <chrono>
#include <cstring>
#include <functional>
#include <thread>
#include <boost/asio.hpp>
#include "common/logging/log.h"
+#include "core/settings.h"
#include "input_common/udp/client.h"
#include "input_common/udp/protocol.h"
@@ -27,11 +26,11 @@ class Socket {
public:
using clock = std::chrono::system_clock;
- explicit Socket(const std::string& host, u16 port, u8 pad_index, u32 client_id,
- SocketCallback callback)
- : callback(std::move(callback)), timer(io_service),
- socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id),
- pad_index(pad_index) {
+ explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, u32 client_id_,
+ SocketCallback callback_)
+ : callback(std::move(callback_)), timer(io_service),
+ socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id_),
+ pad_index(pad_index_) {
boost::system::error_code ec{};
auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
if (ec.value() != boost::system::errc::success) {
@@ -94,13 +93,17 @@ private:
void HandleSend(const boost::system::error_code& error) {
boost::system::error_code _ignored{};
// Send a request for getting port info for the pad
- Request::PortInfo port_info{1, {pad_index, 0, 0, 0}};
+ const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}};
const auto port_message = Request::Create(port_info, client_id);
std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE);
socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored);
// Send a request for getting pad data for the pad
- Request::PadData pad_data{Request::PadData::Flags::Id, pad_index, EMPTY_MAC_ADDRESS};
+ const Request::PadData pad_data{
+ Request::PadData::Flags::Id,
+ static_cast<u8>(pad_index),
+ EMPTY_MAC_ADDRESS,
+ };
const auto pad_message = Request::Create(pad_data, client_id);
std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE);
socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored);
@@ -113,7 +116,7 @@ private:
udp::socket socket;
u32 client_id{};
- u8 pad_index{};
+ std::size_t pad_index{};
static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>);
@@ -131,21 +134,59 @@ static void SocketLoop(Socket* socket) {
socket->Loop();
}
-Client::Client(std::shared_ptr<DeviceStatus> status, const std::string& host, u16 port,
- u8 pad_index, u32 client_id)
- : status(std::move(status)) {
- StartCommunication(host, port, pad_index, client_id);
+Client::Client() {
+ LOG_INFO(Input, "Udp Initialization started");
+ for (std::size_t client = 0; client < clients.size(); client++) {
+ const auto pad = client % 4;
+ StartCommunication(client, Settings::values.udp_input_address,
+ Settings::values.udp_input_port, pad, 24872);
+ // Set motion parameters
+ // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
+ // Real HW values are unknown, 0.0001 is an approximate to Standard
+ clients[client].motion.SetGyroThreshold(0.0001f);
+ }
}
Client::~Client() {
- socket->Stop();
- thread.join();
+ Reset();
+}
+
+std::vector<Common::ParamPackage> Client::GetInputDevices() const {
+ std::vector<Common::ParamPackage> devices;
+ for (std::size_t client = 0; client < clients.size(); client++) {
+ if (!DeviceConnected(client)) {
+ continue;
+ }
+ std::string name = fmt::format("UDP Controller {}", client);
+ devices.emplace_back(Common::ParamPackage{
+ {"class", "cemuhookudp"},
+ {"display", std::move(name)},
+ {"port", std::to_string(client)},
+ });
+ }
+ return devices;
}
-void Client::ReloadSocket(const std::string& host, u16 port, u8 pad_index, u32 client_id) {
- socket->Stop();
- thread.join();
- StartCommunication(host, port, pad_index, client_id);
+bool Client::DeviceConnected(std::size_t pad) const {
+ // Use last timestamp to detect if the socket has stopped sending data
+ const auto now = std::chrono::system_clock::now();
+ const auto time_difference = static_cast<u64>(
+ std::chrono::duration_cast<std::chrono::milliseconds>(now - clients[pad].last_motion_update)
+ .count());
+ return time_difference < 1000 && clients[pad].active == 1;
+}
+
+void Client::ReloadUDPClient() {
+ for (std::size_t client = 0; client < clients.size(); client++) {
+ ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, client);
+ }
+}
+void Client::ReloadSocket(const std::string& host, u16 port, std::size_t pad_index, u32 client_id) {
+ // client number must be determined from host / port and pad index
+ const std::size_t client = pad_index;
+ clients[client].socket->Stop();
+ clients[client].thread.join();
+ StartCommunication(client, host, port, pad_index, client_id);
}
void Client::OnVersion(Response::Version data) {
@@ -157,23 +198,36 @@ void Client::OnPortInfo(Response::PortInfo data) {
}
void Client::OnPadData(Response::PadData data) {
+ // Client number must be determined from host / port and pad index
+ const std::size_t client = data.info.id;
LOG_TRACE(Input, "PadData packet received");
- if (data.packet_counter <= packet_sequence) {
+ if (data.packet_counter == clients[client].packet_sequence) {
LOG_WARNING(
Input,
"PadData packet dropped because its stale info. Current count: {} Packet count: {}",
- packet_sequence, data.packet_counter);
+ clients[client].packet_sequence, data.packet_counter);
return;
}
- packet_sequence = data.packet_counter;
- // TODO: Check how the Switch handles motions and how the CemuhookUDP motion
- // directions correspond to the ones of the Switch
- Common::Vec3f accel = Common::MakeVec<float>(data.accel.x, data.accel.y, data.accel.z);
- Common::Vec3f gyro = Common::MakeVec<float>(data.gyro.pitch, data.gyro.yaw, data.gyro.roll);
- {
- std::lock_guard guard(status->update_mutex);
+ clients[client].active = data.info.is_pad_active;
+ clients[client].packet_sequence = data.packet_counter;
+ const auto now = std::chrono::system_clock::now();
+ const auto time_difference =
+ static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>(
+ now - clients[client].last_motion_update)
+ .count());
+ clients[client].last_motion_update = now;
+ const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw};
+ clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
+ // Gyroscope values are not it the correct scale from better joy.
+ // Dividing by 312 allows us to make one full turn = 1 turn
+ // This must be a configurable valued called sensitivity
+ clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f);
+ clients[client].motion.UpdateRotation(time_difference);
+ clients[client].motion.UpdateOrientation(time_difference);
- status->motion_status = {accel, gyro};
+ {
+ std::lock_guard guard(clients[client].status.update_mutex);
+ clients[client].status.motion_status = clients[client].motion.GetMotion();
// TODO: add a setting for "click" touch. Click touch refers to a device that differentiates
// between a simple "tap" and a hard press that causes the touch screen to click.
@@ -182,41 +236,115 @@ void Client::OnPadData(Response::PadData data) {
float x = 0;
float y = 0;
- if (is_active && status->touch_calibration) {
- const u16 min_x = status->touch_calibration->min_x;
- const u16 max_x = status->touch_calibration->max_x;
- const u16 min_y = status->touch_calibration->min_y;
- const u16 max_y = status->touch_calibration->max_y;
+ if (is_active && clients[client].status.touch_calibration) {
+ const u16 min_x = clients[client].status.touch_calibration->min_x;
+ const u16 max_x = clients[client].status.touch_calibration->max_x;
+ const u16 min_y = clients[client].status.touch_calibration->min_y;
+ const u16 max_y = clients[client].status.touch_calibration->max_y;
- x = (std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) - min_x) /
+ x = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) -
+ min_x) /
static_cast<float>(max_x - min_x);
- y = (std::clamp(static_cast<u16>(data.touch_1.y), min_y, max_y) - min_y) /
+ y = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.y), min_y, max_y) -
+ min_y) /
static_cast<float>(max_y - min_y);
}
- status->touch_status = {x, y, is_active};
+ clients[client].status.touch_status = {x, y, is_active};
+
+ if (configuring) {
+ const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
+ const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
+ UpdateYuzuSettings(client, accelerometer, gyroscope, is_active);
+ }
}
}
-void Client::StartCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id) {
+void Client::StartCommunication(std::size_t client, const std::string& host, u16 port,
+ std::size_t pad_index, u32 client_id) {
SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
[this](Response::PortInfo info) { OnPortInfo(info); },
[this](Response::PadData data) { OnPadData(data); }};
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
- socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
- thread = std::thread{SocketLoop, this->socket.get()};
+ clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
+ clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
+}
+
+void Client::Reset() {
+ for (auto& client : clients) {
+ client.socket->Stop();
+ client.thread.join();
+ }
+}
+
+void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
+ const Common::Vec3<float>& gyro, bool touch) {
+ if (gyro.Length() > 0.2f) {
+ LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}",
+ client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch);
+ }
+ UDPPadStatus pad;
+ if (touch) {
+ pad.touch = PadTouch::Click;
+ pad_queue[client].Push(pad);
+ }
+ for (size_t i = 0; i < 3; ++i) {
+ if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
+ pad.motion = static_cast<PadMotion>(i);
+ pad.motion_value = gyro[i];
+ pad_queue[client].Push(pad);
+ }
+ if (acc[i] > 1.75f || acc[i] < -1.75f) {
+ pad.motion = static_cast<PadMotion>(i + 3);
+ pad.motion_value = acc[i];
+ pad_queue[client].Push(pad);
+ }
+ }
+}
+
+void Client::BeginConfiguration() {
+ for (auto& pq : pad_queue) {
+ pq.Clear();
+ }
+ configuring = true;
+}
+
+void Client::EndConfiguration() {
+ for (auto& pq : pad_queue) {
+ pq.Clear();
+ }
+ configuring = false;
}
-void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id,
- std::function<void()> success_callback,
- std::function<void()> failure_callback) {
+DeviceStatus& Client::GetPadState(std::size_t pad) {
+ return clients[pad].status;
+}
+
+const DeviceStatus& Client::GetPadState(std::size_t pad) const {
+ return clients[pad].status;
+}
+
+std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() {
+ return pad_queue;
+}
+
+const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() const {
+ return pad_queue;
+}
+
+void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
+ const std::function<void()>& success_callback,
+ const std::function<void()>& failure_callback) {
std::thread([=] {
Common::Event success_event;
- SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {},
- [&](Response::PadData data) { success_event.Set(); }};
+ SocketCallback callback{
+ .version = [](Response::Version) {},
+ .port_info = [](Response::PortInfo) {},
+ .pad_data = [&](Response::PadData) { success_event.Set(); },
+ };
Socket socket{host, port, pad_index, client_id, std::move(callback)};
std::thread worker_thread{SocketLoop, &socket};
- bool result = success_event.WaitFor(std::chrono::seconds(8));
+ const bool result = success_event.WaitFor(std::chrono::seconds(8));
socket.Stop();
worker_thread.join();
if (result) {
@@ -228,7 +356,7 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie
}
CalibrationConfigurationJob::CalibrationConfigurationJob(
- const std::string& host, u16 port, u8 pad_index, u32 client_id,
+ const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
std::function<void(Status)> status_callback,
std::function<void(u16, u16, u16, u16)> data_callback) {
@@ -248,7 +376,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
current_status = Status::Ready;
status_callback(current_status);
}
- if (!data.touch_1.is_active) {
+ if (data.touch_1.is_active == 0) {
return;
}
LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x,
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index b8c654755..747e0c0a2 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -12,8 +12,12 @@
#include <thread>
#include <tuple>
#include "common/common_types.h"
+#include "common/param_package.h"
#include "common/thread.h"
+#include "common/threadsafe_queue.h"
#include "common/vector_math.h"
+#include "core/frontend/input.h"
+#include "input_common/motion_input.h"
namespace InputCommon::CemuhookUDP {
@@ -28,9 +32,30 @@ struct PortInfo;
struct Version;
} // namespace Response
+enum class PadMotion {
+ GyroX,
+ GyroY,
+ GyroZ,
+ AccX,
+ AccY,
+ AccZ,
+ Undefined,
+};
+
+enum class PadTouch {
+ Click,
+ Undefined,
+};
+
+struct UDPPadStatus {
+ PadTouch touch{PadTouch::Undefined};
+ PadMotion motion{PadMotion::Undefined};
+ f32 motion_value{0.0f};
+};
+
struct DeviceStatus {
std::mutex update_mutex;
- std::tuple<Common::Vec3<float>, Common::Vec3<float>> motion_status;
+ Input::MotionStatus motion_status;
std::tuple<float, float, bool> touch_status;
// calibration data for scaling the device's touch area to 3ds
@@ -45,22 +70,58 @@ struct DeviceStatus {
class Client {
public:
- explicit Client(std::shared_ptr<DeviceStatus> status, const std::string& host = DEFAULT_ADDR,
- u16 port = DEFAULT_PORT, u8 pad_index = 0, u32 client_id = 24872);
+ // Initialize the UDP client capture and read sequence
+ Client();
+
+ // Close and release the client
~Client();
- void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760, u8 pad_index = 0,
- u32 client_id = 24872);
+
+ // Used for polling
+ void BeginConfiguration();
+ void EndConfiguration();
+
+ std::vector<Common::ParamPackage> GetInputDevices() const;
+
+ bool DeviceConnected(std::size_t pad) const;
+ void ReloadUDPClient();
+ void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760,
+ std::size_t pad_index = 0, u32 client_id = 24872);
+
+ std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue();
+ const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue() const;
+
+ DeviceStatus& GetPadState(std::size_t pad);
+ const DeviceStatus& GetPadState(std::size_t pad) const;
private:
+ struct ClientData {
+ std::unique_ptr<Socket> socket;
+ DeviceStatus status;
+ std::thread thread;
+ u64 packet_sequence = 0;
+ u8 active = 0;
+
+ // Realtime values
+ // motion is initalized with PID values for drift correction on joycons
+ InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f};
+ std::chrono::time_point<std::chrono::system_clock> last_motion_update;
+ };
+
+ // For shutting down, clear all data, join all threads, release usb
+ void Reset();
+
void OnVersion(Response::Version);
void OnPortInfo(Response::PortInfo);
void OnPadData(Response::PadData);
- void StartCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id);
+ void StartCommunication(std::size_t client, const std::string& host, u16 port,
+ std::size_t pad_index, u32 client_id);
+ void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
+ const Common::Vec3<float>& gyro, bool touch);
+
+ bool configuring = false;
- std::unique_ptr<Socket> socket;
- std::shared_ptr<DeviceStatus> status;
- std::thread thread;
- u64 packet_sequence = 0;
+ std::array<ClientData, 4> clients;
+ std::array<Common::SPSCQueue<UDPPadStatus>, 4> pad_queue;
};
/// An async job allowing configuration of the touchpad calibration.
@@ -78,7 +139,7 @@ public:
* @param status_callback Callback for job status updates
* @param data_callback Called when calibration data is ready
*/
- explicit CalibrationConfigurationJob(const std::string& host, u16 port, u8 pad_index,
+ explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index,
u32 client_id, std::function<void(Status)> status_callback,
std::function<void(u16, u16, u16, u16)> data_callback);
~CalibrationConfigurationJob();
@@ -88,8 +149,8 @@ private:
Common::Event complete_event;
};
-void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id,
- std::function<void()> success_callback,
- std::function<void()> failure_callback);
+void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
+ const std::function<void()>& success_callback,
+ const std::function<void()>& failure_callback);
} // namespace InputCommon::CemuhookUDP
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp
index 8c6ef1394..71a76a7aa 100644
--- a/src/input_common/udp/udp.cpp
+++ b/src/input_common/udp/udp.cpp
@@ -1,99 +1,142 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <mutex>
-#include <optional>
-#include <tuple>
-
-#include "common/param_package.h"
-#include "core/frontend/input.h"
-#include "core/settings.h"
+#include <utility>
+#include "common/assert.h"
+#include "common/threadsafe_queue.h"
#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
-namespace InputCommon::CemuhookUDP {
+namespace InputCommon {
-class UDPTouchDevice final : public Input::TouchDevice {
+class UDPMotion final : public Input::MotionDevice {
public:
- explicit UDPTouchDevice(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
- std::tuple<float, float, bool> GetStatus() const override {
- std::lock_guard guard(status->update_mutex);
- return status->touch_status;
+ explicit UDPMotion(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_)
+ : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
+
+ Input::MotionStatus GetStatus() const override {
+ return client->GetPadState(pad).motion_status;
}
private:
- std::shared_ptr<DeviceStatus> status;
+ const std::string ip;
+ const int port;
+ const u32 pad;
+ CemuhookUDP::Client* client;
+ mutable std::mutex mutex;
};
-class UDPMotionDevice final : public Input::MotionDevice {
-public:
- explicit UDPMotionDevice(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
- std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const override {
- std::lock_guard guard(status->update_mutex);
- return status->motion_status;
- }
+/// A motion device factory that creates motion devices from JC Adapter
+UDPMotionFactory::UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_)
+ : client(std::move(client_)) {}
+
+/**
+ * Creates motion device
+ * @param params contains parameters for creating the device:
+ * - "port": the nth jcpad on the adapter
+ */
+std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) {
+ auto ip = params.Get("ip", "127.0.0.1");
+ const auto port = params.Get("port", 26760);
+ const auto pad = static_cast<u32>(params.Get("pad_index", 0));
+
+ return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get());
+}
-private:
- std::shared_ptr<DeviceStatus> status;
-};
+void UDPMotionFactory::BeginConfiguration() {
+ polling = true;
+ client->BeginConfiguration();
+}
-class UDPTouchFactory final : public Input::Factory<Input::TouchDevice> {
-public:
- explicit UDPTouchFactory(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
-
- std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override {
- {
- std::lock_guard guard(status->update_mutex);
- status->touch_calibration = DeviceStatus::CalibrationData{};
- // These default values work well for DS4 but probably not other touch inputs
- status->touch_calibration->min_x = params.Get("min_x", 100);
- status->touch_calibration->min_y = params.Get("min_y", 50);
- status->touch_calibration->max_x = params.Get("max_x", 1800);
- status->touch_calibration->max_y = params.Get("max_y", 850);
+void UDPMotionFactory::EndConfiguration() {
+ polling = false;
+ client->EndConfiguration();
+}
+
+Common::ParamPackage UDPMotionFactory::GetNextInput() {
+ Common::ParamPackage params;
+ CemuhookUDP::UDPPadStatus pad;
+ auto& queue = client->GetPadQueue();
+ for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) {
+ while (queue[pad_number].Pop(pad)) {
+ if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) {
+ continue;
+ }
+ params.Set("engine", "cemuhookudp");
+ params.Set("ip", "127.0.0.1");
+ params.Set("port", 26760);
+ params.Set("pad_index", static_cast<int>(pad_number));
+ params.Set("motion", static_cast<u16>(pad.motion));
+ return params;
}
- return std::make_unique<UDPTouchDevice>(status);
}
+ return params;
+}
-private:
- std::shared_ptr<DeviceStatus> status;
-};
-
-class UDPMotionFactory final : public Input::Factory<Input::MotionDevice> {
+class UDPTouch final : public Input::TouchDevice {
public:
- explicit UDPMotionFactory(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
+ explicit UDPTouch(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_)
+ : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
- std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
- return std::make_unique<UDPMotionDevice>(status);
+ std::tuple<float, float, bool> GetStatus() const override {
+ return client->GetPadState(pad).touch_status;
}
private:
- std::shared_ptr<DeviceStatus> status;
+ const std::string ip;
+ const int port;
+ const u32 pad;
+ CemuhookUDP::Client* client;
+ mutable std::mutex mutex;
};
-State::State() {
- auto status = std::make_shared<DeviceStatus>();
- client =
- std::make_unique<Client>(status, Settings::values.udp_input_address,
- Settings::values.udp_input_port, Settings::values.udp_pad_index);
-
- Input::RegisterFactory<Input::TouchDevice>("cemuhookudp",
- std::make_shared<UDPTouchFactory>(status));
- Input::RegisterFactory<Input::MotionDevice>("cemuhookudp",
- std::make_shared<UDPMotionFactory>(status));
+/// A motion device factory that creates motion devices from JC Adapter
+UDPTouchFactory::UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_)
+ : client(std::move(client_)) {}
+
+/**
+ * Creates motion device
+ * @param params contains parameters for creating the device:
+ * - "port": the nth jcpad on the adapter
+ */
+std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) {
+ auto ip = params.Get("ip", "127.0.0.1");
+ const auto port = params.Get("port", 26760);
+ const auto pad = static_cast<u32>(params.Get("pad_index", 0));
+
+ return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get());
}
-State::~State() {
- Input::UnregisterFactory<Input::TouchDevice>("cemuhookudp");
- Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
+void UDPTouchFactory::BeginConfiguration() {
+ polling = true;
+ client->BeginConfiguration();
}
-void State::ReloadUDPClient() {
- client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port,
- Settings::values.udp_pad_index);
+void UDPTouchFactory::EndConfiguration() {
+ polling = false;
+ client->EndConfiguration();
}
-std::unique_ptr<State> Init() {
- return std::make_unique<State>();
+Common::ParamPackage UDPTouchFactory::GetNextInput() {
+ Common::ParamPackage params;
+ CemuhookUDP::UDPPadStatus pad;
+ auto& queue = client->GetPadQueue();
+ for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) {
+ while (queue[pad_number].Pop(pad)) {
+ if (pad.touch == CemuhookUDP::PadTouch::Undefined) {
+ continue;
+ }
+ params.Set("engine", "cemuhookudp");
+ params.Set("ip", "127.0.0.1");
+ params.Set("port", 26760);
+ params.Set("pad_index", static_cast<int>(pad_number));
+ params.Set("touch", static_cast<u16>(pad.touch));
+ return params;
+ }
+ }
+ return params;
}
-} // namespace InputCommon::CemuhookUDP
+
+} // namespace InputCommon
diff --git a/src/input_common/udp/udp.h b/src/input_common/udp/udp.h
index 4f83f0441..ea3fd4175 100644
--- a/src/input_common/udp/udp.h
+++ b/src/input_common/udp/udp.h
@@ -1,25 +1,57 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
+#include "core/frontend/input.h"
+#include "input_common/udp/client.h"
-namespace InputCommon::CemuhookUDP {
+namespace InputCommon {
-class Client;
-
-class State {
+/// A motion device factory that creates motion devices from udp clients
+class UDPMotionFactory final : public Input::Factory<Input::MotionDevice> {
public:
- State();
- ~State();
- void ReloadUDPClient();
+ explicit UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_);
+
+ std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override;
+
+ Common::ParamPackage GetNextInput();
+
+ /// For device input configuration/polling
+ void BeginConfiguration();
+ void EndConfiguration();
+
+ bool IsPolling() const {
+ return polling;
+ }
private:
- std::unique_ptr<Client> client;
+ std::shared_ptr<CemuhookUDP::Client> client;
+ bool polling = false;
};
-std::unique_ptr<State> Init();
+/// A touch device factory that creates touch devices from udp clients
+class UDPTouchFactory final : public Input::Factory<Input::TouchDevice> {
+public:
+ explicit UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_);
+
+ std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override;
+
+ Common::ParamPackage GetNextInput();
+
+ /// For device input configuration/polling
+ void BeginConfiguration();
+ void EndConfiguration();
+
+ bool IsPolling() const {
+ return polling;
+ }
+
+private:
+ std::shared_ptr<CemuhookUDP::Client> client;
+ bool polling = false;
+};
-} // namespace InputCommon::CemuhookUDP
+} // namespace InputCommon
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 3cd896a0f..3df54816d 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -1,3 +1,5 @@
+add_subdirectory(host_shaders)
+
add_library(video_core STATIC
buffer_cache/buffer_block.h
buffer_cache/buffer_cache.h
@@ -188,6 +190,8 @@ if (ENABLE_VULKAN)
renderer_vulkan/vk_blit_screen.h
renderer_vulkan/vk_buffer_cache.cpp
renderer_vulkan/vk_buffer_cache.h
+ renderer_vulkan/vk_command_pool.cpp
+ renderer_vulkan/vk_command_pool.h
renderer_vulkan/vk_compute_pass.cpp
renderer_vulkan/vk_compute_pass.h
renderer_vulkan/vk_compute_pipeline.cpp
@@ -202,6 +206,8 @@ if (ENABLE_VULKAN)
renderer_vulkan/vk_graphics_pipeline.h
renderer_vulkan/vk_image.cpp
renderer_vulkan/vk_image.h
+ renderer_vulkan/vk_master_semaphore.cpp
+ renderer_vulkan/vk_master_semaphore.h
renderer_vulkan/vk_memory_manager.cpp
renderer_vulkan/vk_memory_manager.h
renderer_vulkan/vk_pipeline_cache.cpp
@@ -212,8 +218,8 @@ if (ENABLE_VULKAN)
renderer_vulkan/vk_rasterizer.h
renderer_vulkan/vk_renderpass_cache.cpp
renderer_vulkan/vk_renderpass_cache.h
- renderer_vulkan/vk_resource_manager.cpp
- renderer_vulkan/vk_resource_manager.h
+ renderer_vulkan/vk_resource_pool.cpp
+ renderer_vulkan/vk_resource_pool.h
renderer_vulkan/vk_sampler_cache.cpp
renderer_vulkan/vk_sampler_cache.h
renderer_vulkan/vk_scheduler.cpp
@@ -244,6 +250,9 @@ create_target_directory_groups(video_core)
target_link_libraries(video_core PUBLIC common core)
target_link_libraries(video_core PRIVATE glad xbyak)
+add_dependencies(video_core host_shaders)
+target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
+
if (ENABLE_VULKAN)
target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
target_compile_definitions(video_core PRIVATE HAS_VULKAN)
@@ -264,5 +273,12 @@ endif()
if (MSVC)
target_compile_options(video_core PRIVATE /we4267)
else()
- target_compile_options(video_core PRIVATE -Werror=conversion -Wno-error=sign-conversion)
+ target_compile_options(video_core PRIVATE
+ -Werror=conversion
+ -Wno-error=sign-conversion
+ -Werror=switch
+ -Werror=unused-variable
+ -Werror=unused-but-set-variable
+ -Werror=class-memaccess
+ )
endif()
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index b5dc68902..e7edd733f 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -51,46 +51,43 @@ public:
bool is_written = false, bool use_fast_cbuf = false) {
std::lock_guard lock{mutex};
- auto& memory_manager = system.GPU().MemoryManager();
- const std::optional<VAddr> cpu_addr_opt = memory_manager.GpuToCpuAddress(gpu_addr);
- if (!cpu_addr_opt) {
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
+ if (!cpu_addr) {
return GetEmptyBuffer(size);
}
- const VAddr cpu_addr = *cpu_addr_opt;
// Cache management is a big overhead, so only cache entries with a given size.
// TODO: Figure out which size is the best for given games.
constexpr std::size_t max_stream_size = 0x800;
if (use_fast_cbuf || size < max_stream_size) {
- if (!is_written && !IsRegionWritten(cpu_addr, cpu_addr + size - 1)) {
- const bool is_granular = memory_manager.IsGranularRange(gpu_addr, size);
+ if (!is_written && !IsRegionWritten(*cpu_addr, *cpu_addr + size - 1)) {
+ const bool is_granular = gpu_memory.IsGranularRange(gpu_addr, size);
if (use_fast_cbuf) {
u8* dest;
if (is_granular) {
- dest = memory_manager.GetPointer(gpu_addr);
+ dest = gpu_memory.GetPointer(gpu_addr);
} else {
staging_buffer.resize(size);
dest = staging_buffer.data();
- memory_manager.ReadBlockUnsafe(gpu_addr, dest, size);
+ gpu_memory.ReadBlockUnsafe(gpu_addr, dest, size);
}
return ConstBufferUpload(dest, size);
}
if (is_granular) {
- u8* const host_ptr = memory_manager.GetPointer(gpu_addr);
+ u8* const host_ptr = gpu_memory.GetPointer(gpu_addr);
return StreamBufferUpload(size, alignment, [host_ptr, size](u8* dest) {
std::memcpy(dest, host_ptr, size);
});
} else {
- return StreamBufferUpload(
- size, alignment, [&memory_manager, gpu_addr, size](u8* dest) {
- memory_manager.ReadBlockUnsafe(gpu_addr, dest, size);
- });
+ return StreamBufferUpload(size, alignment, [this, gpu_addr, size](u8* dest) {
+ gpu_memory.ReadBlockUnsafe(gpu_addr, dest, size);
+ });
}
}
}
- Buffer* const block = GetBlock(cpu_addr, size);
- MapInterval* const map = MapAddress(block, gpu_addr, cpu_addr, size);
+ Buffer* const block = GetBlock(*cpu_addr, size);
+ MapInterval* const map = MapAddress(block, gpu_addr, *cpu_addr, size);
if (!map) {
return GetEmptyBuffer(size);
}
@@ -106,7 +103,7 @@ public:
}
}
- return BufferInfo{block->Handle(), block->Offset(cpu_addr), block->Address()};
+ return BufferInfo{block->Handle(), block->Offset(*cpu_addr), block->Address()};
}
/// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset.
@@ -262,9 +259,11 @@ public:
virtual BufferInfo GetEmptyBuffer(std::size_t size) = 0;
protected:
- explicit BufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
- std::unique_ptr<StreamBuffer> stream_buffer)
- : rasterizer{rasterizer}, system{system}, stream_buffer{std::move(stream_buffer)} {}
+ explicit BufferCache(VideoCore::RasterizerInterface& rasterizer_,
+ Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_,
+ std::unique_ptr<StreamBuffer> stream_buffer_)
+ : rasterizer{rasterizer_}, gpu_memory{gpu_memory_}, cpu_memory{cpu_memory_},
+ stream_buffer{std::move(stream_buffer_)}, stream_buffer_handle{stream_buffer->Handle()} {}
~BufferCache() = default;
@@ -326,14 +325,13 @@ private:
MapInterval* MapAddress(Buffer* block, GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size) {
const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size);
if (overlaps.empty()) {
- auto& memory_manager = system.GPU().MemoryManager();
const VAddr cpu_addr_end = cpu_addr + size;
- if (memory_manager.IsGranularRange(gpu_addr, size)) {
- u8* host_ptr = memory_manager.GetPointer(gpu_addr);
+ if (gpu_memory.IsGranularRange(gpu_addr, size)) {
+ u8* const host_ptr = gpu_memory.GetPointer(gpu_addr);
block->Upload(block->Offset(cpu_addr), size, host_ptr);
} else {
staging_buffer.resize(size);
- memory_manager.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size);
+ gpu_memory.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size);
block->Upload(block->Offset(cpu_addr), size, staging_buffer.data());
}
return Register(MapInterval(cpu_addr, cpu_addr_end, gpu_addr));
@@ -392,7 +390,7 @@ private:
continue;
}
staging_buffer.resize(size);
- system.Memory().ReadBlockUnsafe(interval.lower(), staging_buffer.data(), size);
+ cpu_memory.ReadBlockUnsafe(interval.lower(), staging_buffer.data(), size);
block->Upload(block->Offset(interval.lower()), size, staging_buffer.data());
}
}
@@ -431,7 +429,7 @@ private:
const std::size_t size = map->end - map->start;
staging_buffer.resize(size);
block->Download(block->Offset(map->start), size, staging_buffer.data());
- system.Memory().WriteBlockUnsafe(map->start, staging_buffer.data(), size);
+ cpu_memory.WriteBlockUnsafe(map->start, staging_buffer.data(), size);
map->MarkAsModified(false, 0);
}
@@ -567,7 +565,8 @@ private:
}
VideoCore::RasterizerInterface& rasterizer;
- Core::System& system;
+ Tegra::MemoryManager& gpu_memory;
+ Core::Memory::Memory& cpu_memory;
std::unique_ptr<StreamBuffer> stream_buffer;
BufferType stream_buffer_handle;
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index ff10ff40d..9409c4075 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -10,7 +10,13 @@
namespace Tegra::Engines {
-Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {}
+Fermi2D::Fermi2D() = default;
+
+Fermi2D::~Fermi2D() = default;
+
+void Fermi2D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
+ rasterizer = &rasterizer_;
+}
void Fermi2D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
ASSERT_MSG(method < Regs::NUM_REGS,
@@ -81,13 +87,13 @@ void Fermi2D::HandleSurfaceCopy() {
const Common::Rectangle<u32> src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2};
const Common::Rectangle<u32> dst_rect{regs.blit_dst_x, regs.blit_dst_y, dst_blit_x2,
dst_blit_y2};
- Config copy_config;
- copy_config.operation = regs.operation;
- copy_config.filter = regs.blit_control.filter;
- copy_config.src_rect = src_rect;
- copy_config.dst_rect = dst_rect;
-
- if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) {
+ const Config copy_config{
+ .operation = regs.operation,
+ .filter = regs.blit_control.filter,
+ .src_rect = src_rect,
+ .dst_rect = dst_rect,
+ };
+ if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) {
UNIMPLEMENTED();
}
}
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index 8f37d053f..0909709ec 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -34,8 +34,11 @@ namespace Tegra::Engines {
class Fermi2D final : public EngineInterface {
public:
- explicit Fermi2D(VideoCore::RasterizerInterface& rasterizer);
- ~Fermi2D() = default;
+ explicit Fermi2D();
+ ~Fermi2D();
+
+ /// Binds a rasterizer to this engine.
+ void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
/// Write the value to the register identified by method.
void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
@@ -142,14 +145,14 @@ public:
} regs{};
struct Config {
- Operation operation;
- Filter filter;
+ Operation operation{};
+ Filter filter{};
Common::Rectangle<u32> src_rect;
Common::Rectangle<u32> dst_rect;
};
private:
- VideoCore::RasterizerInterface& rasterizer;
+ VideoCore::RasterizerInterface* rasterizer;
/// Performs the copy from the source surface to the destination surface as configured in the
/// registers.
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index a82b06a38..898370739 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -16,14 +16,15 @@
namespace Tegra::Engines {
-KeplerCompute::KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- MemoryManager& memory_manager)
- : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, upload_state{
- memory_manager,
- regs.upload} {}
+KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_)
+ : system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {}
KeplerCompute::~KeplerCompute() = default;
+void KeplerCompute::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
+ rasterizer = &rasterizer_;
+}
+
void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
ASSERT_MSG(method < Regs::NUM_REGS,
"Invalid KeplerCompute register, increase the size of the Regs structure");
@@ -104,11 +105,11 @@ SamplerDescriptor KeplerCompute::AccessSampler(u32 handle) const {
}
VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() {
- return rasterizer.AccessGuestDriverProfile();
+ return rasterizer->AccessGuestDriverProfile();
}
const VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() const {
- return rasterizer.AccessGuestDriverProfile();
+ return rasterizer->AccessGuestDriverProfile();
}
void KeplerCompute::ProcessLaunch() {
@@ -119,7 +120,7 @@ void KeplerCompute::ProcessLaunch() {
const GPUVAddr code_addr = regs.code_loc.Address() + launch_description.program_start;
LOG_TRACE(HW_GPU, "Compute invocation launched at address 0x{:016x}", code_addr);
- rasterizer.DispatchCompute(code_addr);
+ rasterizer->DispatchCompute(code_addr);
}
Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const {
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h
index b7f668d88..7f2500aab 100644
--- a/src/video_core/engines/kepler_compute.h
+++ b/src/video_core/engines/kepler_compute.h
@@ -42,10 +42,12 @@ namespace Tegra::Engines {
class KeplerCompute final : public ConstBufferEngineInterface, public EngineInterface {
public:
- explicit KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- MemoryManager& memory_manager);
+ explicit KeplerCompute(Core::System& system, MemoryManager& memory_manager);
~KeplerCompute();
+ /// Binds a rasterizer to this engine.
+ void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
+
static constexpr std::size_t NumConstBuffers = 8;
struct Regs {
@@ -230,11 +232,6 @@ public:
const VideoCore::GuestDriverProfile& AccessGuestDriverProfile() const override;
private:
- Core::System& system;
- VideoCore::RasterizerInterface& rasterizer;
- MemoryManager& memory_manager;
- Upload::State upload_state;
-
void ProcessLaunch();
/// Retrieves information about a specific TIC entry from the TIC buffer.
@@ -242,6 +239,11 @@ private:
/// Retrieves information about a specific TSC entry from the TSC buffer.
Texture::TSCEntry GetTSCEntry(u32 tsc_index) const;
+
+ Core::System& system;
+ MemoryManager& memory_manager;
+ VideoCore::RasterizerInterface* rasterizer = nullptr;
+ Upload::State upload_state;
};
#define ASSERT_REG_POSITION(field_name, position) \
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index c01436295..57ebc785f 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -22,14 +22,19 @@ using VideoCore::QueryType;
/// First register id that is actually a Macro call.
constexpr u32 MacroRegistersStart = 0xE00;
-Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- MemoryManager& memory_manager)
- : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager},
- macro_engine{GetMacroEngine(*this)}, upload_state{memory_manager, regs.upload} {
+Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
+ : system{system_}, memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)},
+ upload_state{memory_manager, regs.upload} {
dirty.flags.flip();
InitializeRegisterDefaults();
}
+Maxwell3D::~Maxwell3D() = default;
+
+void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
+ rasterizer = &rasterizer_;
+}
+
void Maxwell3D::InitializeRegisterDefaults() {
// Initializes registers to their default values - what games expect them to be at boot. This is
// for certain registers that may not be explicitly set by games.
@@ -192,7 +197,7 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
switch (method) {
case MAXWELL3D_REG_INDEX(wait_for_idle): {
- rasterizer.WaitForIdle();
+ rasterizer->WaitForIdle();
break;
}
case MAXWELL3D_REG_INDEX(shadow_ram_control): {
@@ -402,7 +407,7 @@ void Maxwell3D::FlushMMEInlineDraw() {
const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed;
if (ShouldExecute()) {
- rasterizer.Draw(is_indexed, true);
+ rasterizer->Draw(is_indexed, true);
}
// TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
@@ -465,7 +470,7 @@ void Maxwell3D::ProcessQueryGet() {
switch (regs.query.query_get.operation) {
case Regs::QueryOperation::Release:
if (regs.query.query_get.fence == 1) {
- rasterizer.SignalSemaphore(regs.query.QueryAddress(), regs.query.query_sequence);
+ rasterizer->SignalSemaphore(regs.query.QueryAddress(), regs.query.query_sequence);
} else {
StampQueryResult(regs.query.query_sequence, regs.query.query_get.short_query == 0);
}
@@ -533,7 +538,7 @@ void Maxwell3D::ProcessQueryCondition() {
void Maxwell3D::ProcessCounterReset() {
switch (regs.counter_reset) {
case Regs::CounterReset::SampleCnt:
- rasterizer.ResetCounter(QueryType::SamplesPassed);
+ rasterizer->ResetCounter(QueryType::SamplesPassed);
break;
default:
LOG_DEBUG(Render_OpenGL, "Unimplemented counter reset={}",
@@ -547,7 +552,7 @@ void Maxwell3D::ProcessSyncPoint() {
const u32 increment = regs.sync_info.increment.Value();
[[maybe_unused]] const u32 cache_flush = regs.sync_info.unknown.Value();
if (increment) {
- rasterizer.SignalSyncPoint(sync_point);
+ rasterizer->SignalSyncPoint(sync_point);
}
}
@@ -570,7 +575,7 @@ void Maxwell3D::DrawArrays() {
const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
if (ShouldExecute()) {
- rasterizer.Draw(is_indexed, false);
+ rasterizer->Draw(is_indexed, false);
}
// TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
@@ -590,9 +595,9 @@ std::optional<u64> Maxwell3D::GetQueryResult() {
return 0;
case Regs::QuerySelect::SamplesPassed:
// Deferred.
- rasterizer.Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed,
- system.GPU().GetTicks());
- return {};
+ rasterizer->Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed,
+ system.GPU().GetTicks());
+ return std::nullopt;
default:
LOG_DEBUG(HW_GPU, "Unimplemented query select type {}",
static_cast<u32>(regs.query.query_get.select.Value()));
@@ -718,7 +723,7 @@ void Maxwell3D::ProcessClearBuffers() {
regs.clear_buffers.R == regs.clear_buffers.B &&
regs.clear_buffers.R == regs.clear_buffers.A);
- rasterizer.Clear();
+ rasterizer->Clear();
}
u32 Maxwell3D::AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const {
@@ -752,11 +757,11 @@ SamplerDescriptor Maxwell3D::AccessSampler(u32 handle) const {
}
VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() {
- return rasterizer.AccessGuestDriverProfile();
+ return rasterizer->AccessGuestDriverProfile();
}
const VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() const {
- return rasterizer.AccessGuestDriverProfile();
+ return rasterizer->AccessGuestDriverProfile();
}
} // namespace Tegra::Engines
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index c97eeb792..bc289c55d 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -51,9 +51,11 @@ namespace Tegra::Engines {
class Maxwell3D final : public ConstBufferEngineInterface, public EngineInterface {
public:
- explicit Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- MemoryManager& memory_manager);
- ~Maxwell3D() = default;
+ explicit Maxwell3D(Core::System& system, MemoryManager& memory_manager);
+ ~Maxwell3D();
+
+ /// Binds a rasterizer to this engine.
+ void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
/// Register structure of the Maxwell3D engine.
/// TODO(Subv): This structure will need to be made bigger as more registers are discovered.
@@ -1418,12 +1420,12 @@ public:
return execute_on;
}
- VideoCore::RasterizerInterface& GetRasterizer() {
- return rasterizer;
+ VideoCore::RasterizerInterface& Rasterizer() {
+ return *rasterizer;
}
- const VideoCore::RasterizerInterface& GetRasterizer() const {
- return rasterizer;
+ const VideoCore::RasterizerInterface& Rasterizer() const {
+ return *rasterizer;
}
/// Notify a memory write has happened.
@@ -1460,11 +1462,10 @@ private:
void InitializeRegisterDefaults();
Core::System& system;
-
- VideoCore::RasterizerInterface& rasterizer;
-
MemoryManager& memory_manager;
+ VideoCore::RasterizerInterface* rasterizer = nullptr;
+
/// Start offsets of each macro in macro_memory
std::array<u32, 0x80> macro_positions = {};
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index e88290754..8fa359d0a 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -114,8 +114,6 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
const u32 block_depth = src_params.block_size.depth;
const size_t src_size =
CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
- const size_t src_layer_size =
- CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth);
if (read_buffer.size() < src_size) {
read_buffer.resize(src_size);
diff --git a/src/video_core/engines/shader_header.h b/src/video_core/engines/shader_header.h
index 72e2a33d5..ceec05459 100644
--- a/src/video_core/engines/shader_header.h
+++ b/src/video_core/engines/shader_header.h
@@ -41,30 +41,30 @@ struct Header {
BitField<26, 1, u32> does_load_or_store;
BitField<27, 1, u32> does_fp64;
BitField<28, 4, u32> stream_out_mask;
- } common0{};
+ } common0;
union {
BitField<0, 24, u32> shader_local_memory_low_size;
BitField<24, 8, u32> per_patch_attribute_count;
- } common1{};
+ } common1;
union {
BitField<0, 24, u32> shader_local_memory_high_size;
BitField<24, 8, u32> threads_per_input_primitive;
- } common2{};
+ } common2;
union {
BitField<0, 24, u32> shader_local_memory_crs_size;
BitField<24, 4, OutputTopology> output_topology;
BitField<28, 4, u32> reserved;
- } common3{};
+ } common3;
union {
BitField<0, 12, u32> max_output_vertices;
BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders.
BitField<20, 4, u32> reserved;
BitField<24, 8, u32> store_req_end; // NOTE: not used by geometry shaders.
- } common4{};
+ } common4;
union {
struct {
@@ -145,7 +145,7 @@ struct Header {
}
} ps;
- std::array<u32, 0xF> raw{};
+ std::array<u32, 0xF> raw;
};
u64 GetLocalMemorySize() const {
@@ -153,7 +153,6 @@ struct Header {
(common2.shader_local_memory_high_size << 24));
}
};
-
static_assert(sizeof(Header) == 0x50, "Incorrect structure size");
} // namespace Tegra::Shader
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index 8b2a6a42c..de6991ef6 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -5,15 +5,10 @@
#pragma once
#include <algorithm>
-#include <array>
-#include <memory>
#include <queue>
-#include "common/assert.h"
#include "common/common_types.h"
#include "core/core.h"
-#include "core/memory.h"
-#include "core/settings.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
@@ -79,8 +74,6 @@ public:
}
void WaitPendingFences() {
- auto& gpu{system.GPU()};
- auto& memory_manager{gpu.MemoryManager()};
while (!fences.empty()) {
TFence& current_fence = fences.front();
if (ShouldWait()) {
@@ -88,8 +81,8 @@ public:
}
PopAsyncFlushes();
if (current_fence->IsSemaphore()) {
- memory_manager.template Write<u32>(current_fence->GetAddress(),
- current_fence->GetPayload());
+ gpu_memory.template Write<u32>(current_fence->GetAddress(),
+ current_fence->GetPayload());
} else {
gpu.IncrementSyncPoint(current_fence->GetPayload());
}
@@ -98,13 +91,13 @@ public:
}
protected:
- FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- TTextureCache& texture_cache, TTBufferCache& buffer_cache,
- TQueryCache& query_cache)
- : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache},
- buffer_cache{buffer_cache}, query_cache{query_cache} {}
+ explicit FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
+ TTextureCache& texture_cache_, TTBufferCache& buffer_cache_,
+ TQueryCache& query_cache_)
+ : rasterizer{rasterizer_}, gpu{gpu_}, gpu_memory{gpu.MemoryManager()},
+ texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, query_cache{query_cache_} {}
- virtual ~FenceManager() {}
+ virtual ~FenceManager() = default;
/// Creates a Sync Point Fence Interface, does not create a backend fence if 'is_stubbed' is
/// true
@@ -118,16 +111,15 @@ protected:
/// Waits until a fence has been signalled by the host GPU.
virtual void WaitFence(TFence& fence) = 0;
- Core::System& system;
VideoCore::RasterizerInterface& rasterizer;
+ Tegra::GPU& gpu;
+ Tegra::MemoryManager& gpu_memory;
TTextureCache& texture_cache;
TTBufferCache& buffer_cache;
TQueryCache& query_cache;
private:
void TryReleasePendingFences() {
- auto& gpu{system.GPU()};
- auto& memory_manager{gpu.MemoryManager()};
while (!fences.empty()) {
TFence& current_fence = fences.front();
if (ShouldWait() && !IsFenceSignaled(current_fence)) {
@@ -135,8 +127,8 @@ private:
}
PopAsyncFlushes();
if (current_fence->IsSemaphore()) {
- memory_manager.template Write<u32>(current_fence->GetAddress(),
- current_fence->GetPayload());
+ gpu_memory.template Write<u32>(current_fence->GetAddress(),
+ current_fence->GetPayload());
} else {
gpu.IncrementSyncPoint(current_fence->GetPayload());
}
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 512578c8b..4bb9256e9 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -27,21 +27,28 @@ namespace Tegra {
MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
-GPU::GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, bool is_async)
- : system{system}, renderer{std::move(renderer_)}, is_async{is_async} {
- auto& rasterizer{renderer->Rasterizer()};
- memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer);
- dma_pusher = std::make_unique<Tegra::DmaPusher>(system, *this);
- maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
- fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer);
- kepler_compute = std::make_unique<Engines::KeplerCompute>(system, rasterizer, *memory_manager);
- maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, *memory_manager);
- kepler_memory = std::make_unique<Engines::KeplerMemory>(system, *memory_manager);
- shader_notify = std::make_unique<VideoCore::ShaderNotify>();
-}
+GPU::GPU(Core::System& system_, bool is_async_)
+ : system{system_}, memory_manager{std::make_unique<Tegra::MemoryManager>(system)},
+ dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)},
+ maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)},
+ fermi_2d{std::make_unique<Engines::Fermi2D>()},
+ kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)},
+ maxwell_dma{std::make_unique<Engines::MaxwellDMA>(system, *memory_manager)},
+ kepler_memory{std::make_unique<Engines::KeplerMemory>(system, *memory_manager)},
+ shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_} {}
GPU::~GPU() = default;
+void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
+ renderer = std::move(renderer_);
+
+ VideoCore::RasterizerInterface& rasterizer = renderer->Rasterizer();
+ memory_manager->BindRasterizer(rasterizer);
+ maxwell_3d->BindRasterizer(rasterizer);
+ fermi_2d->BindRasterizer(rasterizer);
+ kepler_compute->BindRasterizer(rasterizer);
+}
+
Engines::Maxwell3D& GPU::Maxwell3D() {
return *maxwell_3d;
}
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index ebfc7b0c7..2d15d1c6f 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -142,11 +142,6 @@ class MemoryManager;
class GPU {
public:
- explicit GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer,
- bool is_async);
-
- virtual ~GPU();
-
struct MethodCall {
u32 method{};
u32 argument{};
@@ -162,6 +157,12 @@ public:
method_count(method_count) {}
};
+ explicit GPU(Core::System& system, bool is_async);
+ virtual ~GPU();
+
+ /// Binds a renderer to the GPU.
+ void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer);
+
/// Calls a GPU method.
void CallMethod(const MethodCall& method_call);
@@ -345,13 +346,12 @@ private:
bool ExecuteMethodOnEngine(u32 method);
protected:
- std::unique_ptr<Tegra::DmaPusher> dma_pusher;
Core::System& system;
+ std::unique_ptr<Tegra::MemoryManager> memory_manager;
+ std::unique_ptr<Tegra::DmaPusher> dma_pusher;
std::unique_ptr<VideoCore::RendererBase> renderer;
private:
- std::unique_ptr<Tegra::MemoryManager> memory_manager;
-
/// Mapping of command subchannels to their bound engine ids
std::array<EngineID, 8> bound_engines = {};
/// 3D engine
diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp
index 7b855f63e..70a3d5738 100644
--- a/src/video_core/gpu_asynch.cpp
+++ b/src/video_core/gpu_asynch.cpp
@@ -10,16 +10,14 @@
namespace VideoCommon {
-GPUAsynch::GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_,
- std::unique_ptr<Core::Frontend::GraphicsContext>&& context)
- : GPU(system, std::move(renderer_), true), gpu_thread{system},
- cpu_context(renderer->GetRenderWindow().CreateSharedContext()),
- gpu_context(std::move(context)) {}
+GPUAsynch::GPUAsynch(Core::System& system) : GPU{system, true}, gpu_thread{system} {}
GPUAsynch::~GPUAsynch() = default;
void GPUAsynch::Start() {
- gpu_thread.StartThread(*renderer, *gpu_context, *dma_pusher);
+ gpu_thread.StartThread(*renderer, renderer->Context(), *dma_pusher);
+ cpu_context = renderer->GetRenderWindow().CreateSharedContext();
+ cpu_context->MakeCurrent();
}
void GPUAsynch::ObtainContext() {
diff --git a/src/video_core/gpu_asynch.h b/src/video_core/gpu_asynch.h
index 15e9f1d38..f89c855a5 100644
--- a/src/video_core/gpu_asynch.h
+++ b/src/video_core/gpu_asynch.h
@@ -20,8 +20,7 @@ namespace VideoCommon {
/// Implementation of GPU interface that runs the GPU asynchronously
class GPUAsynch final : public Tegra::GPU {
public:
- explicit GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer,
- std::unique_ptr<Core::Frontend::GraphicsContext>&& context);
+ explicit GPUAsynch(Core::System& system);
~GPUAsynch() override;
void Start() override;
@@ -42,7 +41,6 @@ protected:
private:
GPUThread::ThreadManager gpu_thread;
std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context;
- std::unique_ptr<Core::Frontend::GraphicsContext> gpu_context;
};
} // namespace VideoCommon
diff --git a/src/video_core/gpu_synch.cpp b/src/video_core/gpu_synch.cpp
index aaeb9811d..1ca47ddef 100644
--- a/src/video_core/gpu_synch.cpp
+++ b/src/video_core/gpu_synch.cpp
@@ -7,20 +7,18 @@
namespace VideoCommon {
-GPUSynch::GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer,
- std::unique_ptr<Core::Frontend::GraphicsContext>&& context)
- : GPU(system, std::move(renderer), false), context{std::move(context)} {}
+GPUSynch::GPUSynch(Core::System& system) : GPU{system, false} {}
GPUSynch::~GPUSynch() = default;
void GPUSynch::Start() {}
void GPUSynch::ObtainContext() {
- context->MakeCurrent();
+ renderer->Context().MakeCurrent();
}
void GPUSynch::ReleaseContext() {
- context->DoneCurrent();
+ renderer->Context().DoneCurrent();
}
void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) {
diff --git a/src/video_core/gpu_synch.h b/src/video_core/gpu_synch.h
index 762c20aa5..297258cb1 100644
--- a/src/video_core/gpu_synch.h
+++ b/src/video_core/gpu_synch.h
@@ -19,8 +19,7 @@ namespace VideoCommon {
/// Implementation of GPU interface that runs the GPU synchronously
class GPUSynch final : public Tegra::GPU {
public:
- explicit GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer,
- std::unique_ptr<Core::Frontend::GraphicsContext>&& context);
+ explicit GPUSynch(Core::System& system);
~GPUSynch() override;
void Start() override;
@@ -36,9 +35,6 @@ public:
protected:
void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id,
[[maybe_unused]] u32 value) const override {}
-
-private:
- std::unique_ptr<Core::Frontend::GraphicsContext> context;
};
} // namespace VideoCommon
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
new file mode 100644
index 000000000..aa62363a7
--- /dev/null
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -0,0 +1,43 @@
+set(SHADER_FILES
+ opengl_present.frag
+ opengl_present.vert
+)
+
+set(SHADER_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include)
+set(HOST_SHADERS_INCLUDE ${SHADER_INCLUDE} PARENT_SCOPE)
+
+set(SHADER_DIR ${SHADER_INCLUDE}/video_core/host_shaders)
+add_custom_command(
+ OUTPUT
+ ${SHADER_DIR}
+ COMMAND
+ ${CMAKE_COMMAND} -E make_directory ${SHADER_DIR}
+)
+
+set(INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/source_shader.h.in)
+set(HEADER_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/StringShaderHeader.cmake)
+
+foreach(FILENAME IN ITEMS ${SHADER_FILES})
+ string(REPLACE "." "_" SHADER_NAME ${FILENAME})
+ set(SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME})
+ set(HEADER_FILE ${SHADER_DIR}/${SHADER_NAME}.h)
+ add_custom_command(
+ OUTPUT
+ ${HEADER_FILE}
+ COMMAND
+ ${CMAKE_COMMAND} -P ${HEADER_GENERATOR} ${SOURCE_FILE} ${HEADER_FILE} ${INPUT_FILE}
+ MAIN_DEPENDENCY
+ ${SOURCE_FILE}
+ DEPENDS
+ ${HEADER_GENERATOR}
+ ${INPUT_FILE}
+ )
+ set(SHADER_HEADERS ${SHADER_HEADERS} ${HEADER_FILE})
+endforeach()
+
+add_custom_target(host_shaders
+ DEPENDS
+ ${SHADER_HEADERS}
+ SOURCES
+ ${SHADER_FILES}
+)
diff --git a/src/video_core/host_shaders/StringShaderHeader.cmake b/src/video_core/host_shaders/StringShaderHeader.cmake
new file mode 100644
index 000000000..368bce0ed
--- /dev/null
+++ b/src/video_core/host_shaders/StringShaderHeader.cmake
@@ -0,0 +1,11 @@
+set(SOURCE_FILE ${CMAKE_ARGV3})
+set(HEADER_FILE ${CMAKE_ARGV4})
+set(INPUT_FILE ${CMAKE_ARGV5})
+
+get_filename_component(CONTENTS_NAME ${SOURCE_FILE} NAME)
+string(REPLACE "." "_" CONTENTS_NAME ${CONTENTS_NAME})
+string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME)
+
+file(READ ${SOURCE_FILE} CONTENTS)
+
+configure_file(${INPUT_FILE} ${HEADER_FILE} @ONLY)
diff --git a/src/video_core/host_shaders/opengl_present.frag b/src/video_core/host_shaders/opengl_present.frag
new file mode 100644
index 000000000..8a4cb024b
--- /dev/null
+++ b/src/video_core/host_shaders/opengl_present.frag
@@ -0,0 +1,10 @@
+#version 430 core
+
+layout (location = 0) in vec2 frag_tex_coord;
+layout (location = 0) out vec4 color;
+
+layout (binding = 0) uniform sampler2D color_texture;
+
+void main() {
+ color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f);
+}
diff --git a/src/video_core/host_shaders/opengl_present.vert b/src/video_core/host_shaders/opengl_present.vert
new file mode 100644
index 000000000..2235d31a4
--- /dev/null
+++ b/src/video_core/host_shaders/opengl_present.vert
@@ -0,0 +1,24 @@
+#version 430 core
+
+out gl_PerVertex {
+ vec4 gl_Position;
+};
+
+layout (location = 0) in vec2 vert_position;
+layout (location = 1) in vec2 vert_tex_coord;
+layout (location = 0) out vec2 frag_tex_coord;
+
+// This is a truncated 3x3 matrix for 2D transformations:
+// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
+// The third column performs translation.
+// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
+// implicitly be [0, 0, 1]
+layout (location = 0) uniform mat3x2 modelview_matrix;
+
+void main() {
+ // Multiply input position by the rotscale part of the matrix and then manually translate by
+ // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
+ // to `vec3(vert_position.xy, 1.0)`
+ gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
+ frag_tex_coord = vert_tex_coord;
+}
diff --git a/src/video_core/host_shaders/source_shader.h.in b/src/video_core/host_shaders/source_shader.h.in
new file mode 100644
index 000000000..ccdb0d2a9
--- /dev/null
+++ b/src/video_core/host_shaders/source_shader.h.in
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <string_view>
+
+namespace HostShaders {
+
+constexpr std::string_view @CONTENTS_NAME@ = R"(@CONTENTS@)";
+
+} // namespace HostShaders
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp
index a50e7b4e0..cd21a2112 100644
--- a/src/video_core/macro/macro.cpp
+++ b/src/video_core/macro/macro.cpp
@@ -36,7 +36,7 @@ void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method,
}
} else {
// Macro not compiled, check if it's uploaded and if so, compile it
- std::optional<u32> mid_method = std::nullopt;
+ std::optional<u32> mid_method;
const auto macro_code = uploaded_macro_code.find(method);
if (macro_code == uploaded_macro_code.end()) {
for (const auto& [method_base, code] : uploaded_macro_code) {
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp
index 0c9ff59a4..df00b57df 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -24,7 +24,7 @@ void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
maxwell3d.regs.index_array.first = parameters[4];
if (maxwell3d.ShouldExecute()) {
- maxwell3d.GetRasterizer().Draw(true, true);
+ maxwell3d.Rasterizer().Draw(true, true);
}
maxwell3d.regs.index_array.count = 0;
maxwell3d.mme_draw.instance_count = 0;
@@ -42,7 +42,7 @@ void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
maxwell3d.mme_draw.instance_count = count;
if (maxwell3d.ShouldExecute()) {
- maxwell3d.GetRasterizer().Draw(false, true);
+ maxwell3d.Rasterizer().Draw(false, true);
}
maxwell3d.regs.vertex_buffer.count = 0;
maxwell3d.mme_draw.instance_count = 0;
@@ -65,7 +65,7 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
maxwell3d.regs.draw.topology.Assign(
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
if (maxwell3d.ShouldExecute()) {
- maxwell3d.GetRasterizer().Draw(true, true);
+ maxwell3d.Rasterizer().Draw(true, true);
}
maxwell3d.regs.reg_array[0x446] = 0x0; // vertex id base?
maxwell3d.regs.index_array.count = 0;
diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp
index aa5256419..bd01fd1f2 100644
--- a/src/video_core/macro/macro_interpreter.cpp
+++ b/src/video_core/macro/macro_interpreter.cpp
@@ -34,7 +34,6 @@ void MacroInterpreterImpl::Execute(const std::vector<u32>& parameters, u32 metho
this->parameters = std::make_unique<u32[]>(num_parameters);
}
std::memcpy(this->parameters.get(), parameters.data(), num_parameters * sizeof(u32));
- this->num_parameters = num_parameters;
// Execute the code until we hit an exit condition.
bool keep_executing = true;
diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp
index c1b9e4ad9..954b87515 100644
--- a/src/video_core/macro/macro_jit_x64.cpp
+++ b/src/video_core/macro/macro_jit_x64.cpp
@@ -14,11 +14,11 @@ MICROPROFILE_DEFINE(MacroJitCompile, "GPU", "Compile macro JIT", MP_RGB(173, 255
MICROPROFILE_DEFINE(MacroJitExecute, "GPU", "Execute macro JIT", MP_RGB(255, 255, 0));
namespace Tegra {
-static const Xbyak::Reg64 STATE = Xbyak::util::rbx;
-static const Xbyak::Reg32 RESULT = Xbyak::util::ebp;
-static const Xbyak::Reg64 PARAMETERS = Xbyak::util::r12;
-static const Xbyak::Reg32 METHOD_ADDRESS = Xbyak::util::r14d;
-static const Xbyak::Reg64 BRANCH_HOLDER = Xbyak::util::r15;
+constexpr Xbyak::Reg64 STATE = Xbyak::util::rbx;
+constexpr Xbyak::Reg32 RESULT = Xbyak::util::ebp;
+constexpr Xbyak::Reg64 PARAMETERS = Xbyak::util::r12;
+constexpr Xbyak::Reg32 METHOD_ADDRESS = Xbyak::util::r14d;
+constexpr Xbyak::Reg64 BRANCH_HOLDER = Xbyak::util::r15;
static const std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({
STATE,
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 844164645..02cf53d15 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -14,11 +14,15 @@
namespace Tegra {
-MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
- : system{system}, rasterizer{rasterizer}, page_table(page_table_size) {}
+MemoryManager::MemoryManager(Core::System& system_)
+ : system{system_}, page_table(page_table_size) {}
MemoryManager::~MemoryManager() = default;
+void MemoryManager::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
+ rasterizer = &rasterizer_;
+}
+
GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size) {
u64 remaining_size{size};
for (u64 offset{}; offset < size; offset += page_size) {
@@ -54,7 +58,7 @@ void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) {
std::optional<GPUVAddr> MemoryManager::AllocateFixed(GPUVAddr gpu_addr, std::size_t size) {
for (u64 offset{}; offset < size; offset += page_size) {
if (!GetPageEntry(gpu_addr + offset).IsUnmapped()) {
- return {};
+ return std::nullopt;
}
}
@@ -131,13 +135,13 @@ std::optional<GPUVAddr> MemoryManager::FindFreeRange(std::size_t size, std::size
}
}
- return {};
+ return std::nullopt;
}
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const {
const auto page_entry{GetPageEntry(gpu_addr)};
if (!page_entry.IsValid()) {
- return {};
+ return std::nullopt;
}
return page_entry.ToAddress() + (gpu_addr & page_mask);
@@ -217,7 +221,7 @@ void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::siz
// Flush must happen on the rasterizer interface, such that memory is always synchronous
// when it is read (even when in asynchronous GPU mode). Fixes Dead Cells title menu.
- rasterizer.FlushRegion(src_addr, copy_amount);
+ rasterizer->FlushRegion(src_addr, copy_amount);
system.Memory().ReadBlockUnsafe(src_addr, dest_buffer, copy_amount);
}
@@ -266,7 +270,7 @@ void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, s
// Invalidate must happen on the rasterizer interface, such that memory is always
// synchronous when it is written (even when in asynchronous GPU mode).
- rasterizer.InvalidateRegion(dest_addr, copy_amount);
+ rasterizer->InvalidateRegion(dest_addr, copy_amount);
system.Memory().WriteBlockUnsafe(dest_addr, src_buffer, copy_amount);
}
@@ -312,10 +316,10 @@ void MemoryManager::CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_add
WriteBlockUnsafe(gpu_dest_addr, tmp_buffer.data(), size);
}
-bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) {
+bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const {
const auto cpu_addr{GpuToCpuAddress(gpu_addr)};
if (!cpu_addr) {
- return {};
+ return false;
}
const std::size_t page{(*cpu_addr & Core::Memory::PAGE_MASK) + size};
return page <= Core::Memory::PAGE_SIZE;
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 681bd9588..53c8d122a 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -31,19 +31,19 @@ public:
constexpr PageEntry(State state) : state{state} {}
constexpr PageEntry(VAddr addr) : state{static_cast<State>(addr >> ShiftBits)} {}
- constexpr bool IsUnmapped() const {
+ [[nodiscard]] constexpr bool IsUnmapped() const {
return state == State::Unmapped;
}
- constexpr bool IsAllocated() const {
+ [[nodiscard]] constexpr bool IsAllocated() const {
return state == State::Allocated;
}
- constexpr bool IsValid() const {
+ [[nodiscard]] constexpr bool IsValid() const {
return !IsUnmapped() && !IsAllocated();
}
- constexpr VAddr ToAddress() const {
+ [[nodiscard]] constexpr VAddr ToAddress() const {
if (!IsValid()) {
return {};
}
@@ -51,7 +51,7 @@ public:
return static_cast<VAddr>(state) << ShiftBits;
}
- constexpr PageEntry operator+(u64 offset) {
+ [[nodiscard]] constexpr PageEntry operator+(u64 offset) const {
// If this is a reserved value, offsets do not apply
if (!IsValid()) {
return *this;
@@ -68,19 +68,22 @@ static_assert(sizeof(PageEntry) == 4, "PageEntry is too large");
class MemoryManager final {
public:
- explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
+ explicit MemoryManager(Core::System& system);
~MemoryManager();
- std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
+ /// Binds a renderer to the memory manager.
+ void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
+
+ [[nodiscard]] std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
template <typename T>
- T Read(GPUVAddr addr) const;
+ [[nodiscard]] T Read(GPUVAddr addr) const;
template <typename T>
void Write(GPUVAddr addr, T data);
- u8* GetPointer(GPUVAddr addr);
- const u8* GetPointer(GPUVAddr addr) const;
+ [[nodiscard]] u8* GetPointer(GPUVAddr addr);
+ [[nodiscard]] const u8* GetPointer(GPUVAddr addr) const;
/**
* ReadBlock and WriteBlock are full read and write operations over virtual
@@ -109,24 +112,24 @@ public:
/**
* IsGranularRange checks if a gpu region can be simply read with a pointer.
*/
- bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size);
+ [[nodiscard]] bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const;
- GPUVAddr Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size);
- GPUVAddr MapAllocate(VAddr cpu_addr, std::size_t size, std::size_t align);
- std::optional<GPUVAddr> AllocateFixed(GPUVAddr gpu_addr, std::size_t size);
- GPUVAddr Allocate(std::size_t size, std::size_t align);
+ [[nodiscard]] GPUVAddr Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size);
+ [[nodiscard]] GPUVAddr MapAllocate(VAddr cpu_addr, std::size_t size, std::size_t align);
+ [[nodiscard]] std::optional<GPUVAddr> AllocateFixed(GPUVAddr gpu_addr, std::size_t size);
+ [[nodiscard]] GPUVAddr Allocate(std::size_t size, std::size_t align);
void Unmap(GPUVAddr gpu_addr, std::size_t size);
private:
- PageEntry GetPageEntry(GPUVAddr gpu_addr) const;
+ [[nodiscard]] PageEntry GetPageEntry(GPUVAddr gpu_addr) const;
void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size);
GPUVAddr UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size);
- std::optional<GPUVAddr> FindFreeRange(std::size_t size, std::size_t align) const;
+ [[nodiscard]] std::optional<GPUVAddr> FindFreeRange(std::size_t size, std::size_t align) const;
void TryLockPage(PageEntry page_entry, std::size_t size);
void TryUnlockPage(PageEntry page_entry, std::size_t size);
- static constexpr std::size_t PageEntryIndex(GPUVAddr gpu_addr) {
+ [[nodiscard]] static constexpr std::size_t PageEntryIndex(GPUVAddr gpu_addr) {
return (gpu_addr >> page_bits) & page_table_mask;
}
@@ -141,7 +144,7 @@ private:
Core::System& system;
- VideoCore::RasterizerInterface& rasterizer;
+ VideoCore::RasterizerInterface* rasterizer = nullptr;
std::vector<PageEntry> page_table;
};
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index 0d3a88765..fc54ca0ef 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -91,14 +91,15 @@ private:
std::shared_ptr<HostCounter> last;
};
-template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter,
- class QueryPool>
+template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter>
class QueryCacheBase {
public:
- explicit QueryCacheBase(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
- : system{system}, rasterizer{rasterizer}, streams{{CounterStream{
- static_cast<QueryCache&>(*this),
- VideoCore::QueryType::SamplesPassed}}} {}
+ explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_,
+ Tegra::Engines::Maxwell3D& maxwell3d_,
+ Tegra::MemoryManager& gpu_memory_)
+ : rasterizer{rasterizer_}, maxwell3d{maxwell3d_},
+ gpu_memory{gpu_memory_}, streams{{CounterStream{static_cast<QueryCache&>(*this),
+ VideoCore::QueryType::SamplesPassed}}} {}
void InvalidateRegion(VAddr addr, std::size_t size) {
std::unique_lock lock{mutex};
@@ -118,29 +119,27 @@ public:
*/
void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) {
std::unique_lock lock{mutex};
- auto& memory_manager = system.GPU().MemoryManager();
- const std::optional<VAddr> cpu_addr_opt = memory_manager.GpuToCpuAddress(gpu_addr);
- ASSERT(cpu_addr_opt);
- VAddr cpu_addr = *cpu_addr_opt;
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
+ ASSERT(cpu_addr);
- CachedQuery* query = TryGet(cpu_addr);
+ CachedQuery* query = TryGet(*cpu_addr);
if (!query) {
- ASSERT_OR_EXECUTE(cpu_addr_opt, return;);
- const auto host_ptr = memory_manager.GetPointer(gpu_addr);
+ ASSERT_OR_EXECUTE(cpu_addr, return;);
+ u8* const host_ptr = gpu_memory.GetPointer(gpu_addr);
- query = Register(type, cpu_addr, host_ptr, timestamp.has_value());
+ query = Register(type, *cpu_addr, host_ptr, timestamp.has_value());
}
query->BindCounter(Stream(type).Current(), timestamp);
if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
- AsyncFlushQuery(cpu_addr);
+ AsyncFlushQuery(*cpu_addr);
}
}
/// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch.
void UpdateCounters() {
std::unique_lock lock{mutex};
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
Stream(VideoCore::QueryType::SamplesPassed).Update(regs.samplecnt_enable);
}
@@ -206,9 +205,6 @@ public:
committed_flushes.pop_front();
}
-protected:
- std::array<QueryPool, VideoCore::NumQueryTypes> query_pools;
-
private:
/// Flushes a memory range to guest memory and removes it from the cache.
void FlushAndRemoveRegion(VAddr addr, std::size_t size) {
@@ -270,8 +266,9 @@ private:
static constexpr std::uintptr_t PAGE_SIZE = 4096;
static constexpr unsigned PAGE_BITS = 12;
- Core::System& system;
VideoCore::RasterizerInterface& rasterizer;
+ Tegra::Engines::Maxwell3D& maxwell3d;
+ Tegra::MemoryManager& gpu_memory;
std::recursive_mutex mutex;
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 3cbdac8e7..b3e0919f8 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -106,11 +106,8 @@ public:
virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
/// Initialize disk cached resources for the game being emulated
- virtual void LoadDiskResources(const std::atomic_bool& stop_loading = false,
- const DiskResourceLoadCallback& callback = {}) {}
-
- /// Initializes renderer dirty flags
- virtual void SetupDirtyFlags() {}
+ virtual void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading,
+ const DiskResourceLoadCallback& callback) {}
/// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver.
GuestDriverProfile& AccessGuestDriverProfile() {
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index dfb06e87e..a93a1732c 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -9,7 +9,9 @@
namespace VideoCore {
-RendererBase::RendererBase(Core::Frontend::EmuWindow& window) : render_window{window} {
+RendererBase::RendererBase(Core::Frontend::EmuWindow& window_,
+ std::unique_ptr<Core::Frontend::GraphicsContext> context_)
+ : render_window{window_}, context{std::move(context_)} {
RefreshBaseSettings();
}
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 1d85219b6..5c650808b 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -15,7 +15,8 @@
namespace Core::Frontend {
class EmuWindow;
-}
+class GraphicsContext;
+} // namespace Core::Frontend
namespace VideoCore {
@@ -25,14 +26,15 @@ struct RendererSettings {
// Screenshot
std::atomic<bool> screenshot_requested{false};
- void* screenshot_bits;
+ void* screenshot_bits{};
std::function<void()> screenshot_complete_callback;
Layout::FramebufferLayout screenshot_framebuffer_layout;
};
class RendererBase : NonCopyable {
public:
- explicit RendererBase(Core::Frontend::EmuWindow& window);
+ explicit RendererBase(Core::Frontend::EmuWindow& window,
+ std::unique_ptr<Core::Frontend::GraphicsContext> context);
virtual ~RendererBase();
/// Initialize the renderer
@@ -44,11 +46,6 @@ public:
/// Finalize rendering the guest frame and draw into the presentation texture
virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0;
- /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer
- /// specific implementation)
- /// Returns true if a frame was drawn
- virtual bool TryPresent(int timeout_ms) = 0;
-
// Getter/setter functions:
// ------------------------
@@ -68,6 +65,14 @@ public:
return *rasterizer;
}
+ Core::Frontend::GraphicsContext& Context() {
+ return *context;
+ }
+
+ const Core::Frontend::GraphicsContext& Context() const {
+ return *context;
+ }
+
Core::Frontend::EmuWindow& GetRenderWindow() {
return render_window;
}
@@ -94,6 +99,7 @@ public:
protected:
Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
std::unique_ptr<RasterizerInterface> rasterizer;
+ std::unique_ptr<Core::Frontend::GraphicsContext> context;
f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
int m_current_frame = 0; ///< Current frame, should be set by the renderer
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index e866d8f2f..b1c4cd62f 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -59,9 +59,10 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst
static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size));
}
-OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
+OGLBufferCache::OGLBufferCache(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
const Device& device_, std::size_t stream_size)
- : GenericBufferCache{rasterizer, system,
+ : GenericBufferCache{rasterizer, gpu_memory, cpu_memory,
std::make_unique<OGLStreamBuffer>(device_, stream_size, true)},
device{device_} {
if (!device.HasFastBufferSubData()) {
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 88fdc0536..f75b32e31 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -52,7 +52,8 @@ private:
using GenericBufferCache = VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>;
class OGLBufferCache final : public GenericBufferCache {
public:
- explicit OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
+ explicit OGLBufferCache(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
const Device& device, std::size_t stream_size);
~OGLBufferCache();
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index e7d95149f..a94e4f72e 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -193,7 +193,6 @@ bool IsASTCSupported() {
Device::Device()
: max_uniform_buffers{BuildMaxUniformBuffers()}, base_bindings{BuildBaseBindings()} {
const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
- const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
const std::vector extensions = GetExtensions();
diff --git a/src/video_core/renderer_opengl/gl_fence_manager.cpp b/src/video_core/renderer_opengl/gl_fence_manager.cpp
index ec5421afa..b532fdcc2 100644
--- a/src/video_core/renderer_opengl/gl_fence_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_fence_manager.cpp
@@ -4,16 +4,17 @@
#include "common/assert.h"
+#include <glad/glad.h>
+
#include "video_core/renderer_opengl/gl_buffer_cache.h"
#include "video_core/renderer_opengl/gl_fence_manager.h"
namespace OpenGL {
-GLInnerFence::GLInnerFence(u32 payload, bool is_stubbed)
- : VideoCommon::FenceBase(payload, is_stubbed), sync_object{} {}
+GLInnerFence::GLInnerFence(u32 payload, bool is_stubbed) : FenceBase(payload, is_stubbed) {}
GLInnerFence::GLInnerFence(GPUVAddr address, u32 payload, bool is_stubbed)
- : VideoCommon::FenceBase(address, payload, is_stubbed), sync_object{} {}
+ : FenceBase(address, payload, is_stubbed) {}
GLInnerFence::~GLInnerFence() = default;
@@ -44,11 +45,10 @@ void GLInnerFence::Wait() {
glClientWaitSync(sync_object.handle, 0, GL_TIMEOUT_IGNORED);
}
-FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system,
- VideoCore::RasterizerInterface& rasterizer,
+FenceManagerOpenGL::FenceManagerOpenGL(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu,
TextureCacheOpenGL& texture_cache,
OGLBufferCache& buffer_cache, QueryCache& query_cache)
- : GenericFenceManager(system, rasterizer, texture_cache, buffer_cache, query_cache) {}
+ : GenericFenceManager{rasterizer, gpu, texture_cache, buffer_cache, query_cache} {}
Fence FenceManagerOpenGL::CreateFence(u32 value, bool is_stubbed) {
return std::make_shared<GLInnerFence>(value, is_stubbed);
diff --git a/src/video_core/renderer_opengl/gl_fence_manager.h b/src/video_core/renderer_opengl/gl_fence_manager.h
index c917b3343..da1dcdace 100644
--- a/src/video_core/renderer_opengl/gl_fence_manager.h
+++ b/src/video_core/renderer_opengl/gl_fence_manager.h
@@ -5,7 +5,6 @@
#pragma once
#include <memory>
-#include <glad/glad.h>
#include "common/common_types.h"
#include "video_core/fence_manager.h"
@@ -38,9 +37,9 @@ using GenericFenceManager =
class FenceManagerOpenGL final : public GenericFenceManager {
public:
- FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache,
- QueryCache& query_cache);
+ explicit FenceManagerOpenGL(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu,
+ TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache,
+ QueryCache& query_cache);
protected:
Fence CreateFence(u32 value, bool is_stubbed) override;
diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp
index d7ba57aca..1a3d9720e 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_query_cache.cpp
@@ -30,12 +30,11 @@ constexpr GLenum GetTarget(VideoCore::QueryType type) {
} // Anonymous namespace
-QueryCache::QueryCache(Core::System& system, RasterizerOpenGL& gl_rasterizer)
- : VideoCommon::QueryCacheBase<
- QueryCache, CachedQuery, CounterStream, HostCounter,
- std::vector<OGLQuery>>{system,
- static_cast<VideoCore::RasterizerInterface&>(gl_rasterizer)},
- gl_rasterizer{gl_rasterizer} {}
+QueryCache::QueryCache(RasterizerOpenGL& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d,
+ Tegra::MemoryManager& gpu_memory)
+ : VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter>(
+ rasterizer, maxwell3d, gpu_memory),
+ gl_rasterizer{rasterizer} {}
QueryCache::~QueryCache() = default;
@@ -90,6 +89,8 @@ u64 HostCounter::BlockingQuery() const {
CachedQuery::CachedQuery(QueryCache& cache, VideoCore::QueryType type, VAddr cpu_addr, u8* host_ptr)
: VideoCommon::CachedQueryBase<HostCounter>{cpu_addr, host_ptr}, cache{&cache}, type{type} {}
+CachedQuery::~CachedQuery() = default;
+
CachedQuery::CachedQuery(CachedQuery&& rhs) noexcept
: VideoCommon::CachedQueryBase<HostCounter>(std::move(rhs)), cache{rhs.cache}, type{rhs.type} {}
diff --git a/src/video_core/renderer_opengl/gl_query_cache.h b/src/video_core/renderer_opengl/gl_query_cache.h
index d8e7052a1..82cac51ee 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.h
+++ b/src/video_core/renderer_opengl/gl_query_cache.h
@@ -26,10 +26,11 @@ class RasterizerOpenGL;
using CounterStream = VideoCommon::CounterStreamBase<QueryCache, HostCounter>;
-class QueryCache final : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream,
- HostCounter, std::vector<OGLQuery>> {
+class QueryCache final
+ : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> {
public:
- explicit QueryCache(Core::System& system, RasterizerOpenGL& rasterizer);
+ explicit QueryCache(RasterizerOpenGL& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d,
+ Tegra::MemoryManager& gpu_memory);
~QueryCache();
OGLQuery AllocateQuery(VideoCore::QueryType type);
@@ -40,6 +41,7 @@ public:
private:
RasterizerOpenGL& gl_rasterizer;
+ std::array<std::vector<OGLQuery>, VideoCore::NumQueryTypes> query_pools;
};
class HostCounter final : public VideoCommon::HostCounterBase<QueryCache, HostCounter> {
@@ -62,10 +64,12 @@ class CachedQuery final : public VideoCommon::CachedQueryBase<HostCounter> {
public:
explicit CachedQuery(QueryCache& cache, VideoCore::QueryType type, VAddr cpu_addr,
u8* host_ptr);
- CachedQuery(CachedQuery&& rhs) noexcept;
- CachedQuery(const CachedQuery&) = delete;
+ ~CachedQuery() override;
+ CachedQuery(CachedQuery&& rhs) noexcept;
CachedQuery& operator=(CachedQuery&& rhs) noexcept;
+
+ CachedQuery(const CachedQuery&) = delete;
CachedQuery& operator=(const CachedQuery&) = delete;
void Flush() override;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 4af5824cd..bbb2eb17c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -153,16 +153,19 @@ void UpdateBindlessPointers(GLenum target, GLuint64EXT* pointers, std::size_t nu
} // Anonymous namespace
-RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
- const Device& device, ScreenInfo& info,
- ProgramManager& program_manager, StateTracker& state_tracker)
- : RasterizerAccelerated{system.Memory()}, device{device}, texture_cache{system, *this, device,
- state_tracker},
- shader_cache{*this, system, emu_window, device}, query_cache{system, *this},
- buffer_cache{*this, system, device, STREAM_BUFFER_SIZE},
- fence_manager{system, *this, texture_cache, buffer_cache, query_cache}, system{system},
- screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker},
- async_shaders{emu_window} {
+RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu_,
+ Core::Memory::Memory& cpu_memory, const Device& device_,
+ ScreenInfo& screen_info_, ProgramManager& program_manager_,
+ StateTracker& state_tracker_)
+ : RasterizerAccelerated{cpu_memory}, gpu(gpu_), maxwell3d(gpu.Maxwell3D()),
+ kepler_compute(gpu.KeplerCompute()), gpu_memory(gpu.MemoryManager()), device(device_),
+ screen_info(screen_info_), program_manager(program_manager_), state_tracker(state_tracker_),
+ texture_cache(*this, maxwell3d, gpu_memory, device, state_tracker),
+ shader_cache(*this, emu_window, gpu, maxwell3d, kepler_compute, gpu_memory, device),
+ query_cache(*this, maxwell3d, gpu_memory),
+ buffer_cache(*this, gpu_memory, cpu_memory, device, STREAM_BUFFER_SIZE),
+ fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache),
+ async_shaders(emu_window) {
CheckExtensions();
unified_uniform_buffer.Create();
@@ -196,8 +199,7 @@ void RasterizerOpenGL::CheckExtensions() {
}
void RasterizerOpenGL::SetupVertexFormat() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::VertexFormats]) {
return;
}
@@ -217,7 +219,7 @@ void RasterizerOpenGL::SetupVertexFormat() {
}
flags[Dirty::VertexFormat0 + index] = false;
- const auto attrib = gpu.regs.vertex_attrib_format[index];
+ const auto attrib = maxwell3d.regs.vertex_attrib_format[index];
const auto gl_index = static_cast<GLuint>(index);
// Disable constant attributes.
@@ -241,8 +243,7 @@ void RasterizerOpenGL::SetupVertexFormat() {
}
void RasterizerOpenGL::SetupVertexBuffer() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::VertexBuffers]) {
return;
}
@@ -253,7 +254,7 @@ void RasterizerOpenGL::SetupVertexBuffer() {
const bool use_unified_memory = device.HasVertexBufferUnifiedMemory();
// Upload all guest vertex arrays sequentially to our buffer
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_BINDINGS; ++index) {
if (!flags[Dirty::VertexBuffer0 + index]) {
continue;
@@ -290,14 +291,13 @@ void RasterizerOpenGL::SetupVertexBuffer() {
}
void RasterizerOpenGL::SetupVertexInstances() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::VertexInstances]) {
return;
}
flags[Dirty::VertexInstances] = false;
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) {
if (!flags[Dirty::VertexInstance0 + index]) {
continue;
@@ -313,7 +313,7 @@ void RasterizerOpenGL::SetupVertexInstances() {
GLintptr RasterizerOpenGL::SetupIndexBuffer() {
MICROPROFILE_SCOPE(OpenGL_Index);
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
const std::size_t size = CalculateIndexBufferSize();
const auto info = buffer_cache.UploadMemory(regs.index_array.IndexStart(), size);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, info.handle);
@@ -322,15 +322,14 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer() {
void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
MICROPROFILE_SCOPE(OpenGL_Shader);
- auto& gpu = system.GPU().Maxwell3D();
u32 clip_distances = 0;
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
- const auto& shader_config = gpu.regs.shader_config[index];
+ const auto& shader_config = maxwell3d.regs.shader_config[index];
const auto program{static_cast<Maxwell::ShaderProgram>(index)};
// Skip stages that are not enabled
- if (!gpu.regs.IsShaderConfigEnabled(index)) {
+ if (!maxwell3d.regs.IsShaderConfigEnabled(index)) {
switch (program) {
case Maxwell::ShaderProgram::Geometry:
program_manager.UseGeometryShader(0);
@@ -391,11 +390,11 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
}
SyncClipEnabled(clip_distances);
- gpu.dirty.flags[Dirty::Shaders] = false;
+ maxwell3d.dirty.flags[Dirty::Shaders] = false;
}
std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
std::size_t size = 0;
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
@@ -413,34 +412,27 @@ std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
}
std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const {
- const auto& regs = system.GPU().Maxwell3D().regs;
-
- return static_cast<std::size_t>(regs.index_array.count) *
- static_cast<std::size_t>(regs.index_array.FormatSizeInBytes());
+ return static_cast<std::size_t>(maxwell3d.regs.index_array.count) *
+ static_cast<std::size_t>(maxwell3d.regs.index_array.FormatSizeInBytes());
}
-void RasterizerOpenGL::LoadDiskResources(const std::atomic_bool& stop_loading,
+void RasterizerOpenGL::LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) {
- shader_cache.LoadDiskCache(stop_loading, callback);
-}
-
-void RasterizerOpenGL::SetupDirtyFlags() {
- state_tracker.Initialize();
+ shader_cache.LoadDiskCache(title_id, stop_loading, callback);
}
void RasterizerOpenGL::ConfigureFramebuffers() {
MICROPROFILE_SCOPE(OpenGL_Framebuffer);
- auto& gpu = system.GPU().Maxwell3D();
- if (!gpu.dirty.flags[VideoCommon::Dirty::RenderTargets]) {
+ if (!maxwell3d.dirty.flags[VideoCommon::Dirty::RenderTargets]) {
return;
}
- gpu.dirty.flags[VideoCommon::Dirty::RenderTargets] = false;
+ maxwell3d.dirty.flags[VideoCommon::Dirty::RenderTargets] = false;
texture_cache.GuardRenderTargets(true);
View depth_surface = texture_cache.GetDepthBufferSurface(true);
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0);
// Bind the framebuffer surfaces
@@ -472,8 +464,7 @@ void RasterizerOpenGL::ConfigureFramebuffers() {
}
void RasterizerOpenGL::ConfigureClearFramebuffer(bool using_color, bool using_depth_stencil) {
- auto& gpu = system.GPU().Maxwell3D();
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
texture_cache.GuardRenderTargets(true);
View color_surface;
@@ -523,12 +514,11 @@ void RasterizerOpenGL::ConfigureClearFramebuffer(bool using_color, bool using_de
}
void RasterizerOpenGL::Clear() {
- const auto& gpu = system.GPU().Maxwell3D();
- if (!gpu.ShouldExecute()) {
+ if (!maxwell3d.ShouldExecute()) {
return;
}
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
bool use_color{};
bool use_depth{};
bool use_stencil{};
@@ -593,7 +583,6 @@ void RasterizerOpenGL::Clear() {
void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
MICROPROFILE_SCOPE(OpenGL_Drawing);
- auto& gpu = system.GPU().Maxwell3D();
query_cache.UpdateCounters();
@@ -641,7 +630,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
if (invalidated) {
// When the stream buffer has been invalidated, we have to consider vertex buffers as dirty
- auto& dirty = gpu.dirty.flags;
+ auto& dirty = maxwell3d.dirty.flags;
dirty[Dirty::VertexBuffers] = true;
for (int index = Dirty::VertexBuffer0; index <= Dirty::VertexBuffer31; ++index) {
dirty[index] = true;
@@ -662,7 +651,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
// Setup emulation uniform buffer.
if (!device.UseAssemblyShaders()) {
MaxwellUniformData ubo;
- ubo.SetFromRegs(gpu);
+ ubo.SetFromRegs(maxwell3d);
const auto info =
buffer_cache.UploadHostMemory(&ubo, sizeof(ubo), device.GetUniformBufferAlignment());
glBindBufferRange(GL_UNIFORM_BUFFER, EmulationUniformBlockBinding, info.handle, info.offset,
@@ -671,7 +660,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
// Setup shaders and their used resources.
texture_cache.GuardSamplers(true);
- const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(gpu.regs.draw.topology);
+ const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d.regs.draw.topology);
SetupShaders(primitive_mode);
texture_cache.GuardSamplers(false);
@@ -688,14 +677,14 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
BeginTransformFeedback(primitive_mode);
- const GLuint base_instance = static_cast<GLuint>(gpu.regs.vb_base_instance);
+ const GLuint base_instance = static_cast<GLuint>(maxwell3d.regs.vb_base_instance);
const GLsizei num_instances =
- static_cast<GLsizei>(is_instanced ? gpu.mme_draw.instance_count : 1);
+ static_cast<GLsizei>(is_instanced ? maxwell3d.mme_draw.instance_count : 1);
if (is_indexed) {
- const GLint base_vertex = static_cast<GLint>(gpu.regs.vb_element_base);
- const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.index_array.count);
+ const GLint base_vertex = static_cast<GLint>(maxwell3d.regs.vb_element_base);
+ const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d.regs.index_array.count);
const GLvoid* offset = reinterpret_cast<const GLvoid*>(index_buffer_offset);
- const GLenum format = MaxwellToGL::IndexFormat(gpu.regs.index_array.format);
+ const GLenum format = MaxwellToGL::IndexFormat(maxwell3d.regs.index_array.format);
if (num_instances == 1 && base_instance == 0 && base_vertex == 0) {
glDrawElements(primitive_mode, num_vertices, format, offset);
} else if (num_instances == 1 && base_instance == 0) {
@@ -714,8 +703,8 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
base_instance);
}
} else {
- const GLint base_vertex = static_cast<GLint>(gpu.regs.vertex_buffer.first);
- const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.vertex_buffer.count);
+ const GLint base_vertex = static_cast<GLint>(maxwell3d.regs.vertex_buffer.first);
+ const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d.regs.vertex_buffer.count);
if (num_instances == 1 && base_instance == 0) {
glDrawArrays(primitive_mode, base_vertex, num_vertices);
} else if (base_instance == 0) {
@@ -730,7 +719,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
++num_queued_commands;
- system.GPU().TickWork();
+ gpu.TickWork();
}
void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
@@ -753,7 +742,8 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
buffer_cache.Unmap();
- const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
+ const auto& launch_desc = kepler_compute.launch_description;
+ program_manager.BindCompute(kernel->GetHandle());
glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z);
++num_queued_commands;
}
@@ -815,17 +805,14 @@ void RasterizerOpenGL::SyncGuestHost() {
}
void RasterizerOpenGL::SignalSemaphore(GPUVAddr addr, u32 value) {
- auto& gpu{system.GPU()};
if (!gpu.IsAsync()) {
- auto& memory_manager{gpu.MemoryManager()};
- memory_manager.Write<u32>(addr, value);
+ gpu_memory.Write<u32>(addr, value);
return;
}
fence_manager.SignalSemaphore(addr, value);
}
void RasterizerOpenGL::SignalSyncPoint(u32 value) {
- auto& gpu{system.GPU()};
if (!gpu.IsAsync()) {
gpu.IncrementSyncPoint(value);
return;
@@ -834,7 +821,6 @@ void RasterizerOpenGL::SignalSyncPoint(u32 value) {
}
void RasterizerOpenGL::ReleaseFences() {
- auto& gpu{system.GPU()};
if (!gpu.IsAsync()) {
return;
}
@@ -920,7 +906,7 @@ void RasterizerOpenGL::SetupDrawConstBuffers(std::size_t stage_index, Shader* sh
GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV};
MICROPROFILE_SCOPE(OpenGL_UBO);
- const auto& stages = system.GPU().Maxwell3D().state.shader_stages;
+ const auto& stages = maxwell3d.state.shader_stages;
const auto& shader_stage = stages[stage_index];
const auto& entries = shader->GetEntries();
const bool use_unified = entries.use_unified_uniforms;
@@ -945,7 +931,7 @@ void RasterizerOpenGL::SetupDrawConstBuffers(std::size_t stage_index, Shader* sh
void RasterizerOpenGL::SetupComputeConstBuffers(Shader* kernel) {
MICROPROFILE_SCOPE(OpenGL_UBO);
- const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
+ const auto& launch_desc = kepler_compute.launch_description;
const auto& entries = kernel->GetEntries();
const bool use_unified = entries.use_unified_uniforms;
@@ -1018,9 +1004,7 @@ void RasterizerOpenGL::SetupDrawGlobalMemory(std::size_t stage_index, Shader* sh
GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV,
};
- auto& gpu{system.GPU()};
- auto& memory_manager{gpu.MemoryManager()};
- const auto& cbufs{gpu.Maxwell3D().state.shader_stages[stage_index]};
+ const auto& cbufs{maxwell3d.state.shader_stages[stage_index]};
const auto& entries{shader->GetEntries().global_memory_entries};
std::array<GLuint64EXT, 32> pointers;
@@ -1030,8 +1014,8 @@ void RasterizerOpenGL::SetupDrawGlobalMemory(std::size_t stage_index, Shader* sh
u32 binding = assembly_shaders ? 0 : device.GetBaseBindings(stage_index).shader_storage_buffer;
for (const auto& entry : entries) {
const GPUVAddr addr{cbufs.const_buffers[entry.cbuf_index].address + entry.cbuf_offset};
- const GPUVAddr gpu_addr{memory_manager.Read<u64>(addr)};
- const u32 size{memory_manager.Read<u32>(addr + 8)};
+ const GPUVAddr gpu_addr{gpu_memory.Read<u64>(addr)};
+ const u32 size{gpu_memory.Read<u32>(addr + 8)};
SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]);
++binding;
}
@@ -1041,9 +1025,7 @@ void RasterizerOpenGL::SetupDrawGlobalMemory(std::size_t stage_index, Shader* sh
}
void RasterizerOpenGL::SetupComputeGlobalMemory(Shader* kernel) {
- auto& gpu{system.GPU()};
- auto& memory_manager{gpu.MemoryManager()};
- const auto& cbufs{gpu.KeplerCompute().launch_description.const_buffer_config};
+ const auto& cbufs{kepler_compute.launch_description.const_buffer_config};
const auto& entries{kernel->GetEntries().global_memory_entries};
std::array<GLuint64EXT, 32> pointers;
@@ -1052,8 +1034,8 @@ void RasterizerOpenGL::SetupComputeGlobalMemory(Shader* kernel) {
u32 binding = 0;
for (const auto& entry : entries) {
const GPUVAddr addr{cbufs[entry.cbuf_index].Address() + entry.cbuf_offset};
- const GPUVAddr gpu_addr{memory_manager.Read<u64>(addr)};
- const u32 size{memory_manager.Read<u32>(addr + 8)};
+ const GPUVAddr gpu_addr{gpu_memory.Read<u64>(addr)};
+ const u32 size{gpu_memory.Read<u32>(addr + 8)};
SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]);
++binding;
}
@@ -1077,7 +1059,6 @@ void RasterizerOpenGL::SetupGlobalMemory(u32 binding, const GlobalMemoryEntry& e
void RasterizerOpenGL::SetupDrawTextures(std::size_t stage_index, Shader* shader) {
MICROPROFILE_SCOPE(OpenGL_Texture);
- const auto& maxwell3d = system.GPU().Maxwell3D();
u32 binding = device.GetBaseBindings(stage_index).sampler;
for (const auto& entry : shader->GetEntries().samplers) {
const auto shader_type = static_cast<ShaderType>(stage_index);
@@ -1090,11 +1071,10 @@ void RasterizerOpenGL::SetupDrawTextures(std::size_t stage_index, Shader* shader
void RasterizerOpenGL::SetupComputeTextures(Shader* kernel) {
MICROPROFILE_SCOPE(OpenGL_Texture);
- const auto& compute = system.GPU().KeplerCompute();
u32 binding = 0;
for (const auto& entry : kernel->GetEntries().samplers) {
for (std::size_t i = 0; i < entry.size; ++i) {
- const auto texture = GetTextureInfo(compute, entry, ShaderType::Compute, i);
+ const auto texture = GetTextureInfo(kepler_compute, entry, ShaderType::Compute, i);
SetupTexture(binding++, texture, entry);
}
}
@@ -1118,20 +1098,18 @@ void RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextu
}
void RasterizerOpenGL::SetupDrawImages(std::size_t stage_index, Shader* shader) {
- const auto& maxwell3d = system.GPU().Maxwell3D();
u32 binding = device.GetBaseBindings(stage_index).image;
for (const auto& entry : shader->GetEntries().images) {
- const auto shader_type = static_cast<Tegra::Engines::ShaderType>(stage_index);
+ const auto shader_type = static_cast<ShaderType>(stage_index);
const auto tic = GetTextureInfo(maxwell3d, entry, shader_type).tic;
SetupImage(binding++, tic, entry);
}
}
void RasterizerOpenGL::SetupComputeImages(Shader* shader) {
- const auto& compute = system.GPU().KeplerCompute();
u32 binding = 0;
for (const auto& entry : shader->GetEntries().images) {
- const auto tic = GetTextureInfo(compute, entry, Tegra::Engines::ShaderType::Compute).tic;
+ const auto tic = GetTextureInfo(kepler_compute, entry, ShaderType::Compute).tic;
SetupImage(binding++, tic, entry);
}
}
@@ -1151,9 +1129,8 @@ void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& t
}
void RasterizerOpenGL::SyncViewport() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
- const auto& regs = gpu.regs;
+ auto& flags = maxwell3d.dirty.flags;
+ const auto& regs = maxwell3d.regs;
const bool dirty_viewport = flags[Dirty::Viewports];
const bool dirty_clip_control = flags[Dirty::ClipControl];
@@ -1225,25 +1202,23 @@ void RasterizerOpenGL::SyncViewport() {
}
void RasterizerOpenGL::SyncDepthClamp() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::DepthClampEnabled]) {
return;
}
flags[Dirty::DepthClampEnabled] = false;
- oglEnable(GL_DEPTH_CLAMP, gpu.regs.view_volume_clip_control.depth_clamp_disabled == 0);
+ oglEnable(GL_DEPTH_CLAMP, maxwell3d.regs.view_volume_clip_control.depth_clamp_disabled == 0);
}
void RasterizerOpenGL::SyncClipEnabled(u32 clip_mask) {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::ClipDistances] && !flags[Dirty::Shaders]) {
return;
}
flags[Dirty::ClipDistances] = false;
- clip_mask &= gpu.regs.clip_distance_enabled;
+ clip_mask &= maxwell3d.regs.clip_distance_enabled;
if (clip_mask == last_clip_distance_mask) {
return;
}
@@ -1259,9 +1234,8 @@ void RasterizerOpenGL::SyncClipCoef() {
}
void RasterizerOpenGL::SyncCullMode() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
- const auto& regs = gpu.regs;
+ auto& flags = maxwell3d.dirty.flags;
+ const auto& regs = maxwell3d.regs;
if (flags[Dirty::CullTest]) {
flags[Dirty::CullTest] = false;
@@ -1276,26 +1250,24 @@ void RasterizerOpenGL::SyncCullMode() {
}
void RasterizerOpenGL::SyncPrimitiveRestart() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::PrimitiveRestart]) {
return;
}
flags[Dirty::PrimitiveRestart] = false;
- if (gpu.regs.primitive_restart.enabled) {
+ if (maxwell3d.regs.primitive_restart.enabled) {
glEnable(GL_PRIMITIVE_RESTART);
- glPrimitiveRestartIndex(gpu.regs.primitive_restart.index);
+ glPrimitiveRestartIndex(maxwell3d.regs.primitive_restart.index);
} else {
glDisable(GL_PRIMITIVE_RESTART);
}
}
void RasterizerOpenGL::SyncDepthTestState() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
+ const auto& regs = maxwell3d.regs;
- const auto& regs = gpu.regs;
if (flags[Dirty::DepthMask]) {
flags[Dirty::DepthMask] = false;
glDepthMask(regs.depth_write_enabled ? GL_TRUE : GL_FALSE);
@@ -1313,14 +1285,13 @@ void RasterizerOpenGL::SyncDepthTestState() {
}
void RasterizerOpenGL::SyncStencilTestState() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::StencilTest]) {
return;
}
flags[Dirty::StencilTest] = false;
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
oglEnable(GL_STENCIL_TEST, regs.stencil_enable);
glStencilFuncSeparate(GL_FRONT, MaxwellToGL::ComparisonOp(regs.stencil_front_func_func),
@@ -1345,25 +1316,24 @@ void RasterizerOpenGL::SyncStencilTestState() {
}
void RasterizerOpenGL::SyncRasterizeEnable() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::RasterizeEnable]) {
return;
}
flags[Dirty::RasterizeEnable] = false;
- oglEnable(GL_RASTERIZER_DISCARD, gpu.regs.rasterize_enable == 0);
+ oglEnable(GL_RASTERIZER_DISCARD, maxwell3d.regs.rasterize_enable == 0);
}
void RasterizerOpenGL::SyncPolygonModes() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::PolygonModes]) {
return;
}
flags[Dirty::PolygonModes] = false;
- if (gpu.regs.fill_rectangle) {
+ const auto& regs = maxwell3d.regs;
+ if (regs.fill_rectangle) {
if (!GLAD_GL_NV_fill_rectangle) {
LOG_ERROR(Render_OpenGL, "GL_NV_fill_rectangle used and not supported");
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@@ -1376,27 +1346,26 @@ void RasterizerOpenGL::SyncPolygonModes() {
return;
}
- if (gpu.regs.polygon_mode_front == gpu.regs.polygon_mode_back) {
+ if (regs.polygon_mode_front == regs.polygon_mode_back) {
flags[Dirty::PolygonModeFront] = false;
flags[Dirty::PolygonModeBack] = false;
- glPolygonMode(GL_FRONT_AND_BACK, MaxwellToGL::PolygonMode(gpu.regs.polygon_mode_front));
+ glPolygonMode(GL_FRONT_AND_BACK, MaxwellToGL::PolygonMode(regs.polygon_mode_front));
return;
}
if (flags[Dirty::PolygonModeFront]) {
flags[Dirty::PolygonModeFront] = false;
- glPolygonMode(GL_FRONT, MaxwellToGL::PolygonMode(gpu.regs.polygon_mode_front));
+ glPolygonMode(GL_FRONT, MaxwellToGL::PolygonMode(regs.polygon_mode_front));
}
if (flags[Dirty::PolygonModeBack]) {
flags[Dirty::PolygonModeBack] = false;
- glPolygonMode(GL_BACK, MaxwellToGL::PolygonMode(gpu.regs.polygon_mode_back));
+ glPolygonMode(GL_BACK, MaxwellToGL::PolygonMode(regs.polygon_mode_back));
}
}
void RasterizerOpenGL::SyncColorMask() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::ColorMasks]) {
return;
}
@@ -1405,7 +1374,7 @@ void RasterizerOpenGL::SyncColorMask() {
const bool force = flags[Dirty::ColorMaskCommon];
flags[Dirty::ColorMaskCommon] = false;
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
if (regs.color_mask_common) {
if (!force && !flags[Dirty::ColorMask0]) {
return;
@@ -1430,33 +1399,30 @@ void RasterizerOpenGL::SyncColorMask() {
}
void RasterizerOpenGL::SyncMultiSampleState() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::MultisampleControl]) {
return;
}
flags[Dirty::MultisampleControl] = false;
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
oglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE, regs.multisample_control.alpha_to_coverage);
oglEnable(GL_SAMPLE_ALPHA_TO_ONE, regs.multisample_control.alpha_to_one);
}
void RasterizerOpenGL::SyncFragmentColorClampState() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::FragmentClampColor]) {
return;
}
flags[Dirty::FragmentClampColor] = false;
- glClampColor(GL_CLAMP_FRAGMENT_COLOR, gpu.regs.frag_color_clamp ? GL_TRUE : GL_FALSE);
+ glClampColor(GL_CLAMP_FRAGMENT_COLOR, maxwell3d.regs.frag_color_clamp ? GL_TRUE : GL_FALSE);
}
void RasterizerOpenGL::SyncBlendState() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
- const auto& regs = gpu.regs;
+ auto& flags = maxwell3d.dirty.flags;
+ const auto& regs = maxwell3d.regs;
if (flags[Dirty::BlendColor]) {
flags[Dirty::BlendColor] = false;
@@ -1513,14 +1479,13 @@ void RasterizerOpenGL::SyncBlendState() {
}
void RasterizerOpenGL::SyncLogicOpState() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::LogicOp]) {
return;
}
flags[Dirty::LogicOp] = false;
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
if (regs.logic_op.enable) {
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(MaxwellToGL::LogicOp(regs.logic_op.operation));
@@ -1530,14 +1495,13 @@ void RasterizerOpenGL::SyncLogicOpState() {
}
void RasterizerOpenGL::SyncScissorTest() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::Scissors]) {
return;
}
flags[Dirty::Scissors] = false;
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
for (std::size_t index = 0; index < Maxwell::NumViewports; ++index) {
if (!flags[Dirty::Scissor0 + index]) {
continue;
@@ -1556,16 +1520,15 @@ void RasterizerOpenGL::SyncScissorTest() {
}
void RasterizerOpenGL::SyncPointState() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::PointSize]) {
return;
}
flags[Dirty::PointSize] = false;
- oglEnable(GL_POINT_SPRITE, gpu.regs.point_sprite_enable);
+ oglEnable(GL_POINT_SPRITE, maxwell3d.regs.point_sprite_enable);
- if (gpu.regs.vp_point_size.enable) {
+ if (maxwell3d.regs.vp_point_size.enable) {
// By definition of GL_POINT_SIZE, it only matters if GL_PROGRAM_POINT_SIZE is disabled.
glEnable(GL_PROGRAM_POINT_SIZE);
return;
@@ -1573,32 +1536,30 @@ void RasterizerOpenGL::SyncPointState() {
// Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid
// in OpenGL).
- glPointSize(std::max(1.0f, gpu.regs.point_size));
+ glPointSize(std::max(1.0f, maxwell3d.regs.point_size));
glDisable(GL_PROGRAM_POINT_SIZE);
}
void RasterizerOpenGL::SyncLineState() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::LineWidth]) {
return;
}
flags[Dirty::LineWidth] = false;
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
oglEnable(GL_LINE_SMOOTH, regs.line_smooth_enable);
glLineWidth(regs.line_smooth_enable ? regs.line_width_smooth : regs.line_width_aliased);
}
void RasterizerOpenGL::SyncPolygonOffset() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::PolygonOffset]) {
return;
}
flags[Dirty::PolygonOffset] = false;
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
oglEnable(GL_POLYGON_OFFSET_FILL, regs.polygon_offset_fill_enable);
oglEnable(GL_POLYGON_OFFSET_LINE, regs.polygon_offset_line_enable);
oglEnable(GL_POLYGON_OFFSET_POINT, regs.polygon_offset_point_enable);
@@ -1612,14 +1573,13 @@ void RasterizerOpenGL::SyncPolygonOffset() {
}
void RasterizerOpenGL::SyncAlphaTest() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::AlphaTest]) {
return;
}
flags[Dirty::AlphaTest] = false;
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
if (regs.alpha_test_enabled && regs.rt_control.count > 1) {
LOG_WARNING(Render_OpenGL, "Alpha testing with more than one render target is not tested");
}
@@ -1633,20 +1593,19 @@ void RasterizerOpenGL::SyncAlphaTest() {
}
void RasterizerOpenGL::SyncFramebufferSRGB() {
- auto& gpu = system.GPU().Maxwell3D();
- auto& flags = gpu.dirty.flags;
+ auto& flags = maxwell3d.dirty.flags;
if (!flags[Dirty::FramebufferSRGB]) {
return;
}
flags[Dirty::FramebufferSRGB] = false;
- oglEnable(GL_FRAMEBUFFER_SRGB, gpu.regs.framebuffer_srgb);
+ oglEnable(GL_FRAMEBUFFER_SRGB, maxwell3d.regs.framebuffer_srgb);
}
void RasterizerOpenGL::SyncTransformFeedback() {
// TODO(Rodrigo): Inject SKIP_COMPONENTS*_NV when required. An unimplemented message will signal
// when this is required.
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
static constexpr std::size_t STRIDE = 3;
std::array<GLint, 128 * STRIDE * Maxwell::NumTransformFeedbackBuffers> attribs;
@@ -1698,7 +1657,7 @@ void RasterizerOpenGL::SyncTransformFeedback() {
}
void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) {
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
if (regs.tfb_enabled == 0) {
return;
}
@@ -1741,7 +1700,7 @@ void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) {
}
void RasterizerOpenGL::EndTransformFeedback() {
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
if (regs.tfb_enabled == 0) {
return;
}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index ccc6f50f6..f451404b2 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -36,8 +36,8 @@
#include "video_core/shader/async_shaders.h"
#include "video_core/textures/texture.h"
-namespace Core {
-class System;
+namespace Core::Memory {
+class Memory;
}
namespace Core::Frontend {
@@ -55,9 +55,10 @@ struct DrawParameters;
class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
public:
- explicit RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
- const Device& device, ScreenInfo& info,
- ProgramManager& program_manager, StateTracker& state_tracker);
+ explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
+ Core::Memory::Memory& cpu_memory, const Device& device,
+ ScreenInfo& screen_info, ProgramManager& program_manager,
+ StateTracker& state_tracker);
~RasterizerOpenGL() override;
void Draw(bool is_indexed, bool is_instanced) override;
@@ -83,9 +84,8 @@ public:
const Tegra::Engines::Fermi2D::Config& copy_config) override;
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
u32 pixel_stride) override;
- void LoadDiskResources(const std::atomic_bool& stop_loading,
+ void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) override;
- void SetupDirtyFlags() override;
/// Returns true when there are commands queued to the OpenGL server.
bool AnyCommandQueued() const {
@@ -237,7 +237,15 @@ private:
void SetupShaders(GLenum primitive_mode);
+ Tegra::GPU& gpu;
+ Tegra::Engines::Maxwell3D& maxwell3d;
+ Tegra::Engines::KeplerCompute& kepler_compute;
+ Tegra::MemoryManager& gpu_memory;
+
const Device& device;
+ ScreenInfo& screen_info;
+ ProgramManager& program_manager;
+ StateTracker& state_tracker;
TextureCacheOpenGL texture_cache;
ShaderCacheOpenGL shader_cache;
@@ -247,10 +255,6 @@ private:
OGLBufferCache buffer_cache;
FenceManagerOpenGL fence_manager;
- Core::System& system;
- ScreenInfo& screen_info;
- ProgramManager& program_manager;
- StateTracker& state_tracker;
VideoCommon::Shader::AsyncShaders async_shaders;
static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
index a787e27d2..0ebcec427 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <string_view>
#include <utility>
#include <glad/glad.h>
#include "common/common_types.h"
@@ -82,11 +83,13 @@ void OGLSampler::Release() {
handle = 0;
}
-void OGLShader::Create(const char* source, GLenum type) {
- if (handle != 0)
+void OGLShader::Create(std::string_view source, GLenum type) {
+ if (handle != 0) {
return;
- if (source == nullptr)
+ }
+ if (source.empty()) {
return;
+ }
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
handle = GLShader::LoadShader(source, type);
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index b05cb641c..f48398669 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -4,6 +4,7 @@
#pragma once
+#include <string_view>
#include <utility>
#include <glad/glad.h>
#include "common/common_types.h"
@@ -127,7 +128,7 @@ public:
return *this;
}
- void Create(const char* source, GLenum type);
+ void Create(std::string_view source, GLenum type);
void Release();
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index eb49a36bf..bd56bed0c 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -22,6 +22,7 @@
#include "video_core/memory_manager.h"
#include "video_core/renderer_opengl/gl_arb_decompiler.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
+#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_shader_cache.h"
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
#include "video_core/renderer_opengl/gl_shader_disk_cache.h"
@@ -238,12 +239,11 @@ std::unique_ptr<Shader> Shader::CreateStageFromMemory(
ProgramCode code_b, VideoCommon::Shader::AsyncShaders& async_shaders, VAddr cpu_addr) {
const auto shader_type = GetShaderType(program_type);
- auto& gpu = params.system.GPU();
+ auto& gpu = params.gpu;
gpu.ShaderNotify().MarkSharderBuilding();
auto registry = std::make_shared<Registry>(shader_type, gpu.Maxwell3D());
- if (!async_shaders.IsShaderAsync(params.system.GPU()) ||
- !params.device.UseAsynchronousShaders()) {
+ if (!async_shaders.IsShaderAsync(gpu) || !params.device.UseAsynchronousShaders()) {
const ShaderIR ir(code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, *registry);
// TODO(Rodrigo): Handle VertexA shaders
// std::optional<ShaderIR> ir_b;
@@ -286,11 +286,10 @@ std::unique_ptr<Shader> Shader::CreateStageFromMemory(
std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& params,
ProgramCode code) {
- auto& gpu = params.system.GPU();
+ auto& gpu = params.gpu;
gpu.ShaderNotify().MarkSharderBuilding();
- auto& engine = gpu.KeplerCompute();
- auto registry = std::make_shared<Registry>(ShaderType::Compute, engine);
+ auto registry = std::make_shared<Registry>(ShaderType::Compute, params.engine);
const ShaderIR ir(code, KERNEL_MAIN_OFFSET, COMPILER_SETTINGS, *registry);
const u64 uid = params.unique_identifier;
auto program = BuildShader(params.device, ShaderType::Compute, uid, ir, *registry);
@@ -319,15 +318,20 @@ std::unique_ptr<Shader> Shader::CreateFromCache(const ShaderParameters& params,
precompiled_shader.registry, precompiled_shader.entries, precompiled_shader.program));
}
-ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
- Core::Frontend::EmuWindow& emu_window, const Device& device)
- : VideoCommon::ShaderCache<Shader>{rasterizer}, system{system},
- emu_window{emu_window}, device{device}, disk_cache{system} {}
+ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer,
+ Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
+ Tegra::Engines::Maxwell3D& maxwell3d_,
+ Tegra::Engines::KeplerCompute& kepler_compute_,
+ Tegra::MemoryManager& gpu_memory_, const Device& device_)
+ : VideoCommon::ShaderCache<Shader>{rasterizer}, emu_window{emu_window_}, gpu{gpu_},
+ gpu_memory{gpu_memory_}, maxwell3d{maxwell3d_},
+ kepler_compute{kepler_compute_}, device{device_} {}
ShaderCacheOpenGL::~ShaderCacheOpenGL() = default;
-void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
+void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) {
+ disk_cache.BindTitleID(title_id);
const std::optional transferable = disk_cache.LoadTransferable();
if (!transferable) {
return;
@@ -480,21 +484,19 @@ ProgramSharedPtr ShaderCacheOpenGL::GeneratePrecompiledProgram(
Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program,
VideoCommon::Shader::AsyncShaders& async_shaders) {
- if (!system.GPU().Maxwell3D().dirty.flags[Dirty::Shaders]) {
+ if (!maxwell3d.dirty.flags[Dirty::Shaders]) {
auto* last_shader = last_shaders[static_cast<std::size_t>(program)];
if (last_shader->IsBuilt()) {
return last_shader;
}
}
- auto& memory_manager{system.GPU().MemoryManager()};
- const GPUVAddr address{GetShaderAddress(system, program)};
+ const GPUVAddr address{GetShaderAddress(maxwell3d, program)};
if (device.UseAsynchronousShaders() && async_shaders.HasCompletedWork()) {
auto completed_work = async_shaders.GetCompletedWork();
for (auto& work : completed_work) {
Shader* shader = TryGet(work.cpu_address);
- auto& gpu = system.GPU();
gpu.ShaderNotify().MarkShaderComplete();
if (shader == nullptr) {
continue;
@@ -506,14 +508,13 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program,
shader->AsyncGLASMBuilt(std::move(work.program.glasm));
}
+ auto& registry = shader->GetRegistry();
+
ShaderDiskCacheEntry entry;
entry.type = work.shader_type;
entry.code = std::move(work.code);
entry.code_b = std::move(work.code_b);
entry.unique_identifier = work.uid;
-
- auto& registry = shader->GetRegistry();
-
entry.bound_buffer = registry.GetBoundBuffer();
entry.graphics_info = registry.GetGraphicsInfo();
entry.keys = registry.GetKeys();
@@ -524,28 +525,28 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program,
}
// Look up shader in the cache based on address
- const auto cpu_addr{memory_manager.GpuToCpuAddress(address)};
+ const std::optional<VAddr> cpu_addr{gpu_memory.GpuToCpuAddress(address)};
if (Shader* const shader{cpu_addr ? TryGet(*cpu_addr) : null_shader.get()}) {
return last_shaders[static_cast<std::size_t>(program)] = shader;
}
- const auto host_ptr{memory_manager.GetPointer(address)};
+ const u8* const host_ptr{gpu_memory.GetPointer(address)};
// No shader found - create a new one
- ProgramCode code{GetShaderCode(memory_manager, address, host_ptr, false)};
+ ProgramCode code{GetShaderCode(gpu_memory, address, host_ptr, false)};
ProgramCode code_b;
if (program == Maxwell::ShaderProgram::VertexA) {
- const GPUVAddr address_b{GetShaderAddress(system, Maxwell::ShaderProgram::VertexB)};
- const u8* host_ptr_b = memory_manager.GetPointer(address_b);
- code_b = GetShaderCode(memory_manager, address_b, host_ptr_b, false);
+ const GPUVAddr address_b{GetShaderAddress(maxwell3d, Maxwell::ShaderProgram::VertexB)};
+ const u8* host_ptr_b = gpu_memory.GetPointer(address_b);
+ code_b = GetShaderCode(gpu_memory, address_b, host_ptr_b, false);
}
const std::size_t code_size = code.size() * sizeof(u64);
const u64 unique_identifier = GetUniqueIdentifier(
GetShaderType(program), program == Maxwell::ShaderProgram::VertexA, code, code_b);
- const ShaderParameters params{system, disk_cache, device,
- *cpu_addr, host_ptr, unique_identifier};
+ const ShaderParameters params{gpu, maxwell3d, disk_cache, device,
+ *cpu_addr, host_ptr, unique_identifier};
std::unique_ptr<Shader> shader;
const auto found = runtime_cache.find(unique_identifier);
@@ -567,21 +568,20 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program,
}
Shader* ShaderCacheOpenGL::GetComputeKernel(GPUVAddr code_addr) {
- auto& memory_manager{system.GPU().MemoryManager()};
- const auto cpu_addr{memory_manager.GpuToCpuAddress(code_addr)};
+ const std::optional<VAddr> cpu_addr{gpu_memory.GpuToCpuAddress(code_addr)};
if (Shader* const kernel = cpu_addr ? TryGet(*cpu_addr) : null_kernel.get()) {
return kernel;
}
- const auto host_ptr{memory_manager.GetPointer(code_addr)};
// No kernel found, create a new one
- ProgramCode code{GetShaderCode(memory_manager, code_addr, host_ptr, true)};
+ const u8* host_ptr{gpu_memory.GetPointer(code_addr)};
+ ProgramCode code{GetShaderCode(gpu_memory, code_addr, host_ptr, true)};
const std::size_t code_size{code.size() * sizeof(u64)};
const u64 unique_identifier{GetUniqueIdentifier(ShaderType::Compute, false, code)};
- const ShaderParameters params{system, disk_cache, device,
- *cpu_addr, host_ptr, unique_identifier};
+ const ShaderParameters params{gpu, kepler_compute, disk_cache, device,
+ *cpu_addr, host_ptr, unique_identifier};
std::unique_ptr<Shader> kernel;
const auto found = runtime_cache.find(unique_identifier);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 7528ac686..1708af06a 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -25,8 +25,8 @@
#include "video_core/shader/shader_ir.h"
#include "video_core/shader_cache.h"
-namespace Core {
-class System;
+namespace Tegra {
+class MemoryManager;
}
namespace Core::Frontend {
@@ -57,11 +57,12 @@ struct PrecompiledShader {
};
struct ShaderParameters {
- Core::System& system;
+ Tegra::GPU& gpu;
+ Tegra::Engines::ConstBufferEngineInterface& engine;
ShaderDiskCacheOpenGL& disk_cache;
const Device& device;
VAddr cpu_addr;
- u8* host_ptr;
+ const u8* host_ptr;
u64 unique_identifier;
};
@@ -118,12 +119,14 @@ private:
class ShaderCacheOpenGL final : public VideoCommon::ShaderCache<Shader> {
public:
- explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
- Core::Frontend::EmuWindow& emu_window, const Device& device);
+ explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::Frontend::EmuWindow& emu_window,
+ Tegra::GPU& gpu, Tegra::Engines::Maxwell3D& maxwell3d,
+ Tegra::Engines::KeplerCompute& kepler_compute,
+ Tegra::MemoryManager& gpu_memory, const Device& device);
~ShaderCacheOpenGL() override;
/// Loads disk cache for the current game
- void LoadDiskCache(const std::atomic_bool& stop_loading,
+ void LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback);
/// Gets the current specified shader stage program
@@ -138,9 +141,13 @@ private:
const ShaderDiskCacheEntry& entry, const ShaderDiskCachePrecompiled& precompiled_entry,
const std::unordered_set<GLenum>& supported_formats);
- Core::System& system;
Core::Frontend::EmuWindow& emu_window;
+ Tegra::GPU& gpu;
+ Tegra::MemoryManager& gpu_memory;
+ Tegra::Engines::Maxwell3D& maxwell3d;
+ Tegra::Engines::KeplerCompute& kepler_compute;
const Device& device;
+
ShaderDiskCacheOpenGL disk_cache;
std::unordered_map<u64, PrecompiledShader> runtime_cache;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 3f75fcd2b..bbb8fb095 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -813,7 +813,7 @@ private:
const u8 location = static_cast<u8>(static_cast<u32>(index) * 4 + element);
const auto it = transform_feedback.find(location);
if (it == transform_feedback.end()) {
- return {};
+ return std::nullopt;
}
return it->second.components;
}
@@ -1295,21 +1295,21 @@ private:
switch (element) {
case 0:
UNIMPLEMENTED();
- return {};
+ return std::nullopt;
case 1:
if (stage == ShaderType::Vertex && !device.HasVertexViewportLayer()) {
- return {};
+ return std::nullopt;
}
return {{"gl_Layer", Type::Int}};
case 2:
if (stage == ShaderType::Vertex && !device.HasVertexViewportLayer()) {
- return {};
+ return std::nullopt;
}
return {{"gl_ViewportIndex", Type::Int}};
case 3:
return {{"gl_PointSize", Type::Float}};
}
- return {};
+ return std::nullopt;
case Attribute::Index::FrontColor:
return {{"gl_FrontColor"s + GetSwizzle(element), Type::Float}};
case Attribute::Index::FrontSecondaryColor:
@@ -1332,7 +1332,7 @@ private:
Type::Float}};
}
UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute));
- return {};
+ return std::nullopt;
}
}
@@ -1443,8 +1443,10 @@ private:
return expr + ", vec2(0.0), vec2(0.0))";
case TextureType::TextureCube:
return expr + ", vec3(0.0), vec3(0.0))";
+ default:
+ UNREACHABLE();
+ break;
}
- UNREACHABLE();
}
for (const auto& variant : extras) {
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 52fbab3c1..166ee34e1 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -206,28 +206,32 @@ bool ShaderDiskCacheEntry::Save(Common::FS::IOFile& file) const {
flat_bindless_samplers.size();
}
-ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL(Core::System& system) : system{system} {}
+ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL() = default;
ShaderDiskCacheOpenGL::~ShaderDiskCacheOpenGL() = default;
+void ShaderDiskCacheOpenGL::BindTitleID(u64 title_id_) {
+ title_id = title_id_;
+}
+
std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTransferable() {
// Skip games without title id
- const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0;
+ const bool has_title_id = title_id != 0;
if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) {
- return {};
+ return std::nullopt;
}
Common::FS::IOFile file(GetTransferablePath(), "rb");
if (!file.IsOpen()) {
LOG_INFO(Render_OpenGL, "No transferable shader cache found");
is_usable = true;
- return {};
+ return std::nullopt;
}
u32 version{};
if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) {
LOG_ERROR(Render_OpenGL, "Failed to get transferable cache version, skipping it");
- return {};
+ return std::nullopt;
}
if (version < NativeVersion) {
@@ -235,12 +239,12 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran
file.Close();
InvalidateTransferable();
is_usable = true;
- return {};
+ return std::nullopt;
}
if (version > NativeVersion) {
LOG_WARNING(Render_OpenGL, "Transferable shader cache was generated with a newer version "
"of the emulator, skipping");
- return {};
+ return std::nullopt;
}
// Version is valid, load the shaders
@@ -249,7 +253,7 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran
ShaderDiskCacheEntry& entry = entries.emplace_back();
if (!entry.Load(file)) {
LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry, skipping");
- return {};
+ return std::nullopt;
}
}
@@ -290,12 +294,12 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo
ShaderCacheVersionHash file_hash{};
if (!LoadArrayFromPrecompiled(file_hash.data(), file_hash.size())) {
precompiled_cache_virtual_file_offset = 0;
- return {};
+ return std::nullopt;
}
if (GetShaderCacheVersionHash() != file_hash) {
LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of the emulator");
precompiled_cache_virtual_file_offset = 0;
- return {};
+ return std::nullopt;
}
std::vector<ShaderDiskCachePrecompiled> entries;
@@ -305,15 +309,16 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo
if (!LoadObjectFromPrecompiled(entry.unique_identifier) ||
!LoadObjectFromPrecompiled(entry.binary_format) ||
!LoadObjectFromPrecompiled(binary_size)) {
- return {};
+ return std::nullopt;
}
entry.binary.resize(binary_size);
if (!LoadArrayFromPrecompiled(entry.binary.data(), entry.binary.size())) {
- return {};
+ return std::nullopt;
}
}
- return entries;
+
+ return std::move(entries);
}
void ShaderDiskCacheOpenGL::InvalidateTransferable() {
@@ -473,7 +478,7 @@ std::string ShaderDiskCacheOpenGL::GetBaseDir() const {
}
std::string ShaderDiskCacheOpenGL::GetTitleID() const {
- return fmt::format("{:016X}", system.CurrentProcess()->GetTitleID());
+ return fmt::format("{:016X}", title_id);
}
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.h b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
index db2bb73bc..aef841c1d 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
@@ -21,10 +21,6 @@
#include "video_core/engines/shader_type.h"
#include "video_core/shader/registry.h"
-namespace Core {
-class System;
-}
-
namespace Common::FS {
class IOFile;
}
@@ -70,9 +66,12 @@ struct ShaderDiskCachePrecompiled {
class ShaderDiskCacheOpenGL {
public:
- explicit ShaderDiskCacheOpenGL(Core::System& system);
+ explicit ShaderDiskCacheOpenGL();
~ShaderDiskCacheOpenGL();
+ /// Binds a title ID for all future operations.
+ void BindTitleID(u64 title_id);
+
/// Loads transferable cache. If file has a old version or on failure, it deletes the file.
std::optional<std::vector<ShaderDiskCacheEntry>> LoadTransferable();
@@ -157,8 +156,6 @@ private:
return LoadArrayFromPrecompiled(&object, 1);
}
- Core::System& system;
-
// Stores whole precompiled cache which will be read from or saved to the precompiled chache
// file
FileSys::VectorVfsFile precompiled_cache_virtual_file;
@@ -168,8 +165,11 @@ private:
// Stored transferable shaders
std::unordered_set<u64> stored_transferable;
+ /// Title ID to operate on
+ u64 title_id = 0;
+
// The cache has been loaded at boot
- bool is_usable{};
+ bool is_usable = false;
};
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index 9e74eda0d..4bf0d6090 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <string_view>
#include <vector>
#include <glad/glad.h>
#include "common/assert.h"
@@ -11,7 +12,8 @@
namespace OpenGL::GLShader {
namespace {
-const char* GetStageDebugName(GLenum type) {
+
+std::string_view StageDebugName(GLenum type) {
switch (type) {
case GL_VERTEX_SHADER:
return "vertex";
@@ -25,12 +27,17 @@ const char* GetStageDebugName(GLenum type) {
UNIMPLEMENTED();
return "unknown";
}
+
} // Anonymous namespace
-GLuint LoadShader(const char* source, GLenum type) {
- const char* debug_type = GetStageDebugName(type);
+GLuint LoadShader(std::string_view source, GLenum type) {
+ const std::string_view debug_type = StageDebugName(type);
const GLuint shader_id = glCreateShader(type);
- glShaderSource(shader_id, 1, &source, nullptr);
+
+ const GLchar* source_string = source.data();
+ const GLint source_length = static_cast<GLint>(source.size());
+
+ glShaderSource(shader_id, 1, &source_string, &source_length);
LOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type);
glCompileShader(shader_id);
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h
index 03b7548c2..1b770532e 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.h
+++ b/src/video_core/renderer_opengl/gl_shader_util.h
@@ -38,7 +38,7 @@ void LogShaderSource(T... shaders) {
* @param source String of the GLSL shader program
* @param type Type of the shader (GL_VERTEX_SHADER, GL_GEOMETRY_SHADER or GL_FRAGMENT_SHADER)
*/
-GLuint LoadShader(const char* source, GLenum type);
+GLuint LoadShader(std::string_view source, GLenum type);
/**
* Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader)
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp
index d24fad3de..6bcf831f2 100644
--- a/src/video_core/renderer_opengl/gl_state_tracker.cpp
+++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp
@@ -214,10 +214,8 @@ void SetupDirtyMisc(Tables& tables) {
} // Anonymous namespace
-StateTracker::StateTracker(Core::System& system) : system{system} {}
-
-void StateTracker::Initialize() {
- auto& dirty = system.GPU().Maxwell3D().dirty;
+StateTracker::StateTracker(Tegra::GPU& gpu) : flags{gpu.Maxwell3D().dirty.flags} {
+ auto& dirty = gpu.Maxwell3D().dirty;
auto& tables = dirty.tables;
SetupDirtyRenderTargets(tables);
SetupDirtyColorMasks(tables);
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.h b/src/video_core/renderer_opengl/gl_state_tracker.h
index 0f823288e..9d127548f 100644
--- a/src/video_core/renderer_opengl/gl_state_tracker.h
+++ b/src/video_core/renderer_opengl/gl_state_tracker.h
@@ -13,8 +13,8 @@
#include "video_core/dirty_flags.h"
#include "video_core/engines/maxwell_3d.h"
-namespace Core {
-class System;
+namespace Tegra {
+class GPU;
}
namespace OpenGL {
@@ -90,9 +90,7 @@ static_assert(Last <= std::numeric_limits<u8>::max());
class StateTracker {
public:
- explicit StateTracker(Core::System& system);
-
- void Initialize();
+ explicit StateTracker(Tegra::GPU& gpu);
void BindIndexBuffer(GLuint new_index_buffer) {
if (index_buffer == new_index_buffer) {
@@ -103,7 +101,6 @@ public:
}
void NotifyScreenDrawVertexArray() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::VertexFormats] = true;
flags[OpenGL::Dirty::VertexFormat0 + 0] = true;
flags[OpenGL::Dirty::VertexFormat0 + 1] = true;
@@ -117,98 +114,81 @@ public:
}
void NotifyPolygonModes() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::PolygonModes] = true;
flags[OpenGL::Dirty::PolygonModeFront] = true;
flags[OpenGL::Dirty::PolygonModeBack] = true;
}
void NotifyViewport0() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::Viewports] = true;
flags[OpenGL::Dirty::Viewport0] = true;
}
void NotifyScissor0() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::Scissors] = true;
flags[OpenGL::Dirty::Scissor0] = true;
}
void NotifyColorMask0() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::ColorMasks] = true;
flags[OpenGL::Dirty::ColorMask0] = true;
}
void NotifyBlend0() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::BlendStates] = true;
flags[OpenGL::Dirty::BlendState0] = true;
}
void NotifyFramebuffer() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[VideoCommon::Dirty::RenderTargets] = true;
}
void NotifyFrontFace() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::FrontFace] = true;
}
void NotifyCullTest() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::CullTest] = true;
}
void NotifyDepthMask() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::DepthMask] = true;
}
void NotifyDepthTest() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::DepthTest] = true;
}
void NotifyStencilTest() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::StencilTest] = true;
}
void NotifyPolygonOffset() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::PolygonOffset] = true;
}
void NotifyRasterizeEnable() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::RasterizeEnable] = true;
}
void NotifyFramebufferSRGB() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::FramebufferSRGB] = true;
}
void NotifyLogicOp() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::LogicOp] = true;
}
void NotifyClipControl() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::ClipControl] = true;
}
void NotifyAlphaTest() {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
flags[OpenGL::Dirty::AlphaTest] = true;
}
private:
- Core::System& system;
+ Tegra::Engines::Maxwell3D::DirtyState::Flags& flags;
GLuint index_buffer = 0;
};
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 0a7bc9e2b..a863ef218 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -403,7 +403,7 @@ void CachedSurface::DecorateSurfaceName() {
LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr(), params.TargetName());
}
-void CachedSurfaceView::DecorateViewName(GPUVAddr gpu_addr, std::string prefix) {
+void CachedSurfaceView::DecorateViewName(GPUVAddr gpu_addr, const std::string& prefix) {
LabelGLObject(GL_TEXTURE, main_view.handle, gpu_addr, prefix);
}
@@ -532,10 +532,12 @@ OGLTextureView CachedSurfaceView::CreateTextureView() const {
return texture_view;
}
-TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system,
- VideoCore::RasterizerInterface& rasterizer,
- const Device& device, StateTracker& state_tracker)
- : TextureCacheBase{system, rasterizer, device.HasASTC()}, state_tracker{state_tracker} {
+TextureCacheOpenGL::TextureCacheOpenGL(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::Engines::Maxwell3D& maxwell3d,
+ Tegra::MemoryManager& gpu_memory, const Device& device,
+ StateTracker& state_tracker_)
+ : TextureCacheBase{rasterizer, maxwell3d, gpu_memory, device.HasASTC()}, state_tracker{
+ state_tracker_} {
src_framebuffer.Create();
dst_framebuffer.Create();
}
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index bfc4ddf5d..7787134fc 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -90,7 +90,7 @@ public:
Tegra::Texture::SwizzleSource z_source,
Tegra::Texture::SwizzleSource w_source);
- void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
+ void DecorateViewName(GPUVAddr gpu_addr, const std::string& prefix);
void MarkAsModified(u64 tick) {
surface.MarkAsModified(true, tick);
@@ -129,8 +129,10 @@ private:
class TextureCacheOpenGL final : public TextureCacheBase {
public:
- explicit TextureCacheOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- const Device& device, StateTracker& state_tracker);
+ explicit TextureCacheOpenGL(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::Engines::Maxwell3D& maxwell3d,
+ Tegra::MemoryManager& gpu_memory, const Device& device,
+ StateTracker& state_tracker);
~TextureCacheOpenGL();
protected:
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index fe9bd4b5a..a8be2aa37 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -47,6 +47,8 @@ inline GLenum VertexFormat(Maxwell::VertexAttribute attrib) {
return GL_UNSIGNED_INT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return GL_UNSIGNED_INT_2_10_10_10_REV;
+ default:
+ break;
}
break;
case Maxwell::VertexAttribute::Type::SignedNorm:
@@ -70,6 +72,8 @@ inline GLenum VertexFormat(Maxwell::VertexAttribute attrib) {
return GL_INT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return GL_INT_2_10_10_10_REV;
+ default:
+ break;
}
break;
case Maxwell::VertexAttribute::Type::Float:
@@ -84,6 +88,8 @@ inline GLenum VertexFormat(Maxwell::VertexAttribute attrib) {
case Maxwell::VertexAttribute::Size::Size_32_32_32:
case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
return GL_FLOAT;
+ default:
+ break;
}
break;
}
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 14bbc3a1c..2ccca1993 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -21,6 +21,8 @@
#include "core/perf_stats.h"
#include "core/settings.h"
#include "core/telemetry_session.h"
+#include "video_core/host_shaders/opengl_present_frag.h"
+#include "video_core/host_shaders/opengl_present_vert.h"
#include "video_core/morton.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_manager.h"
@@ -30,60 +32,6 @@ namespace OpenGL {
namespace {
-constexpr std::size_t SWAP_CHAIN_SIZE = 3;
-
-struct Frame {
- u32 width{}; /// Width of the frame (to detect resize)
- u32 height{}; /// Height of the frame
- bool color_reloaded{}; /// Texture attachment was recreated (ie: resized)
- OpenGL::OGLRenderbuffer color{}; /// Buffer shared between the render/present FBO
- OpenGL::OGLFramebuffer render{}; /// FBO created on the render thread
- OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread
- GLsync render_fence{}; /// Fence created on the render thread
- GLsync present_fence{}; /// Fence created on the presentation thread
- bool is_srgb{}; /// Framebuffer is sRGB or RGB
-};
-
-constexpr char VERTEX_SHADER[] = R"(
-#version 430 core
-
-out gl_PerVertex {
- vec4 gl_Position;
-};
-
-layout (location = 0) in vec2 vert_position;
-layout (location = 1) in vec2 vert_tex_coord;
-layout (location = 0) out vec2 frag_tex_coord;
-
-// This is a truncated 3x3 matrix for 2D transformations:
-// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
-// The third column performs translation.
-// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
-// implicitly be [0, 0, 1]
-layout (location = 0) uniform mat3x2 modelview_matrix;
-
-void main() {
- // Multiply input position by the rotscale part of the matrix and then manually translate by
- // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
- // to `vec3(vert_position.xy, 1.0)`
- gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
- frag_tex_coord = vert_tex_coord;
-}
-)";
-
-constexpr char FRAGMENT_SHADER[] = R"(
-#version 430 core
-
-layout (location = 0) in vec2 frag_tex_coord;
-layout (location = 0) out vec4 color;
-
-layout (binding = 0) uniform sampler2D color_texture;
-
-void main() {
- color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f);
-}
-)";
-
constexpr GLint PositionLocation = 0;
constexpr GLint TexCoordLocation = 1;
constexpr GLint ModelViewMatrixLocation = 0;
@@ -96,24 +44,6 @@ struct ScreenRectVertex {
std::array<GLfloat, 2> tex_coord;
};
-/// Returns true if any debug tool is attached
-bool HasDebugTool() {
- const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED");
- if (nsight) {
- return true;
- }
-
- GLint num_extensions;
- glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
- for (GLuint index = 0; index < static_cast<GLuint>(num_extensions); ++index) {
- const auto name = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, index));
- if (!std::strcmp(name, "GL_EXT_debug_tool")) {
- return true;
- }
- }
- return false;
-}
-
/**
* Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left
* corner and (width, height) on the lower-bottom.
@@ -197,132 +127,15 @@ void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severit
} // Anonymous namespace
-/**
- * For smooth Vsync rendering, we want to always present the latest frame that the core generates,
- * but also make sure that rendering happens at the pace that the frontend dictates. This is a
- * helper class that the renderer uses to sync frames between the render thread and the presentation
- * thread
- */
-class FrameMailbox {
-public:
- std::mutex swap_chain_lock;
- std::condition_variable present_cv;
- std::array<Frame, SWAP_CHAIN_SIZE> swap_chain{};
- std::queue<Frame*> free_queue;
- std::deque<Frame*> present_queue;
- Frame* previous_frame{};
-
- FrameMailbox() {
- for (auto& frame : swap_chain) {
- free_queue.push(&frame);
- }
- }
-
- ~FrameMailbox() {
- // lock the mutex and clear out the present and free_queues and notify any people who are
- // blocked to prevent deadlock on shutdown
- std::scoped_lock lock{swap_chain_lock};
- std::queue<Frame*>().swap(free_queue);
- present_queue.clear();
- present_cv.notify_all();
- }
-
- void ReloadPresentFrame(Frame* frame, u32 height, u32 width) {
- frame->present.Release();
- frame->present.Create();
- GLint previous_draw_fbo{};
- glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previous_draw_fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, frame->present.handle);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
- frame->color.handle);
- if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- LOG_CRITICAL(Render_OpenGL, "Failed to recreate present FBO!");
- }
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, previous_draw_fbo);
- frame->color_reloaded = false;
- }
-
- void ReloadRenderFrame(Frame* frame, u32 width, u32 height) {
- // Recreate the color texture attachment
- frame->color.Release();
- frame->color.Create();
- const GLenum internal_format = frame->is_srgb ? GL_SRGB8 : GL_RGB8;
- glNamedRenderbufferStorage(frame->color.handle, internal_format, width, height);
-
- // Recreate the FBO for the render target
- frame->render.Release();
- frame->render.Create();
- glBindFramebuffer(GL_FRAMEBUFFER, frame->render.handle);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
- frame->color.handle);
- if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- LOG_CRITICAL(Render_OpenGL, "Failed to recreate render FBO!");
- }
-
- frame->width = width;
- frame->height = height;
- frame->color_reloaded = true;
- }
-
- Frame* GetRenderFrame() {
- std::unique_lock lock{swap_chain_lock};
-
- // If theres no free frames, we will reuse the oldest render frame
- if (free_queue.empty()) {
- auto frame = present_queue.back();
- present_queue.pop_back();
- return frame;
- }
-
- Frame* frame = free_queue.front();
- free_queue.pop();
- return frame;
- }
-
- void ReleaseRenderFrame(Frame* frame) {
- std::unique_lock lock{swap_chain_lock};
- present_queue.push_front(frame);
- present_cv.notify_one();
- }
-
- Frame* TryGetPresentFrame(int timeout_ms) {
- std::unique_lock lock{swap_chain_lock};
- // wait for new entries in the present_queue
- present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms),
- [&] { return !present_queue.empty(); });
- if (present_queue.empty()) {
- // timed out waiting for a frame to draw so return the previous frame
- return previous_frame;
- }
-
- // free the previous frame and add it back to the free queue
- if (previous_frame) {
- free_queue.push(previous_frame);
- }
-
- // the newest entries are pushed to the front of the queue
- Frame* frame = present_queue.front();
- present_queue.pop_front();
- // remove all old entries from the present queue and move them back to the free_queue
- for (auto f : present_queue) {
- free_queue.push(f);
- }
- present_queue.clear();
- previous_frame = frame;
- return frame;
- }
-};
-
-RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system,
- Core::Frontend::GraphicsContext& context)
- : RendererBase{emu_window}, emu_window{emu_window}, system{system}, context{context},
- program_manager{device}, has_debug_tool{HasDebugTool()} {}
+RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
+ Core::Frontend::EmuWindow& emu_window_,
+ Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
+ std::unique_ptr<Core::Frontend::GraphicsContext> context)
+ : RendererBase{emu_window_, std::move(context)}, telemetry_session{telemetry_session_},
+ emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, program_manager{device} {}
RendererOpenGL::~RendererOpenGL() = default;
-MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 128, 64));
-MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128));
-
void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
if (!framebuffer) {
return;
@@ -331,79 +144,34 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
PrepareRendertarget(framebuffer);
RenderScreenshot();
- Frame* frame;
- {
- MICROPROFILE_SCOPE(OpenGL_WaitPresent);
-
- frame = frame_mailbox->GetRenderFrame();
-
- // Clean up sync objects before drawing
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ DrawScreen(emu_window.GetFramebufferLayout());
- // INTEL driver workaround. We can't delete the previous render sync object until we are
- // sure that the presentation is done
- if (frame->present_fence) {
- glClientWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED);
- }
-
- // delete the draw fence if the frame wasn't presented
- if (frame->render_fence) {
- glDeleteSync(frame->render_fence);
- frame->render_fence = 0;
- }
-
- // wait for the presentation to be done
- if (frame->present_fence) {
- glWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED);
- glDeleteSync(frame->present_fence);
- frame->present_fence = 0;
- }
- }
+ ++m_current_frame;
- {
- MICROPROFILE_SCOPE(OpenGL_RenderFrame);
- const auto& layout = render_window.GetFramebufferLayout();
-
- // Recreate the frame if the size of the window has changed
- if (layout.width != frame->width || layout.height != frame->height ||
- screen_info.display_srgb != frame->is_srgb) {
- LOG_DEBUG(Render_OpenGL, "Reloading render frame");
- frame->is_srgb = screen_info.display_srgb;
- frame_mailbox->ReloadRenderFrame(frame, layout.width, layout.height);
- }
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frame->render.handle);
- DrawScreen(layout);
- // Create a fence for the frontend to wait on and swap this frame to OffTex
- frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glFlush();
- frame_mailbox->ReleaseRenderFrame(frame);
- m_current_frame++;
- rasterizer->TickFrame();
- }
+ rasterizer->TickFrame();
render_window.PollEvents();
- if (has_debug_tool) {
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
- Present(0);
- context.SwapBuffers();
- }
+ context->SwapBuffers();
}
void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) {
- if (framebuffer) {
- // If framebuffer is provided, reload it from memory to a texture
- if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) ||
- screen_info.texture.height != static_cast<GLsizei>(framebuffer->height) ||
- screen_info.texture.pixel_format != framebuffer->pixel_format ||
- gl_framebuffer_data.empty()) {
- // Reallocate texture if the framebuffer size has changed.
- // This is expected to not happen very often and hence should not be a
- // performance problem.
- ConfigureFramebufferTexture(screen_info.texture, *framebuffer);
- }
-
- // Load the framebuffer from memory, draw it to the screen, and swap buffers
- LoadFBToScreenInfo(*framebuffer);
+ if (!framebuffer) {
+ return;
+ }
+ // If framebuffer is provided, reload it from memory to a texture
+ if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) ||
+ screen_info.texture.height != static_cast<GLsizei>(framebuffer->height) ||
+ screen_info.texture.pixel_format != framebuffer->pixel_format ||
+ gl_framebuffer_data.empty()) {
+ // Reallocate texture if the framebuffer size has changed.
+ // This is expected to not happen very often and hence should not be a
+ // performance problem.
+ ConfigureFramebufferTexture(screen_info.texture, *framebuffer);
}
+
+ // Load the framebuffer from memory, draw it to the screen, and swap buffers
+ LoadFBToScreenInfo(*framebuffer);
}
void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) {
@@ -423,7 +191,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
const u32 bytes_per_pixel{VideoCore::Surface::GetBytesPerPixel(pixel_format)};
const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
- u8* const host_ptr{system.Memory().GetPointer(framebuffer_addr)};
+ u8* const host_ptr{cpu_memory.GetPointer(framebuffer_addr)};
rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes);
// TODO(Rodrigo): Read this from HLE
@@ -453,17 +221,15 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
}
void RendererOpenGL::InitOpenGLObjects() {
- frame_mailbox = std::make_unique<FrameMailbox>();
-
glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
Settings::values.bg_blue.GetValue(), 0.0f);
// Create shader programs
OGLShader vertex_shader;
- vertex_shader.Create(VERTEX_SHADER, GL_VERTEX_SHADER);
+ vertex_shader.Create(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER);
OGLShader fragment_shader;
- fragment_shader.Create(FRAGMENT_SHADER, GL_FRAGMENT_SHADER);
+ fragment_shader.Create(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
vertex_program.Create(true, false, vertex_shader.handle);
fragment_program.Create(true, false, fragment_shader.handle);
@@ -508,7 +274,6 @@ void RendererOpenGL::AddTelemetryFields() {
LOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor);
LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
- auto& telemetry_session = system.TelemetrySession();
constexpr auto user_system = Common::Telemetry::FieldType::UserSystem;
telemetry_session.AddField(user_system, "GPU_Vendor", gpu_vendor);
telemetry_session.AddField(user_system, "GPU_Model", gpu_model);
@@ -519,8 +284,8 @@ void RendererOpenGL::CreateRasterizer() {
if (rasterizer) {
return;
}
- rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, device, screen_info,
- program_manager, state_tracker);
+ rasterizer = std::make_unique<RasterizerOpenGL>(emu_window, gpu, cpu_memory, device,
+ screen_info, program_manager, state_tracker);
}
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
@@ -683,51 +448,6 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
program_manager.RestoreGuestPipeline();
}
-bool RendererOpenGL::TryPresent(int timeout_ms) {
- if (has_debug_tool) {
- LOG_DEBUG(Render_OpenGL,
- "Skipping presentation because we are presenting on the main context");
- return false;
- }
- return Present(timeout_ms);
-}
-
-bool RendererOpenGL::Present(int timeout_ms) {
- const auto& layout = render_window.GetFramebufferLayout();
- auto frame = frame_mailbox->TryGetPresentFrame(timeout_ms);
- if (!frame) {
- LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present");
- return false;
- }
-
- // Clearing before a full overwrite of a fbo can signal to drivers that they can avoid a
- // readback since we won't be doing any blending
- glClear(GL_COLOR_BUFFER_BIT);
-
- // Recreate the presentation FBO if the color attachment was changed
- if (frame->color_reloaded) {
- LOG_DEBUG(Render_OpenGL, "Reloading present frame");
- frame_mailbox->ReloadPresentFrame(frame, layout.width, layout.height);
- }
- glWaitSync(frame->render_fence, 0, GL_TIMEOUT_IGNORED);
- // INTEL workaround.
- // Normally we could just delete the draw fence here, but due to driver bugs, we can just delete
- // it on the emulation thread without too much penalty
- // glDeleteSync(frame.render_sync);
- // frame.render_sync = 0;
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER, frame->present.handle);
- glBlitFramebuffer(0, 0, frame->width, frame->height, 0, 0, layout.width, layout.height,
- GL_COLOR_BUFFER_BIT, GL_LINEAR);
-
- // Insert fence for the main thread to block on
- frame->present_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glFlush();
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
- return true;
-}
-
void RendererOpenGL::RenderScreenshot() {
if (!renderer_settings.screenshot_requested) {
return;
@@ -742,7 +462,7 @@ void RendererOpenGL::RenderScreenshot() {
screenshot_framebuffer.Create();
glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle);
- Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
+ const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 8b18d32e6..9ef181f95 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -16,16 +16,25 @@
namespace Core {
class System;
-}
+class TelemetrySession;
+} // namespace Core
namespace Core::Frontend {
class EmuWindow;
}
+namespace Core::Memory {
+class Memory;
+}
+
namespace Layout {
struct FramebufferLayout;
}
+namespace Tegra {
+class GPU;
+}
+
namespace OpenGL {
/// Structure used for storing information about the textures for the Switch screen
@@ -46,24 +55,17 @@ struct ScreenInfo {
TextureInfo texture;
};
-struct PresentationTexture {
- u32 width = 0;
- u32 height = 0;
- OGLTexture texture;
-};
-
-class FrameMailbox;
-
class RendererOpenGL final : public VideoCore::RendererBase {
public:
- explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system,
- Core::Frontend::GraphicsContext& context);
+ explicit RendererOpenGL(Core::TelemetrySession& telemetry_session,
+ Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory,
+ Tegra::GPU& gpu,
+ std::unique_ptr<Core::Frontend::GraphicsContext> context);
~RendererOpenGL() override;
bool Init() override;
void ShutDown() override;
void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override;
- bool TryPresent(int timeout_ms) override;
private:
/// Initializes the OpenGL state and creates persistent objects.
@@ -91,14 +93,13 @@ private:
void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer);
- bool Present(int timeout_ms);
-
+ Core::TelemetrySession& telemetry_session;
Core::Frontend::EmuWindow& emu_window;
- Core::System& system;
- Core::Frontend::GraphicsContext& context;
- const Device device;
+ Core::Memory::Memory& cpu_memory;
+ Tegra::GPU& gpu;
- StateTracker state_tracker{system};
+ const Device device;
+ StateTracker state_tracker{gpu};
// OpenGL object IDs
OGLBuffer vertex_buffer;
@@ -120,13 +121,8 @@ private:
std::vector<u8> gl_framebuffer_data;
/// Used for transforming the framebuffer orientation
- Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags;
+ Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{};
Common::Rectangle<int> framebuffer_crop_rect;
-
- /// Frame presentation mailbox
- std::unique_ptr<FrameMailbox> frame_mailbox;
-
- bool has_debug_tool = false;
};
} // namespace OpenGL
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index 81a39a3b8..da5c550ea 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -58,6 +58,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
logic_op.Assign(PackLogicOp(regs.logic_op.operation));
rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0);
+ topology.Assign(regs.draw.topology);
std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast
@@ -131,7 +132,6 @@ void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size
}
void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
- const u32 topology_index = static_cast<u32>(regs.draw.topology.Value());
u32 packed_front_face = PackFrontFace(regs.front_face);
if (regs.screen_y_control.triangle_rast_flip != 0) {
// Flip front face
@@ -161,7 +161,6 @@ void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
depth_test_enable.Assign(regs.depth_test_enable);
front_face.Assign(packed_front_face);
depth_test_func.Assign(PackComparisonOp(regs.depth_test_func));
- topology.Assign(topology_index);
cull_face.Assign(PackCullFace(regs.cull_face));
cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0);
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
index cdcbb65f5..2c18eeaae 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
@@ -150,9 +150,8 @@ struct FixedPipelineState {
};
union {
u32 raw2;
- BitField<0, 4, u32> topology;
- BitField<4, 2, u32> cull_face;
- BitField<6, 1, u32> cull_enable;
+ BitField<0, 2, u32> cull_face;
+ BitField<2, 1, u32> cull_enable;
};
std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings;
@@ -169,10 +168,6 @@ struct FixedPipelineState {
Maxwell::FrontFace FrontFace() const noexcept {
return UnpackFrontFace(front_face.Value());
}
-
- constexpr Maxwell::PrimitiveTopology Topology() const noexcept {
- return static_cast<Maxwell::PrimitiveTopology>(topology.Value());
- }
};
union {
@@ -190,6 +185,7 @@ struct FixedPipelineState {
BitField<18, 1, u32> logic_op_enable;
BitField<19, 4, u32> logic_op;
BitField<23, 1, u32> rasterize_enable;
+ BitField<24, 4, Maxwell::PrimitiveTopology> topology;
};
u32 point_size;
std::array<u32, Maxwell::NumVertexArrays> binding_divisors;
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index f8c77f4fa..d22de1d81 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -78,9 +78,10 @@ VkSamplerAddressMode WrapMode(const VKDevice& device, Tegra::Texture::WrapMode w
case Tegra::Texture::WrapMode::MirrorOnceBorder:
UNIMPLEMENTED();
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", static_cast<u32>(wrap_mode));
+ return {};
}
- UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", static_cast<u32>(wrap_mode));
- return {};
}
VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_func) {
@@ -298,9 +299,10 @@ VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const VKDevice& device,
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
case Maxwell::PrimitiveTopology::Patches:
return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented topology={}", static_cast<u32>(topology));
+ return {};
}
- UNIMPLEMENTED_MSG("Unimplemented topology={}", static_cast<u32>(topology));
- return {};
}
VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size) {
@@ -325,6 +327,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R16G16B16A16_UNORM;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
+ default:
+ break;
}
break;
case Maxwell::VertexAttribute::Type::SignedNorm:
@@ -347,6 +351,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R16G16B16A16_SNORM;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_SNORM_PACK32;
+ default:
+ break;
}
break;
case Maxwell::VertexAttribute::Type::UnsignedScaled:
@@ -369,6 +375,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R16G16B16A16_USCALED;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_USCALED_PACK32;
+ default:
+ break;
}
break;
case Maxwell::VertexAttribute::Type::SignedScaled:
@@ -391,6 +399,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R16G16B16A16_SSCALED;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_SSCALED_PACK32;
+ default:
+ break;
}
break;
case Maxwell::VertexAttribute::Type::UnsignedInt:
@@ -421,6 +431,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R32G32B32A32_UINT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_UINT_PACK32;
+ default:
+ break;
}
break;
case Maxwell::VertexAttribute::Type::SignedInt:
@@ -451,6 +463,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R32G32B32A32_SINT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_SINT_PACK32;
+ default:
+ break;
}
break;
case Maxwell::VertexAttribute::Type::Float:
@@ -471,6 +485,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R32G32B32_SFLOAT;
case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
return VK_FORMAT_R32G32B32A32_SFLOAT;
+ default:
+ break;
}
break;
}
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 7ffc90cd0..f2610868e 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -25,9 +25,9 @@
#include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/renderer_vulkan/vk_blit_screen.h"
#include "video_core/renderer_vulkan/vk_device.h"
+#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_memory_manager.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_state_tracker.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
@@ -56,7 +56,7 @@ VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT* data,
[[maybe_unused]] void* user_data) {
- const char* message{data->pMessage};
+ const char* const message{data->pMessage};
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
LOG_CRITICAL(Render_Vulkan, "{}", message);
@@ -86,7 +86,7 @@ Common::DynamicLibrary OpenVulkanLibrary() {
if (!library.Open(filename.c_str())) {
// Android devices may not have libvulkan.so.1, only libvulkan.so.
filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
- library.Open(filename.c_str());
+ (void)library.Open(filename.c_str());
}
#endif
return library;
@@ -240,8 +240,12 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext
} // Anonymous namespace
-RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system)
- : RendererBase(window), system{system} {}
+RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
+ Core::Frontend::EmuWindow& emu_window,
+ Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
+ std::unique_ptr<Core::Frontend::GraphicsContext> context)
+ : RendererBase{emu_window, std::move(context)}, telemetry_session{telemetry_session_},
+ cpu_memory{cpu_memory_}, gpu{gpu_} {}
RendererVulkan::~RendererVulkan() {
ShutDown();
@@ -268,11 +272,11 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
scheduler->WaitWorker();
swapchain->AcquireNextImage();
- const auto [fence, render_semaphore] = blit_screen->Draw(*framebuffer, use_accelerated);
+ const VkSemaphore render_semaphore = blit_screen->Draw(*framebuffer, use_accelerated);
- scheduler->Flush(false, render_semaphore);
+ scheduler->Flush(render_semaphore);
- if (swapchain->Present(render_semaphore, fence)) {
+ if (swapchain->Present(render_semaphore)) {
blit_screen->Recreate();
}
@@ -282,11 +286,6 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
render_window.PollEvents();
}
-bool RendererVulkan::TryPresent(int /*timeout_ms*/) {
- // TODO (bunnei): ImplementMe
- return true;
-}
-
bool RendererVulkan::Init() {
library = OpenVulkanLibrary();
std::tie(instance, instance_version) = CreateInstance(
@@ -299,23 +298,21 @@ bool RendererVulkan::Init() {
memory_manager = std::make_unique<VKMemoryManager>(*device);
- resource_manager = std::make_unique<VKResourceManager>(*device);
+ state_tracker = std::make_unique<StateTracker>(gpu);
+
+ scheduler = std::make_unique<VKScheduler>(*device, *state_tracker);
const auto& framebuffer = render_window.GetFramebufferLayout();
- swapchain = std::make_unique<VKSwapchain>(*surface, *device);
+ swapchain = std::make_unique<VKSwapchain>(*surface, *device, *scheduler);
swapchain->Create(framebuffer.width, framebuffer.height, false);
- state_tracker = std::make_unique<StateTracker>(system);
-
- scheduler = std::make_unique<VKScheduler>(*device, *resource_manager, *state_tracker);
-
- rasterizer = std::make_unique<RasterizerVulkan>(system, render_window, screen_info, *device,
- *resource_manager, *memory_manager,
- *state_tracker, *scheduler);
+ rasterizer = std::make_unique<RasterizerVulkan>(render_window, gpu, gpu.MemoryManager(),
+ cpu_memory, screen_info, *device,
+ *memory_manager, *state_tracker, *scheduler);
- blit_screen = std::make_unique<VKBlitScreen>(system, render_window, *rasterizer, *device,
- *resource_manager, *memory_manager, *swapchain,
- *scheduler, screen_info);
+ blit_screen =
+ std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device,
+ *memory_manager, *swapchain, *scheduler, screen_info);
return true;
}
@@ -333,7 +330,6 @@ void RendererVulkan::ShutDown() {
scheduler.reset();
swapchain.reset();
memory_manager.reset();
- resource_manager.reset();
device.reset();
}
@@ -442,8 +438,7 @@ void RendererVulkan::Report() const {
LOG_INFO(Render_Vulkan, "Device: {}", model_name);
LOG_INFO(Render_Vulkan, "Vulkan: {}", api_version);
- auto& telemetry_session = system.TelemetrySession();
- constexpr auto field = Common::Telemetry::FieldType::UserSystem;
+ static constexpr auto field = Common::Telemetry::FieldType::UserSystem;
telemetry_session.AddField(field, "GPU_Vendor", vendor_name);
telemetry_session.AddField(field, "GPU_Model", model_name);
telemetry_session.AddField(field, "GPU_Vulkan_Driver", driver_name);
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 9617a93e9..1044ca124 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -14,7 +14,15 @@
#include "video_core/renderer_vulkan/wrapper.h"
namespace Core {
-class System;
+class TelemetrySession;
+}
+
+namespace Core::Memory {
+class Memory;
+}
+
+namespace Tegra {
+class GPU;
}
namespace Vulkan {
@@ -22,9 +30,7 @@ namespace Vulkan {
class StateTracker;
class VKBlitScreen;
class VKDevice;
-class VKFence;
class VKMemoryManager;
-class VKResourceManager;
class VKSwapchain;
class VKScheduler;
class VKImage;
@@ -38,13 +44,15 @@ struct VKScreenInfo {
class RendererVulkan final : public VideoCore::RendererBase {
public:
- explicit RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system);
+ explicit RendererVulkan(Core::TelemetrySession& telemtry_session,
+ Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory,
+ Tegra::GPU& gpu,
+ std::unique_ptr<Core::Frontend::GraphicsContext> context);
~RendererVulkan() override;
bool Init() override;
void ShutDown() override;
void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override;
- bool TryPresent(int timeout_ms) override;
static std::vector<std::string> EnumerateDevices();
@@ -57,7 +65,9 @@ private:
void Report() const;
- Core::System& system;
+ Core::TelemetrySession& telemetry_session;
+ Core::Memory::Memory& cpu_memory;
+ Tegra::GPU& gpu;
Common::DynamicLibrary library;
vk::InstanceDispatch dld;
@@ -71,11 +81,10 @@ private:
vk::DebugCallback debug_callback;
std::unique_ptr<VKDevice> device;
- std::unique_ptr<VKSwapchain> swapchain;
std::unique_ptr<VKMemoryManager> memory_manager;
- std::unique_ptr<VKResourceManager> resource_manager;
std::unique_ptr<StateTracker> state_tracker;
std::unique_ptr<VKScheduler> scheduler;
+ std::unique_ptr<VKSwapchain> swapchain;
std::unique_ptr<VKBlitScreen> blit_screen;
};
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index a551e3de8..b5b60309e 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -12,11 +12,9 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/math_util.h"
-
#include "core/core.h"
#include "core/frontend/emu_window.h"
#include "core/memory.h"
-
#include "video_core/gpu.h"
#include "video_core/morton.h"
#include "video_core/rasterizer_interface.h"
@@ -24,8 +22,8 @@
#include "video_core/renderer_vulkan/vk_blit_screen.h"
#include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_image.h"
+#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_memory_manager.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
@@ -210,17 +208,15 @@ struct VKBlitScreen::BufferData {
// Unaligned image data goes here
};
-VKBlitScreen::VKBlitScreen(Core::System& system, Core::Frontend::EmuWindow& render_window,
- VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
- VKResourceManager& resource_manager, VKMemoryManager& memory_manager,
- VKSwapchain& swapchain, VKScheduler& scheduler,
- const VKScreenInfo& screen_info)
- : system{system}, render_window{render_window}, rasterizer{rasterizer}, device{device},
- resource_manager{resource_manager}, memory_manager{memory_manager}, swapchain{swapchain},
- scheduler{scheduler}, image_count{swapchain.GetImageCount()}, screen_info{screen_info} {
- watches.resize(image_count);
- std::generate(watches.begin(), watches.end(),
- []() { return std::make_unique<VKFenceWatch>(); });
+VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_,
+ Core::Frontend::EmuWindow& render_window_,
+ VideoCore::RasterizerInterface& rasterizer_, const VKDevice& device_,
+ VKMemoryManager& memory_manager_, VKSwapchain& swapchain_,
+ VKScheduler& scheduler_, const VKScreenInfo& screen_info_)
+ : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_},
+ device{device_}, memory_manager{memory_manager_}, swapchain{swapchain_},
+ scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} {
+ resource_ticks.resize(image_count);
CreateStaticResources();
CreateDynamicResources();
@@ -232,15 +228,16 @@ void VKBlitScreen::Recreate() {
CreateDynamicResources();
}
-std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
- bool use_accelerated) {
+VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool use_accelerated) {
RefreshResources(framebuffer);
// Finish any pending renderpass
scheduler.RequestOutsideRenderPassOperationContext();
const std::size_t image_index = swapchain.GetImageIndex();
- watches[image_index]->Watch(scheduler.GetFence());
+
+ scheduler.Wait(resource_ticks[image_index]);
+ resource_ticks[image_index] = scheduler.CurrentTick();
VKImage* blit_image = use_accelerated ? screen_info.image : raw_images[image_index].get();
@@ -259,7 +256,7 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon
const auto pixel_format =
VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format);
const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset;
- const auto host_ptr = system.Memory().GetPointer(framebuffer_addr);
+ const auto host_ptr = cpu_memory.GetPointer(framebuffer_addr);
rasterizer.FlushRegion(ToCacheAddr(host_ptr), GetSizeInBytes(framebuffer));
// TODO(Rodrigo): Read this from HLE
@@ -343,7 +340,7 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon
cmdbuf.EndRenderPass();
});
- return {scheduler.GetFence(), *semaphores[image_index]};
+ return *semaphores[image_index];
}
void VKBlitScreen::CreateStaticResources() {
@@ -711,7 +708,7 @@ void VKBlitScreen::CreateFramebuffers() {
void VKBlitScreen::ReleaseRawImages() {
for (std::size_t i = 0; i < raw_images.size(); ++i) {
- watches[i]->Wait();
+ scheduler.Wait(resource_ticks.at(i));
}
raw_images.clear();
raw_buffer_commits.clear();
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 243640fab..8f2839214 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -5,16 +5,18 @@
#pragma once
#include <memory>
-#include <tuple>
#include "video_core/renderer_vulkan/vk_memory_manager.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/wrapper.h"
namespace Core {
class System;
}
+namespace Core::Memory {
+class Memory;
+}
+
namespace Core::Frontend {
class EmuWindow;
}
@@ -30,26 +32,26 @@ class RasterizerInterface;
namespace Vulkan {
struct ScreenInfo;
+
class RasterizerVulkan;
class VKDevice;
-class VKFence;
class VKImage;
class VKScheduler;
class VKSwapchain;
class VKBlitScreen final {
public:
- explicit VKBlitScreen(Core::System& system, Core::Frontend::EmuWindow& render_window,
+ explicit VKBlitScreen(Core::Memory::Memory& cpu_memory,
+ Core::Frontend::EmuWindow& render_window,
VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
- VKResourceManager& resource_manager, VKMemoryManager& memory_manager,
- VKSwapchain& swapchain, VKScheduler& scheduler,
- const VKScreenInfo& screen_info);
+ VKMemoryManager& memory_manager, VKSwapchain& swapchain,
+ VKScheduler& scheduler, const VKScreenInfo& screen_info);
~VKBlitScreen();
void Recreate();
- std::tuple<VKFence&, VkSemaphore> Draw(const Tegra::FramebufferConfig& framebuffer,
- bool use_accelerated);
+ [[nodiscard]] VkSemaphore Draw(const Tegra::FramebufferConfig& framebuffer,
+ bool use_accelerated);
private:
struct BufferData;
@@ -81,11 +83,10 @@ private:
u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer,
std::size_t image_index) const;
- Core::System& system;
+ Core::Memory::Memory& cpu_memory;
Core::Frontend::EmuWindow& render_window;
VideoCore::RasterizerInterface& rasterizer;
const VKDevice& device;
- VKResourceManager& resource_manager;
VKMemoryManager& memory_manager;
VKSwapchain& swapchain;
VKScheduler& scheduler;
@@ -106,7 +107,7 @@ private:
vk::Buffer buffer;
VKMemoryCommit buffer_commit;
- std::vector<std::unique_ptr<VKFenceWatch>> watches;
+ std::vector<u64> resource_ticks;
std::vector<vk::Semaphore> semaphores;
std::vector<std::unique_ptr<VKImage>> raw_images;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 1d2f8b557..d9d3da9ea 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -145,14 +145,15 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst
});
}
-VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
- const VKDevice& device, VKMemoryManager& memory_manager,
- VKScheduler& scheduler, VKStagingBufferPool& staging_pool)
- : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer, system,
- CreateStreamBuffer(device,
- scheduler)},
- device{device}, memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{
- staging_pool} {}
+VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
+ const VKDevice& device_, VKMemoryManager& memory_manager_,
+ VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_)
+ : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer, gpu_memory, cpu_memory,
+ CreateStreamBuffer(device_,
+ scheduler_)},
+ device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{
+ staging_pool_} {}
VKBufferCache::~VKBufferCache() = default;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 991ee451c..7fb5ceedf 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -13,10 +13,6 @@
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/wrapper.h"
-namespace Core {
-class System;
-}
-
namespace Vulkan {
class VKDevice;
@@ -53,7 +49,8 @@ private:
class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> {
public:
- explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
+ explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
const VKDevice& device, VKMemoryManager& memory_manager,
VKScheduler& scheduler, VKStagingBufferPool& staging_pool);
~VKBufferCache();
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.cpp b/src/video_core/renderer_vulkan/vk_command_pool.cpp
new file mode 100644
index 000000000..6339f4fe0
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_command_pool.cpp
@@ -0,0 +1,46 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cstddef>
+
+#include "video_core/renderer_vulkan/vk_command_pool.h"
+#include "video_core/renderer_vulkan/vk_device.h"
+#include "video_core/renderer_vulkan/wrapper.h"
+
+namespace Vulkan {
+
+constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000;
+
+struct CommandPool::Pool {
+ vk::CommandPool handle;
+ vk::CommandBuffers cmdbufs;
+};
+
+CommandPool::CommandPool(MasterSemaphore& master_semaphore, const VKDevice& device)
+ : ResourcePool(master_semaphore, COMMAND_BUFFER_POOL_SIZE), device{device} {}
+
+CommandPool::~CommandPool() = default;
+
+void CommandPool::Allocate(size_t begin, size_t end) {
+ // Command buffers are going to be commited, recorded, executed every single usage cycle.
+ // They are also going to be reseted when commited.
+ Pool& pool = pools.emplace_back();
+ pool.handle = device.GetLogical().CreateCommandPool({
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ .pNext = nullptr,
+ .flags =
+ VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
+ .queueFamilyIndex = device.GetGraphicsFamily(),
+ });
+ pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE);
+}
+
+VkCommandBuffer CommandPool::Commit() {
+ const size_t index = CommitResource();
+ const auto pool_index = index / COMMAND_BUFFER_POOL_SIZE;
+ const auto sub_index = index % COMMAND_BUFFER_POOL_SIZE;
+ return pools[pool_index].cmdbufs[sub_index];
+}
+
+} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.h b/src/video_core/renderer_vulkan/vk_command_pool.h
new file mode 100644
index 000000000..b9cb3fb5d
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_command_pool.h
@@ -0,0 +1,34 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cstddef>
+#include <vector>
+
+#include "video_core/renderer_vulkan/vk_resource_pool.h"
+#include "video_core/renderer_vulkan/wrapper.h"
+
+namespace Vulkan {
+
+class MasterSemaphore;
+class VKDevice;
+
+class CommandPool final : public ResourcePool {
+public:
+ explicit CommandPool(MasterSemaphore& master_semaphore, const VKDevice& device);
+ ~CommandPool() override;
+
+ void Allocate(size_t begin, size_t end) override;
+
+ VkCommandBuffer Commit();
+
+private:
+ struct Pool;
+
+ const VKDevice& device;
+ std::vector<Pool> pools;
+};
+
+} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 182461ed9..9637c6059 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -112,7 +112,8 @@ constexpr u8 quad_array[] = {
0xf9, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x00,
0xf9, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4e, 0x00, 0x00, 0x00,
0xf9, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00,
- 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00};
+ 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
+};
VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() {
return {
@@ -218,7 +219,8 @@ constexpr u8 uint8_pass[] = {
0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
0xf9, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00,
- 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00};
+ 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
+};
// Quad indexed SPIR-V module. Generated from the "shaders/" directory.
constexpr u8 QUAD_INDEXED_SPV[] = {
@@ -341,7 +343,8 @@ constexpr u8 QUAD_INDEXED_SPV[] = {
0xf9, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x37, 0x00, 0x00, 0x00,
0xf9, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, 0x00,
0xf9, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00,
- 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00};
+ 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
+};
std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() {
return {{
@@ -448,12 +451,12 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto
VKComputePass::~VKComputePass() = default;
-VkDescriptorSet VKComputePass::CommitDescriptorSet(VKUpdateDescriptorQueue& update_descriptor_queue,
- VKFence& fence) {
+VkDescriptorSet VKComputePass::CommitDescriptorSet(
+ VKUpdateDescriptorQueue& update_descriptor_queue) {
if (!descriptor_template) {
return nullptr;
}
- const auto set = descriptor_allocator->Commit(fence);
+ const VkDescriptorSet set = descriptor_allocator->Commit();
update_descriptor_queue.Send(*descriptor_template, set);
return set;
}
@@ -477,7 +480,7 @@ std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32
update_descriptor_queue.Acquire();
update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size);
- const auto set = CommitDescriptorSet(update_descriptor_queue, scheduler.GetFence());
+ const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue);
scheduler.RequestOutsideRenderPassOperationContext();
@@ -520,13 +523,13 @@ Uint8Pass::~Uint8Pass() = default;
std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer,
u64 src_offset) {
- const auto staging_size = static_cast<u32>(num_vertices * sizeof(u16));
+ const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16));
auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false);
update_descriptor_queue.Acquire();
update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices);
update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size);
- const auto set = CommitDescriptorSet(update_descriptor_queue, scheduler.GetFence());
+ const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set,
@@ -589,7 +592,7 @@ std::pair<VkBuffer, u64> QuadIndexedPass::Assemble(
update_descriptor_queue.Acquire();
update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size);
update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size);
- const auto set = CommitDescriptorSet(update_descriptor_queue, scheduler.GetFence());
+ const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set,
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index 230b526bc..acc94f27e 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -15,7 +15,6 @@
namespace Vulkan {
class VKDevice;
-class VKFence;
class VKScheduler;
class VKStagingBufferPool;
class VKUpdateDescriptorQueue;
@@ -30,8 +29,7 @@ public:
~VKComputePass();
protected:
- VkDescriptorSet CommitDescriptorSet(VKUpdateDescriptorQueue& update_descriptor_queue,
- VKFence& fence);
+ VkDescriptorSet CommitDescriptorSet(VKUpdateDescriptorQueue& update_descriptor_queue);
vk::DescriptorUpdateTemplateKHR descriptor_template;
vk::PipelineLayout layout;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index ed9d2991c..9be72dc9b 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -32,7 +32,7 @@ VkDescriptorSet VKComputePipeline::CommitDescriptorSet() {
if (!descriptor_template) {
return {};
}
- const auto set = descriptor_allocator.Commit(scheduler.GetFence());
+ const VkDescriptorSet set = descriptor_allocator.Commit();
update_descriptor_queue.Send(*descriptor_template, set);
return set;
}
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
index ac4a0884e..f38e089d5 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
@@ -7,7 +7,8 @@
#include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/renderer_vulkan/vk_device.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
+#include "video_core/renderer_vulkan/vk_resource_pool.h"
+#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/wrapper.h"
namespace Vulkan {
@@ -15,14 +16,15 @@ namespace Vulkan {
// Prefer small grow rates to avoid saturating the descriptor pool with barely used pipelines.
constexpr std::size_t SETS_GROW_RATE = 0x20;
-DescriptorAllocator::DescriptorAllocator(VKDescriptorPool& descriptor_pool,
- VkDescriptorSetLayout layout)
- : VKFencedPool{SETS_GROW_RATE}, descriptor_pool{descriptor_pool}, layout{layout} {}
+DescriptorAllocator::DescriptorAllocator(VKDescriptorPool& descriptor_pool_,
+ VkDescriptorSetLayout layout_)
+ : ResourcePool(descriptor_pool_.master_semaphore, SETS_GROW_RATE),
+ descriptor_pool{descriptor_pool_}, layout{layout_} {}
DescriptorAllocator::~DescriptorAllocator() = default;
-VkDescriptorSet DescriptorAllocator::Commit(VKFence& fence) {
- const std::size_t index = CommitResource(fence);
+VkDescriptorSet DescriptorAllocator::Commit() {
+ const std::size_t index = CommitResource();
return descriptors_allocations[index / SETS_GROW_RATE][index % SETS_GROW_RATE];
}
@@ -30,8 +32,9 @@ void DescriptorAllocator::Allocate(std::size_t begin, std::size_t end) {
descriptors_allocations.push_back(descriptor_pool.AllocateDescriptors(layout, end - begin));
}
-VKDescriptorPool::VKDescriptorPool(const VKDevice& device)
- : device{device}, active_pool{AllocateNewPool()} {}
+VKDescriptorPool::VKDescriptorPool(const VKDevice& device_, VKScheduler& scheduler)
+ : device{device_}, master_semaphore{scheduler.GetMasterSemaphore()}, active_pool{
+ AllocateNewPool()} {}
VKDescriptorPool::~VKDescriptorPool() = default;
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
index 9efa66bef..544f32a20 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
@@ -6,21 +6,24 @@
#include <vector>
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
+#include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/renderer_vulkan/wrapper.h"
namespace Vulkan {
+class VKDevice;
class VKDescriptorPool;
+class VKScheduler;
-class DescriptorAllocator final : public VKFencedPool {
+class DescriptorAllocator final : public ResourcePool {
public:
explicit DescriptorAllocator(VKDescriptorPool& descriptor_pool, VkDescriptorSetLayout layout);
~DescriptorAllocator() override;
+ DescriptorAllocator& operator=(const DescriptorAllocator&) = delete;
DescriptorAllocator(const DescriptorAllocator&) = delete;
- VkDescriptorSet Commit(VKFence& fence);
+ VkDescriptorSet Commit();
protected:
void Allocate(std::size_t begin, std::size_t end) override;
@@ -36,15 +39,19 @@ class VKDescriptorPool final {
friend DescriptorAllocator;
public:
- explicit VKDescriptorPool(const VKDevice& device);
+ explicit VKDescriptorPool(const VKDevice& device, VKScheduler& scheduler);
~VKDescriptorPool();
+ VKDescriptorPool(const VKDescriptorPool&) = delete;
+ VKDescriptorPool& operator=(const VKDescriptorPool&) = delete;
+
private:
vk::DescriptorPool* AllocateNewPool();
vk::DescriptorSets AllocateDescriptors(VkDescriptorSetLayout layout, std::size_t count);
const VKDevice& device;
+ MasterSemaphore& master_semaphore;
std::vector<vk::DescriptorPool> pools;
vk::DescriptorPool* active_pool;
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 90916ee0e..e1217ca83 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -45,6 +45,7 @@ constexpr std::array REQUIRED_EXTENSIONS{
VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
+ VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME,
VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME,
@@ -81,6 +82,21 @@ VkFormatFeatureFlags GetFormatFeatures(VkFormatProperties properties, FormatType
}
}
+[[nodiscard]] bool IsRDNA(std::string_view device_name, VkDriverIdKHR driver_id) {
+ static constexpr std::array RDNA_DEVICES{
+ "5700",
+ "5600",
+ "5500",
+ "5300",
+ };
+ if (driver_id != VK_DRIVER_ID_AMD_PROPRIETARY_KHR) {
+ return false;
+ }
+ return std::any_of(RDNA_DEVICES.begin(), RDNA_DEVICES.end(), [device_name](const char* name) {
+ return device_name.find(name) != std::string_view::npos;
+ });
+}
+
std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
vk::PhysicalDevice physical, const vk::InstanceDispatch& dld) {
static constexpr std::array formats{
@@ -253,6 +269,13 @@ bool VKDevice::Create() {
.inheritedQueries = false,
};
+ VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR,
+ .pNext = nullptr,
+ .timelineSemaphore = true,
+ };
+ SetNext(next, timeline_semaphore);
+
VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
.pNext = nullptr,
@@ -383,6 +406,15 @@ bool VKDevice::Create() {
CollectTelemetryParameters();
+ if (ext_extended_dynamic_state && IsRDNA(properties.deviceName, driver_id)) {
+ // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but on RDNA devices it
+ // seems to cause stability issues
+ LOG_WARNING(
+ Render_Vulkan,
+ "Blacklisting AMD proprietary on RDNA devices from VK_EXT_extended_dynamic_state");
+ ext_extended_dynamic_state = false;
+ }
+
graphics_queue = logical.GetQueue(graphics_family);
present_queue = logical.GetQueue(present_family);
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
index d7f65d435..5babbdd0b 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
@@ -29,8 +29,8 @@ void InnerFence::Queue() {
}
ASSERT(!event);
- event = device.GetLogical().CreateNewEvent();
- ticks = scheduler.Ticks();
+ event = device.GetLogical().CreateEvent();
+ ticks = scheduler.CurrentTick();
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([event = *event](vk::CommandBuffer cmdbuf) {
@@ -52,7 +52,7 @@ void InnerFence::Wait() {
}
ASSERT(event);
- if (ticks >= scheduler.Ticks()) {
+ if (ticks >= scheduler.CurrentTick()) {
scheduler.Flush();
}
while (!IsEventSignalled()) {
@@ -71,12 +71,12 @@ bool InnerFence::IsEventSignalled() const {
}
}
-VKFenceManager::VKFenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- const VKDevice& device, VKScheduler& scheduler,
- VKTextureCache& texture_cache, VKBufferCache& buffer_cache,
- VKQueryCache& query_cache)
- : GenericFenceManager(system, rasterizer, texture_cache, buffer_cache, query_cache),
- device{device}, scheduler{scheduler} {}
+VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu,
+ Tegra::MemoryManager& memory_manager, VKTextureCache& texture_cache,
+ VKBufferCache& buffer_cache, VKQueryCache& query_cache,
+ const VKDevice& device_, VKScheduler& scheduler_)
+ : GenericFenceManager(rasterizer, gpu, texture_cache, buffer_cache, query_cache),
+ device{device_}, scheduler{scheduler_} {}
Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) {
return std::make_shared<InnerFence>(device, scheduler, value, is_stubbed);
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h
index 043fe7947..1547d6d30 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.h
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.h
@@ -55,10 +55,10 @@ using GenericFenceManager =
class VKFenceManager final : public GenericFenceManager {
public:
- explicit VKFenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- const VKDevice& device, VKScheduler& scheduler,
- VKTextureCache& texture_cache, VKBufferCache& buffer_cache,
- VKQueryCache& query_cache);
+ explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu,
+ Tegra::MemoryManager& memory_manager, VKTextureCache& texture_cache,
+ VKBufferCache& buffer_cache, VKQueryCache& query_cache,
+ const VKDevice& device, VKScheduler& scheduler);
protected:
Fence CreateFence(u32 value, bool is_stubbed) override;
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 2e46c6278..696eaeb5f 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -93,7 +93,7 @@ VkDescriptorSet VKGraphicsPipeline::CommitDescriptorSet() {
if (!descriptor_template) {
return {};
}
- const auto set = descriptor_allocator.Commit(scheduler.GetFence());
+ const VkDescriptorSet set = descriptor_allocator.Commit();
update_descriptor_queue.Send(*descriptor_template, set);
return set;
}
@@ -261,12 +261,12 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
vertex_input_ci.pNext = &input_divisor_ci;
}
- const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology());
+ const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, state.topology);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
- .topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()),
+ .topology = MaxwellToVK::PrimitiveTopology(device, state.topology),
.primitiveRestartEnable = state.primitive_restart_enable != 0 &&
SupportsPrimitiveRestart(input_assembly_topology),
};
@@ -400,7 +400,6 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
static constexpr std::array extended{
VK_DYNAMIC_STATE_CULL_MODE_EXT,
VK_DYNAMIC_STATE_FRONT_FACE_EXT,
- VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,
VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
new file mode 100644
index 000000000..ae26e558d
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
@@ -0,0 +1,56 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <atomic>
+#include <chrono>
+
+#include "core/settings.h"
+#include "video_core/renderer_vulkan/vk_device.h"
+#include "video_core/renderer_vulkan/vk_master_semaphore.h"
+#include "video_core/renderer_vulkan/wrapper.h"
+
+namespace Vulkan {
+
+using namespace std::chrono_literals;
+
+MasterSemaphore::MasterSemaphore(const VKDevice& device) {
+ static constexpr VkSemaphoreTypeCreateInfoKHR semaphore_type_ci{
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR,
+ .pNext = nullptr,
+ .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE_KHR,
+ .initialValue = 0,
+ };
+ static constexpr VkSemaphoreCreateInfo semaphore_ci{
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+ .pNext = &semaphore_type_ci,
+ .flags = 0,
+ };
+ semaphore = device.GetLogical().CreateSemaphore(semaphore_ci);
+
+ if (!Settings::values.renderer_debug) {
+ return;
+ }
+ // Validation layers have a bug where they fail to track resource usage when using timeline
+ // semaphores and synchronizing with GetSemaphoreCounterValueKHR. To workaround this issue, have
+ // a separate thread waiting for each timeline semaphore value.
+ debug_thread = std::thread([this] {
+ u64 counter = 0;
+ while (!shutdown) {
+ if (semaphore.Wait(counter, 10'000'000)) {
+ ++counter;
+ }
+ }
+ });
+}
+
+MasterSemaphore::~MasterSemaphore() {
+ shutdown = true;
+
+ // This thread might not be started
+ if (debug_thread.joinable()) {
+ debug_thread.join();
+ }
+}
+
+} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h
new file mode 100644
index 000000000..0e93706d7
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h
@@ -0,0 +1,70 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+#include <thread>
+
+#include "common/common_types.h"
+#include "video_core/renderer_vulkan/wrapper.h"
+
+namespace Vulkan {
+
+class VKDevice;
+
+class MasterSemaphore {
+public:
+ explicit MasterSemaphore(const VKDevice& device);
+ ~MasterSemaphore();
+
+ /// Returns the current logical tick.
+ [[nodiscard]] u64 CurrentTick() const noexcept {
+ return current_tick;
+ }
+
+ /// Returns the timeline semaphore handle.
+ [[nodiscard]] VkSemaphore Handle() const noexcept {
+ return *semaphore;
+ }
+
+ /// Returns true when a tick has been hit by the GPU.
+ [[nodiscard]] bool IsFree(u64 tick) {
+ return gpu_tick >= tick;
+ }
+
+ /// Advance to the logical tick.
+ void NextTick() noexcept {
+ ++current_tick;
+ }
+
+ /// Refresh the known GPU tick
+ void Refresh() {
+ gpu_tick = semaphore.GetCounter();
+ }
+
+ /// Waits for a tick to be hit on the GPU
+ void Wait(u64 tick) {
+ // No need to wait if the GPU is ahead of the tick
+ if (IsFree(tick)) {
+ return;
+ }
+ // Update the GPU tick and try again
+ Refresh();
+ if (IsFree(tick)) {
+ return;
+ }
+ // If none of the above is hit, fallback to a regular wait
+ semaphore.Wait(tick);
+ }
+
+private:
+ vk::Semaphore semaphore; ///< Timeline semaphore.
+ std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick.
+ std::atomic<u64> current_tick{1}; ///< Current logical tick.
+ std::atomic<bool> shutdown{false}; ///< True when the object is being destroyed.
+ std::thread debug_thread; ///< Debug thread to workaround validation layer bugs.
+};
+
+} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index cfdcdd6ab..dedc9c466 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -135,64 +135,56 @@ bool ComputePipelineCacheKey::operator==(const ComputePipelineCacheKey& rhs) con
return std::memcmp(&rhs, this, sizeof *this) == 0;
}
-Shader::Shader(Core::System& system, Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr,
- VideoCommon::Shader::ProgramCode program_code, u32 main_offset)
- : gpu_addr{gpu_addr}, program_code{std::move(program_code)},
- registry{stage, GetEngine(system, stage)}, shader_ir{this->program_code, main_offset,
- compiler_settings, registry},
- entries{GenerateShaderEntries(shader_ir)} {}
+Shader::Shader(Tegra::Engines::ConstBufferEngineInterface& engine, Tegra::Engines::ShaderType stage,
+ GPUVAddr gpu_addr_, VAddr cpu_addr, VideoCommon::Shader::ProgramCode program_code_,
+ u32 main_offset)
+ : gpu_addr(gpu_addr_), program_code(std::move(program_code_)), registry(stage, engine),
+ shader_ir(program_code, main_offset, compiler_settings, registry),
+ entries(GenerateShaderEntries(shader_ir)) {}
Shader::~Shader() = default;
-Tegra::Engines::ConstBufferEngineInterface& Shader::GetEngine(Core::System& system,
- Tegra::Engines::ShaderType stage) {
- if (stage == ShaderType::Compute) {
- return system.GPU().KeplerCompute();
- } else {
- return system.GPU().Maxwell3D();
- }
-}
-
-VKPipelineCache::VKPipelineCache(Core::System& system, RasterizerVulkan& rasterizer,
- const VKDevice& device, VKScheduler& scheduler,
- VKDescriptorPool& descriptor_pool,
- VKUpdateDescriptorQueue& update_descriptor_queue,
- VKRenderPassCache& renderpass_cache)
- : VideoCommon::ShaderCache<Shader>{rasterizer}, system{system}, device{device},
- scheduler{scheduler}, descriptor_pool{descriptor_pool},
- update_descriptor_queue{update_descriptor_queue}, renderpass_cache{renderpass_cache} {}
+VKPipelineCache::VKPipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu_,
+ Tegra::Engines::Maxwell3D& maxwell3d_,
+ Tegra::Engines::KeplerCompute& kepler_compute_,
+ Tegra::MemoryManager& gpu_memory_, const VKDevice& device_,
+ VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_,
+ VKUpdateDescriptorQueue& update_descriptor_queue_,
+ VKRenderPassCache& renderpass_cache_)
+ : VideoCommon::ShaderCache<Shader>{rasterizer}, gpu{gpu_}, maxwell3d{maxwell3d_},
+ kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_},
+ scheduler{scheduler_}, descriptor_pool{descriptor_pool_},
+ update_descriptor_queue{update_descriptor_queue_}, renderpass_cache{renderpass_cache_} {}
VKPipelineCache::~VKPipelineCache() = default;
std::array<Shader*, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() {
- const auto& gpu = system.GPU().Maxwell3D();
-
std::array<Shader*, Maxwell::MaxShaderProgram> shaders{};
+
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
const auto program{static_cast<Maxwell::ShaderProgram>(index)};
// Skip stages that are not enabled
- if (!gpu.regs.IsShaderConfigEnabled(index)) {
+ if (!maxwell3d.regs.IsShaderConfigEnabled(index)) {
continue;
}
- auto& memory_manager{system.GPU().MemoryManager()};
- const GPUVAddr program_addr{GetShaderAddress(system, program)};
- const std::optional cpu_addr = memory_manager.GpuToCpuAddress(program_addr);
+ const GPUVAddr gpu_addr{GetShaderAddress(maxwell3d, program)};
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
ASSERT(cpu_addr);
Shader* result = cpu_addr ? TryGet(*cpu_addr) : null_shader.get();
if (!result) {
- const auto host_ptr{memory_manager.GetPointer(program_addr)};
+ const u8* const host_ptr{gpu_memory.GetPointer(gpu_addr)};
// No shader found - create a new one
- constexpr u32 stage_offset = STAGE_MAIN_OFFSET;
+ static constexpr u32 stage_offset = STAGE_MAIN_OFFSET;
const auto stage = static_cast<ShaderType>(index == 0 ? 0 : index - 1);
- ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, false);
+ ProgramCode code = GetShaderCode(gpu_memory, gpu_addr, host_ptr, false);
const std::size_t size_in_bytes = code.size() * sizeof(u64);
- auto shader = std::make_unique<Shader>(system, stage, program_addr, std::move(code),
- stage_offset);
+ auto shader = std::make_unique<Shader>(maxwell3d, stage, gpu_addr, *cpu_addr,
+ std::move(code), stage_offset);
result = shader.get();
if (cpu_addr) {
@@ -215,11 +207,11 @@ VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
}
last_graphics_key = key;
- if (device.UseAsynchronousShaders() && async_shaders.IsShaderAsync(system.GPU())) {
+ if (device.UseAsynchronousShaders() && async_shaders.IsShaderAsync(gpu)) {
std::unique_lock lock{pipeline_cache};
const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
if (is_cache_miss) {
- system.GPU().ShaderNotify().MarkSharderBuilding();
+ gpu.ShaderNotify().MarkSharderBuilding();
LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
const auto [program, bindings] = DecompileShaders(key.fixed_state);
async_shaders.QueueVulkanShader(this, device, scheduler, descriptor_pool,
@@ -233,13 +225,13 @@ VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
auto& entry = pair->second;
if (is_cache_miss) {
- system.GPU().ShaderNotify().MarkSharderBuilding();
+ gpu.ShaderNotify().MarkSharderBuilding();
LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
const auto [program, bindings] = DecompileShaders(key.fixed_state);
entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool,
update_descriptor_queue, renderpass_cache, key,
bindings, program);
- system.GPU().ShaderNotify().MarkShaderComplete();
+ gpu.ShaderNotify().MarkShaderComplete();
}
last_graphics_pipeline = entry.get();
return last_graphics_pipeline;
@@ -255,22 +247,21 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach
}
LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
- auto& memory_manager = system.GPU().MemoryManager();
- const auto program_addr = key.shader;
+ const GPUVAddr gpu_addr = key.shader;
- const auto cpu_addr = memory_manager.GpuToCpuAddress(program_addr);
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
ASSERT(cpu_addr);
Shader* shader = cpu_addr ? TryGet(*cpu_addr) : null_kernel.get();
if (!shader) {
// No shader found - create a new one
- const auto host_ptr = memory_manager.GetPointer(program_addr);
+ const auto host_ptr = gpu_memory.GetPointer(gpu_addr);
- ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, true);
+ ProgramCode code = GetShaderCode(gpu_memory, gpu_addr, host_ptr, true);
const std::size_t size_in_bytes = code.size() * sizeof(u64);
- auto shader_info = std::make_unique<Shader>(system, ShaderType::Compute, program_addr,
- std::move(code), KERNEL_MAIN_OFFSET);
+ auto shader_info = std::make_unique<Shader>(kepler_compute, ShaderType::Compute, gpu_addr,
+ *cpu_addr, std::move(code), KERNEL_MAIN_OFFSET);
shader = shader_info.get();
if (cpu_addr) {
@@ -298,7 +289,7 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach
}
void VKPipelineCache::EmplacePipeline(std::unique_ptr<VKGraphicsPipeline> pipeline) {
- system.GPU().ShaderNotify().MarkShaderComplete();
+ gpu.ShaderNotify().MarkShaderComplete();
std::unique_lock lock{pipeline_cache};
graphics_cache.at(pipeline->GetCacheKey()) = std::move(pipeline);
}
@@ -339,12 +330,8 @@ void VKPipelineCache::OnShaderRemoval(Shader* shader) {
std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>>
VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
- auto& memory_manager = system.GPU().MemoryManager();
- const auto& gpu = system.GPU().Maxwell3D();
-
Specialization specialization;
- if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points ||
- device.IsExtExtendedDynamicStateSupported()) {
+ if (fixed_state.topology == Maxwell::PrimitiveTopology::Points) {
float point_size;
std::memcpy(&point_size, &fixed_state.point_size, sizeof(float));
specialization.point_size = point_size;
@@ -364,12 +351,12 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
const auto program_enum = static_cast<Maxwell::ShaderProgram>(index);
// Skip stages that are not enabled
- if (!gpu.regs.IsShaderConfigEnabled(index)) {
+ if (!maxwell3d.regs.IsShaderConfigEnabled(index)) {
continue;
}
- const GPUVAddr gpu_addr = GetShaderAddress(system, program_enum);
- const std::optional<VAddr> cpu_addr = memory_manager.GpuToCpuAddress(gpu_addr);
+ const GPUVAddr gpu_addr = GetShaderAddress(maxwell3d, program_enum);
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
Shader* const shader = cpu_addr ? TryGet(*cpu_addr) : null_shader.get();
const std::size_t stage = index == 0 ? 0 : index - 1; // Stage indices are 0 - 5
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index c04829e77..e558e6658 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -38,7 +38,6 @@ class RasterizerVulkan;
class VKComputePipeline;
class VKDescriptorPool;
class VKDevice;
-class VKFence;
class VKScheduler;
class VKUpdateDescriptorQueue;
@@ -85,7 +84,8 @@ namespace Vulkan {
class Shader {
public:
- explicit Shader(Core::System& system, Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr,
+ explicit Shader(Tegra::Engines::ConstBufferEngineInterface& engine,
+ Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, VAddr cpu_addr,
VideoCommon::Shader::ProgramCode program_code, u32 main_offset);
~Shader();
@@ -97,22 +97,19 @@ public:
return shader_ir;
}
- const VideoCommon::Shader::Registry& GetRegistry() const {
- return registry;
- }
-
const VideoCommon::Shader::ShaderIR& GetIR() const {
return shader_ir;
}
+ const VideoCommon::Shader::Registry& GetRegistry() const {
+ return registry;
+ }
+
const ShaderEntries& GetEntries() const {
return entries;
}
private:
- static Tegra::Engines::ConstBufferEngineInterface& GetEngine(Core::System& system,
- Tegra::Engines::ShaderType stage);
-
GPUVAddr gpu_addr{};
VideoCommon::Shader::ProgramCode program_code;
VideoCommon::Shader::Registry registry;
@@ -122,9 +119,11 @@ private:
class VKPipelineCache final : public VideoCommon::ShaderCache<Shader> {
public:
- explicit VKPipelineCache(Core::System& system, RasterizerVulkan& rasterizer,
- const VKDevice& device, VKScheduler& scheduler,
- VKDescriptorPool& descriptor_pool,
+ explicit VKPipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu,
+ Tegra::Engines::Maxwell3D& maxwell3d,
+ Tegra::Engines::KeplerCompute& kepler_compute,
+ Tegra::MemoryManager& gpu_memory, const VKDevice& device,
+ VKScheduler& scheduler, VKDescriptorPool& descriptor_pool,
VKUpdateDescriptorQueue& update_descriptor_queue,
VKRenderPassCache& renderpass_cache);
~VKPipelineCache() override;
@@ -145,7 +144,11 @@ private:
std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> DecompileShaders(
const FixedPipelineState& fixed_state);
- Core::System& system;
+ Tegra::GPU& gpu;
+ Tegra::Engines::Maxwell3D& maxwell3d;
+ Tegra::Engines::KeplerCompute& kepler_compute;
+ Tegra::MemoryManager& gpu_memory;
+
const VKDevice& device;
VKScheduler& scheduler;
VKDescriptorPool& descriptor_pool;
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 6cd63d090..ee2d871e3 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -9,35 +9,33 @@
#include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_query_cache.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
+#include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/wrapper.h"
namespace Vulkan {
+using VideoCore::QueryType;
+
namespace {
constexpr std::array QUERY_TARGETS = {VK_QUERY_TYPE_OCCLUSION};
-constexpr VkQueryType GetTarget(VideoCore::QueryType type) {
+constexpr VkQueryType GetTarget(QueryType type) {
return QUERY_TARGETS[static_cast<std::size_t>(type)];
}
} // Anonymous namespace
-QueryPool::QueryPool() : VKFencedPool{GROW_STEP} {}
+QueryPool::QueryPool(const VKDevice& device_, VKScheduler& scheduler, QueryType type_)
+ : ResourcePool{scheduler.GetMasterSemaphore(), GROW_STEP}, device{device_}, type{type_} {}
QueryPool::~QueryPool() = default;
-void QueryPool::Initialize(const VKDevice& device_, VideoCore::QueryType type_) {
- device = &device_;
- type = type_;
-}
-
-std::pair<VkQueryPool, u32> QueryPool::Commit(VKFence& fence) {
+std::pair<VkQueryPool, u32> QueryPool::Commit() {
std::size_t index;
do {
- index = CommitResource(fence);
+ index = CommitResource();
} while (usage[index]);
usage[index] = true;
@@ -47,7 +45,7 @@ std::pair<VkQueryPool, u32> QueryPool::Commit(VKFence& fence) {
void QueryPool::Allocate(std::size_t begin, std::size_t end) {
usage.resize(end);
- pools.push_back(device->GetLogical().CreateQueryPool({
+ pools.push_back(device.GetLogical().CreateQueryPool({
.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -68,30 +66,39 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) {
usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false;
}
-VKQueryCache::VKQueryCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
+VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory,
const VKDevice& device, VKScheduler& scheduler)
- : VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter,
- QueryPool>{system, rasterizer},
- device{device}, scheduler{scheduler} {
- for (std::size_t i = 0; i < static_cast<std::size_t>(VideoCore::NumQueryTypes); ++i) {
- query_pools[i].Initialize(device, static_cast<VideoCore::QueryType>(i));
+ : VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream,
+ HostCounter>{rasterizer, maxwell3d, gpu_memory},
+ device{device}, scheduler{scheduler}, query_pools{
+ QueryPool{device, scheduler,
+ QueryType::SamplesPassed},
+ } {}
+
+VKQueryCache::~VKQueryCache() {
+ // TODO(Rodrigo): This is a hack to destroy all HostCounter instances before the base class
+ // destructor is called. The query cache should be redesigned to have a proper ownership model
+ // instead of using shared pointers.
+ for (size_t query_type = 0; query_type < VideoCore::NumQueryTypes; ++query_type) {
+ auto& stream = Stream(static_cast<QueryType>(query_type));
+ stream.Update(false);
+ stream.Reset();
}
}
-VKQueryCache::~VKQueryCache() = default;
-
-std::pair<VkQueryPool, u32> VKQueryCache::AllocateQuery(VideoCore::QueryType type) {
- return query_pools[static_cast<std::size_t>(type)].Commit(scheduler.GetFence());
+std::pair<VkQueryPool, u32> VKQueryCache::AllocateQuery(QueryType type) {
+ return query_pools[static_cast<std::size_t>(type)].Commit();
}
-void VKQueryCache::Reserve(VideoCore::QueryType type, std::pair<VkQueryPool, u32> query) {
+void VKQueryCache::Reserve(QueryType type, std::pair<VkQueryPool, u32> query) {
query_pools[static_cast<std::size_t>(type)].Reserve(query);
}
HostCounter::HostCounter(VKQueryCache& cache, std::shared_ptr<HostCounter> dependency,
- VideoCore::QueryType type)
+ QueryType type)
: VideoCommon::HostCounterBase<VKQueryCache, HostCounter>{std::move(dependency)}, cache{cache},
- type{type}, query{cache.AllocateQuery(type)}, ticks{cache.Scheduler().Ticks()} {
+ type{type}, query{cache.AllocateQuery(type)}, tick{cache.Scheduler().CurrentTick()} {
const vk::Device* logical = &cache.Device().GetLogical();
cache.Scheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) {
logical->ResetQueryPoolEXT(query.first, query.second, 1);
@@ -109,7 +116,7 @@ void HostCounter::EndQuery() {
}
u64 HostCounter::BlockingQuery() const {
- if (ticks >= cache.Scheduler().Ticks()) {
+ if (tick >= cache.Scheduler().CurrentTick()) {
cache.Scheduler().Flush();
}
u64 data;
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h
index 40119e6d3..2e57fb75d 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.h
+++ b/src/video_core/renderer_vulkan/vk_query_cache.h
@@ -11,7 +11,7 @@
#include "common/common_types.h"
#include "video_core/query_cache.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
+#include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/renderer_vulkan/wrapper.h"
namespace VideoCore {
@@ -28,14 +28,12 @@ class VKScheduler;
using CounterStream = VideoCommon::CounterStreamBase<VKQueryCache, HostCounter>;
-class QueryPool final : public VKFencedPool {
+class QueryPool final : public ResourcePool {
public:
- explicit QueryPool();
+ explicit QueryPool(const VKDevice& device, VKScheduler& scheduler, VideoCore::QueryType type);
~QueryPool() override;
- void Initialize(const VKDevice& device, VideoCore::QueryType type);
-
- std::pair<VkQueryPool, u32> Commit(VKFence& fence);
+ std::pair<VkQueryPool, u32> Commit();
void Reserve(std::pair<VkQueryPool, u32> query);
@@ -45,18 +43,18 @@ protected:
private:
static constexpr std::size_t GROW_STEP = 512;
- const VKDevice* device = nullptr;
- VideoCore::QueryType type = {};
+ const VKDevice& device;
+ const VideoCore::QueryType type;
std::vector<vk::QueryPool> pools;
std::vector<bool> usage;
};
class VKQueryCache final
- : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter,
- QueryPool> {
+ : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter> {
public:
- explicit VKQueryCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
+ explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory,
const VKDevice& device, VKScheduler& scheduler);
~VKQueryCache();
@@ -75,6 +73,7 @@ public:
private:
const VKDevice& device;
VKScheduler& scheduler;
+ std::array<QueryPool, VideoCore::NumQueryTypes> query_pools;
};
class HostCounter final : public VideoCommon::HostCounterBase<VKQueryCache, HostCounter> {
@@ -91,7 +90,7 @@ private:
VKQueryCache& cache;
const VideoCore::QueryType type;
const std::pair<VkQueryPool, u32> query;
- const u64 ticks;
+ const u64 tick;
};
class CachedQuery : public VideoCommon::CachedQueryBase<HostCounter> {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 936f76195..e0fb8693f 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -31,7 +31,6 @@
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/vk_sampler_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -381,28 +380,28 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf) const {
}
}
-RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& renderer,
- VKScreenInfo& screen_info, const VKDevice& device,
- VKResourceManager& resource_manager,
- VKMemoryManager& memory_manager, StateTracker& state_tracker,
- VKScheduler& scheduler)
- : RasterizerAccelerated{system.Memory()}, system{system}, render_window{renderer},
- screen_info{screen_info}, device{device}, resource_manager{resource_manager},
- memory_manager{memory_manager}, state_tracker{state_tracker}, scheduler{scheduler},
- staging_pool(device, memory_manager, scheduler), descriptor_pool(device),
- update_descriptor_queue(device, scheduler), renderpass_cache(device),
+RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu_,
+ Tegra::MemoryManager& gpu_memory_,
+ Core::Memory::Memory& cpu_memory, VKScreenInfo& screen_info_,
+ const VKDevice& device_, VKMemoryManager& memory_manager_,
+ StateTracker& state_tracker_, VKScheduler& scheduler_)
+ : RasterizerAccelerated(cpu_memory), gpu(gpu_), gpu_memory(gpu_memory_),
+ maxwell3d(gpu.Maxwell3D()), kepler_compute(gpu.KeplerCompute()), screen_info(screen_info_),
+ device(device_), memory_manager(memory_manager_), state_tracker(state_tracker_),
+ scheduler(scheduler_), staging_pool(device, memory_manager, scheduler),
+ descriptor_pool(device, scheduler_), update_descriptor_queue(device, scheduler),
+ renderpass_cache(device),
quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
- texture_cache(system, *this, device, resource_manager, memory_manager, scheduler,
- staging_pool),
- pipeline_cache(system, *this, device, scheduler, descriptor_pool, update_descriptor_queue,
- renderpass_cache),
- buffer_cache(*this, system, device, memory_manager, scheduler, staging_pool),
- sampler_cache(device),
- fence_manager(system, *this, device, scheduler, texture_cache, buffer_cache, query_cache),
- query_cache(system, *this, device, scheduler),
- wfi_event{device.GetLogical().CreateNewEvent()}, async_shaders{renderer} {
+ texture_cache(*this, maxwell3d, gpu_memory, device, memory_manager, scheduler, staging_pool),
+ pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler,
+ descriptor_pool, update_descriptor_queue, renderpass_cache),
+ buffer_cache(*this, gpu_memory, cpu_memory, device, memory_manager, scheduler, staging_pool),
+ sampler_cache(device), query_cache(*this, maxwell3d, gpu_memory, device, scheduler),
+ fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device,
+ scheduler),
+ wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window) {
scheduler.SetQueryCache(query_cache);
if (device.UseAsynchronousShaders()) {
async_shaders.AllocateWorkers();
@@ -414,15 +413,13 @@ RasterizerVulkan::~RasterizerVulkan() = default;
void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
MICROPROFILE_SCOPE(Vulkan_Drawing);
+ SCOPE_EXIT({ gpu.TickWork(); });
FlushWork();
query_cache.UpdateCounters();
- SCOPE_EXIT({ system.GPU().TickWork(); });
-
- const auto& gpu = system.GPU().Maxwell3D();
GraphicsPipelineCacheKey key;
- key.fixed_state.Fill(gpu.regs, device.IsExtExtendedDynamicStateSupported());
+ key.fixed_state.Fill(maxwell3d.regs, device.IsExtExtendedDynamicStateSupported());
buffer_cache.Map(CalculateGraphicsStreamBufferSize(is_indexed));
@@ -480,8 +477,7 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
void RasterizerVulkan::Clear() {
MICROPROFILE_SCOPE(Vulkan_Clearing);
- const auto& gpu = system.GPU().Maxwell3D();
- if (!system.GPU().Maxwell3D().ShouldExecute()) {
+ if (!maxwell3d.ShouldExecute()) {
return;
}
@@ -490,7 +486,7 @@ void RasterizerVulkan::Clear() {
query_cache.UpdateCounters();
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
const bool use_color = regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
regs.clear_buffers.A;
const bool use_depth = regs.clear_buffers.Z;
@@ -559,7 +555,7 @@ void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) {
query_cache.UpdateCounters();
- const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
+ const auto& launch_desc = kepler_compute.launch_description;
auto& pipeline = pipeline_cache.GetComputePipeline({
.shader = code_addr,
.shared_memory_size = launch_desc.shared_alloc,
@@ -655,16 +651,14 @@ void RasterizerVulkan::SyncGuestHost() {
}
void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) {
- auto& gpu{system.GPU()};
if (!gpu.IsAsync()) {
- gpu.MemoryManager().Write<u32>(addr, value);
+ gpu_memory.Write<u32>(addr, value);
return;
}
fence_manager.SignalSemaphore(addr, value);
}
void RasterizerVulkan::SignalSyncPoint(u32 value) {
- auto& gpu{system.GPU()};
if (!gpu.IsAsync()) {
gpu.IncrementSyncPoint(value);
return;
@@ -673,7 +667,6 @@ void RasterizerVulkan::SignalSyncPoint(u32 value) {
}
void RasterizerVulkan::ReleaseFences() {
- auto& gpu{system.GPU()};
if (!gpu.IsAsync()) {
return;
}
@@ -751,10 +744,6 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
return true;
}
-void RasterizerVulkan::SetupDirtyFlags() {
- state_tracker.Initialize();
-}
-
void RasterizerVulkan::FlushWork() {
static constexpr u32 DRAWS_TO_DISPATCH = 4096;
@@ -778,10 +767,9 @@ void RasterizerVulkan::FlushWork() {
RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments(bool is_clear) {
MICROPROFILE_SCOPE(Vulkan_RenderTargets);
- auto& maxwell3d = system.GPU().Maxwell3D();
- auto& dirty = maxwell3d.dirty.flags;
- auto& regs = maxwell3d.regs;
+ const auto& regs = maxwell3d.regs;
+ auto& dirty = maxwell3d.dirty.flags;
const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets];
dirty[VideoCommon::Dirty::RenderTargets] = false;
@@ -844,7 +832,7 @@ std::tuple<VkFramebuffer, VkExtent2D> RasterizerVulkan::ConfigureFramebuffers(
return true;
};
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count);
for (std::size_t index = 0; index < num_attachments; ++index) {
if (try_push(color_attachments[index])) {
@@ -880,13 +868,12 @@ RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineSt
bool is_instanced) {
MICROPROFILE_SCOPE(Vulkan_Geometry);
- const auto& gpu = system.GPU().Maxwell3D();
- const auto& regs = gpu.regs;
+ const auto& regs = maxwell3d.regs;
SetupVertexArrays(buffer_bindings);
const u32 base_instance = regs.vb_base_instance;
- const u32 num_instances = is_instanced ? gpu.mme_draw.instance_count : 1;
+ const u32 num_instances = is_instanced ? maxwell3d.mme_draw.instance_count : 1;
const u32 base_vertex = is_indexed ? regs.vb_element_base : regs.vertex_buffer.first;
const u32 num_vertices = is_indexed ? regs.index_array.count : regs.vertex_buffer.count;
@@ -947,7 +934,7 @@ void RasterizerVulkan::SetupImageTransitions(
}
void RasterizerVulkan::UpdateDynamicStates() {
- auto& regs = system.GPU().Maxwell3D().regs;
+ auto& regs = maxwell3d.regs;
UpdateViewportsState(regs);
UpdateScissorsState(regs);
UpdateDepthBias(regs);
@@ -961,14 +948,13 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateDepthWriteEnable(regs);
UpdateDepthCompareOp(regs);
UpdateFrontFace(regs);
- UpdatePrimitiveTopology(regs);
UpdateStencilOp(regs);
UpdateStencilTestEnable(regs);
}
}
void RasterizerVulkan::BeginTransformFeedback() {
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
if (regs.tfb_enabled == 0) {
return;
}
@@ -1000,7 +986,7 @@ void RasterizerVulkan::BeginTransformFeedback() {
}
void RasterizerVulkan::EndTransformFeedback() {
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
if (regs.tfb_enabled == 0) {
return;
}
@@ -1013,7 +999,7 @@ void RasterizerVulkan::EndTransformFeedback() {
}
void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) {
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
const auto& vertex_array = regs.vertex_array[index];
@@ -1039,7 +1025,7 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar
if (params.num_vertices == 0) {
return;
}
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
switch (regs.draw.topology) {
case Maxwell::PrimitiveTopology::Quads: {
if (!params.is_indexed) {
@@ -1087,8 +1073,7 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar
void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, std::size_t stage) {
MICROPROFILE_SCOPE(Vulkan_ConstBuffers);
- const auto& gpu = system.GPU().Maxwell3D();
- const auto& shader_stage = gpu.state.shader_stages[stage];
+ const auto& shader_stage = maxwell3d.state.shader_stages[stage];
for (const auto& entry : entries.const_buffers) {
SetupConstBuffer(entry, shader_stage.const_buffers[entry.GetIndex()]);
}
@@ -1096,8 +1081,7 @@ void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, s
void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage) {
MICROPROFILE_SCOPE(Vulkan_GlobalBuffers);
- auto& gpu{system.GPU()};
- const auto cbufs{gpu.Maxwell3D().state.shader_stages[stage]};
+ const auto& cbufs{maxwell3d.state.shader_stages[stage]};
for (const auto& entry : entries.global_buffers) {
const auto addr = cbufs.const_buffers[entry.GetCbufIndex()].address + entry.GetCbufOffset();
@@ -1107,19 +1091,17 @@ void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries,
void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, std::size_t stage) {
MICROPROFILE_SCOPE(Vulkan_Textures);
- const auto& gpu = system.GPU().Maxwell3D();
for (const auto& entry : entries.uniform_texels) {
- const auto image = GetTextureInfo(gpu, entry, stage).tic;
+ const auto image = GetTextureInfo(maxwell3d, entry, stage).tic;
SetupUniformTexels(image, entry);
}
}
void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage) {
MICROPROFILE_SCOPE(Vulkan_Textures);
- const auto& gpu = system.GPU().Maxwell3D();
for (const auto& entry : entries.samplers) {
for (std::size_t i = 0; i < entry.size; ++i) {
- const auto texture = GetTextureInfo(gpu, entry, stage, i);
+ const auto texture = GetTextureInfo(maxwell3d, entry, stage, i);
SetupTexture(texture, entry);
}
}
@@ -1127,25 +1109,23 @@ void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::
void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, std::size_t stage) {
MICROPROFILE_SCOPE(Vulkan_Textures);
- const auto& gpu = system.GPU().Maxwell3D();
for (const auto& entry : entries.storage_texels) {
- const auto image = GetTextureInfo(gpu, entry, stage).tic;
+ const auto image = GetTextureInfo(maxwell3d, entry, stage).tic;
SetupStorageTexel(image, entry);
}
}
void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) {
MICROPROFILE_SCOPE(Vulkan_Images);
- const auto& gpu = system.GPU().Maxwell3D();
for (const auto& entry : entries.images) {
- const auto tic = GetTextureInfo(gpu, entry, stage).tic;
+ const auto tic = GetTextureInfo(maxwell3d, entry, stage).tic;
SetupImage(tic, entry);
}
}
void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) {
MICROPROFILE_SCOPE(Vulkan_ConstBuffers);
- const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
+ const auto& launch_desc = kepler_compute.launch_description;
for (const auto& entry : entries.const_buffers) {
const auto& config = launch_desc.const_buffer_config[entry.GetIndex()];
const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value();
@@ -1159,7 +1139,7 @@ void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) {
void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) {
MICROPROFILE_SCOPE(Vulkan_GlobalBuffers);
- const auto cbufs{system.GPU().KeplerCompute().launch_description.const_buffer_config};
+ const auto& cbufs{kepler_compute.launch_description.const_buffer_config};
for (const auto& entry : entries.global_buffers) {
const auto addr{cbufs[entry.GetCbufIndex()].Address() + entry.GetCbufOffset()};
SetupGlobalBuffer(entry, addr);
@@ -1168,19 +1148,17 @@ void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) {
void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) {
MICROPROFILE_SCOPE(Vulkan_Textures);
- const auto& gpu = system.GPU().KeplerCompute();
for (const auto& entry : entries.uniform_texels) {
- const auto image = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic;
+ const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic;
SetupUniformTexels(image, entry);
}
}
void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) {
MICROPROFILE_SCOPE(Vulkan_Textures);
- const auto& gpu = system.GPU().KeplerCompute();
for (const auto& entry : entries.samplers) {
for (std::size_t i = 0; i < entry.size; ++i) {
- const auto texture = GetTextureInfo(gpu, entry, ComputeShaderIndex, i);
+ const auto texture = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex, i);
SetupTexture(texture, entry);
}
}
@@ -1188,18 +1166,16 @@ void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) {
void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) {
MICROPROFILE_SCOPE(Vulkan_Textures);
- const auto& gpu = system.GPU().KeplerCompute();
for (const auto& entry : entries.storage_texels) {
- const auto image = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic;
+ const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic;
SetupStorageTexel(image, entry);
}
}
void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) {
MICROPROFILE_SCOPE(Vulkan_Images);
- const auto& gpu = system.GPU().KeplerCompute();
for (const auto& entry : entries.images) {
- const auto tic = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic;
+ const auto tic = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic;
SetupImage(tic, entry);
}
}
@@ -1223,9 +1199,8 @@ void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry,
}
void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address) {
- auto& memory_manager{system.GPU().MemoryManager()};
- const auto actual_addr = memory_manager.Read<u64>(address);
- const auto size = memory_manager.Read<u32>(address + 8);
+ const u64 actual_addr = gpu_memory.Read<u64>(address);
+ const u32 size = gpu_memory.Read<u32>(address + 8);
if (size == 0) {
// Sometimes global memory pointers don't have a proper size. Upload a dummy entry
@@ -1442,16 +1417,6 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
[front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); });
}
-void RasterizerVulkan::UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs) {
- if (!state_tracker.TouchPrimitiveTopology()) {
- return;
- }
- const Maxwell::PrimitiveTopology primitive_topology = regs.draw.topology.Value();
- scheduler.Record([this, primitive_topology](vk::CommandBuffer cmdbuf) {
- cmdbuf.SetPrimitiveTopologyEXT(MaxwellToVK::PrimitiveTopology(device, primitive_topology));
- });
-}
-
void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) {
if (!state_tracker.TouchStencilOp()) {
return;
@@ -1508,7 +1473,7 @@ std::size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const {
}
std::size_t RasterizerVulkan::CalculateVertexArraysSize() const {
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
std::size_t size = 0;
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
@@ -1523,9 +1488,8 @@ std::size_t RasterizerVulkan::CalculateVertexArraysSize() const {
}
std::size_t RasterizerVulkan::CalculateIndexBufferSize() const {
- const auto& regs = system.GPU().Maxwell3D().regs;
- return static_cast<std::size_t>(regs.index_array.count) *
- static_cast<std::size_t>(regs.index_array.FormatSizeInBytes());
+ return static_cast<std::size_t>(maxwell3d.regs.index_array.count) *
+ static_cast<std::size_t>(maxwell3d.regs.index_array.FormatSizeInBytes());
}
std::size_t RasterizerVulkan::CalculateConstBufferSize(
@@ -1540,7 +1504,7 @@ std::size_t RasterizerVulkan::CalculateConstBufferSize(
}
RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions) const {
- const auto& regs = system.GPU().Maxwell3D().regs;
+ const auto& regs = maxwell3d.regs;
const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count);
RenderPassParams params;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index f640ba649..237e51fa4 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -25,7 +25,6 @@
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_query_cache.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/vk_sampler_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -106,10 +105,11 @@ struct ImageView {
class RasterizerVulkan final : public VideoCore::RasterizerAccelerated {
public:
- explicit RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& render_window,
+ explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
+ Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
VKScreenInfo& screen_info, const VKDevice& device,
- VKResourceManager& resource_manager, VKMemoryManager& memory_manager,
- StateTracker& state_tracker, VKScheduler& scheduler);
+ VKMemoryManager& memory_manager, StateTracker& state_tracker,
+ VKScheduler& scheduler);
~RasterizerVulkan() override;
void Draw(bool is_indexed, bool is_instanced) override;
@@ -135,7 +135,6 @@ public:
const Tegra::Engines::Fermi2D::Config& copy_config) override;
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
u32 pixel_stride) override;
- void SetupDirtyFlags() override;
VideoCommon::Shader::AsyncShaders& GetAsyncShaders() {
return async_shaders;
@@ -260,7 +259,6 @@ private:
void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs);
- void UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
@@ -279,11 +277,13 @@ private:
VkBuffer DefaultBuffer();
- Core::System& system;
- Core::Frontend::EmuWindow& render_window;
+ Tegra::GPU& gpu;
+ Tegra::MemoryManager& gpu_memory;
+ Tegra::Engines::Maxwell3D& maxwell3d;
+ Tegra::Engines::KeplerCompute& kepler_compute;
+
VKScreenInfo& screen_info;
const VKDevice& device;
- VKResourceManager& resource_manager;
VKMemoryManager& memory_manager;
StateTracker& state_tracker;
VKScheduler& scheduler;
@@ -300,8 +300,8 @@ private:
VKPipelineCache pipeline_cache;
VKBufferCache buffer_cache;
VKSamplerCache sampler_cache;
- VKFenceManager fence_manager;
VKQueryCache query_cache;
+ VKFenceManager fence_manager;
vk::Buffer default_buffer;
VKMemoryCommit default_buffer_commit;
diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp
deleted file mode 100644
index f19330a36..000000000
--- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp
+++ /dev/null
@@ -1,311 +0,0 @@
-// Copyright 2018 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <algorithm>
-#include <optional>
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "video_core/renderer_vulkan/vk_device.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
-#include "video_core/renderer_vulkan/wrapper.h"
-
-namespace Vulkan {
-
-namespace {
-
-// TODO(Rodrigo): Fine tune these numbers.
-constexpr std::size_t COMMAND_BUFFER_POOL_SIZE = 0x1000;
-constexpr std::size_t FENCES_GROW_STEP = 0x40;
-
-constexpr VkFenceCreateInfo BuildFenceCreateInfo() {
- return {
- .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
- .pNext = nullptr,
- .flags = 0,
- };
-}
-
-} // Anonymous namespace
-
-class CommandBufferPool final : public VKFencedPool {
-public:
- explicit CommandBufferPool(const VKDevice& device)
- : VKFencedPool(COMMAND_BUFFER_POOL_SIZE), device{device} {}
-
- void Allocate(std::size_t begin, std::size_t end) override {
- // Command buffers are going to be commited, recorded, executed every single usage cycle.
- // They are also going to be reseted when commited.
- Pool& pool = pools.emplace_back();
- pool.handle = device.GetLogical().CreateCommandPool({
- .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
- .pNext = nullptr,
- .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT |
- VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
- .queueFamilyIndex = device.GetGraphicsFamily(),
- });
- pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE);
- }
-
- VkCommandBuffer Commit(VKFence& fence) {
- const std::size_t index = CommitResource(fence);
- const auto pool_index = index / COMMAND_BUFFER_POOL_SIZE;
- const auto sub_index = index % COMMAND_BUFFER_POOL_SIZE;
- return pools[pool_index].cmdbufs[sub_index];
- }
-
-private:
- struct Pool {
- vk::CommandPool handle;
- vk::CommandBuffers cmdbufs;
- };
-
- const VKDevice& device;
- std::vector<Pool> pools;
-};
-
-VKResource::VKResource() = default;
-
-VKResource::~VKResource() = default;
-
-VKFence::VKFence(const VKDevice& device)
- : device{device}, handle{device.GetLogical().CreateFence(BuildFenceCreateInfo())} {}
-
-VKFence::~VKFence() = default;
-
-void VKFence::Wait() {
- switch (const VkResult result = handle.Wait()) {
- case VK_SUCCESS:
- return;
- case VK_ERROR_DEVICE_LOST:
- device.ReportLoss();
- [[fallthrough]];
- default:
- throw vk::Exception(result);
- }
-}
-
-void VKFence::Release() {
- ASSERT(is_owned);
- is_owned = false;
-}
-
-void VKFence::Commit() {
- is_owned = true;
- is_used = true;
-}
-
-bool VKFence::Tick(bool gpu_wait, bool owner_wait) {
- if (!is_used) {
- // If a fence is not used it's always free.
- return true;
- }
- if (is_owned && !owner_wait) {
- // The fence is still being owned (Release has not been called) and ownership wait has
- // not been asked.
- return false;
- }
-
- if (gpu_wait) {
- // Wait for the fence if it has been requested.
- (void)handle.Wait();
- } else {
- if (handle.GetStatus() != VK_SUCCESS) {
- // Vulkan fence is not ready, not much it can do here
- return false;
- }
- }
-
- // Broadcast resources their free state.
- for (auto* resource : protected_resources) {
- resource->OnFenceRemoval(this);
- }
- protected_resources.clear();
-
- // Prepare fence for reusage.
- handle.Reset();
- is_used = false;
- return true;
-}
-
-void VKFence::Protect(VKResource* resource) {
- protected_resources.push_back(resource);
-}
-
-void VKFence::Unprotect(VKResource* resource) {
- const auto it = std::find(protected_resources.begin(), protected_resources.end(), resource);
- ASSERT(it != protected_resources.end());
-
- resource->OnFenceRemoval(this);
- protected_resources.erase(it);
-}
-
-void VKFence::RedirectProtection(VKResource* old_resource, VKResource* new_resource) noexcept {
- std::replace(std::begin(protected_resources), std::end(protected_resources), old_resource,
- new_resource);
-}
-
-VKFenceWatch::VKFenceWatch() = default;
-
-VKFenceWatch::VKFenceWatch(VKFence& initial_fence) {
- Watch(initial_fence);
-}
-
-VKFenceWatch::VKFenceWatch(VKFenceWatch&& rhs) noexcept {
- fence = std::exchange(rhs.fence, nullptr);
- if (fence) {
- fence->RedirectProtection(&rhs, this);
- }
-}
-
-VKFenceWatch& VKFenceWatch::operator=(VKFenceWatch&& rhs) noexcept {
- fence = std::exchange(rhs.fence, nullptr);
- if (fence) {
- fence->RedirectProtection(&rhs, this);
- }
- return *this;
-}
-
-VKFenceWatch::~VKFenceWatch() {
- if (fence) {
- fence->Unprotect(this);
- }
-}
-
-void VKFenceWatch::Wait() {
- if (fence == nullptr) {
- return;
- }
- fence->Wait();
- fence->Unprotect(this);
-}
-
-void VKFenceWatch::Watch(VKFence& new_fence) {
- Wait();
- fence = &new_fence;
- fence->Protect(this);
-}
-
-bool VKFenceWatch::TryWatch(VKFence& new_fence) {
- if (fence) {
- return false;
- }
- fence = &new_fence;
- fence->Protect(this);
- return true;
-}
-
-void VKFenceWatch::OnFenceRemoval(VKFence* signaling_fence) {
- ASSERT_MSG(signaling_fence == fence, "Removing the wrong fence");
- fence = nullptr;
-}
-
-VKFencedPool::VKFencedPool(std::size_t grow_step) : grow_step{grow_step} {}
-
-VKFencedPool::~VKFencedPool() = default;
-
-std::size_t VKFencedPool::CommitResource(VKFence& fence) {
- const auto Search = [&](std::size_t begin, std::size_t end) -> std::optional<std::size_t> {
- for (std::size_t iterator = begin; iterator < end; ++iterator) {
- if (watches[iterator]->TryWatch(fence)) {
- // The resource is now being watched, a free resource was successfully found.
- return iterator;
- }
- }
- return {};
- };
- // Try to find a free resource from the hinted position to the end.
- auto found = Search(free_iterator, watches.size());
- if (!found) {
- // Search from beginning to the hinted position.
- found = Search(0, free_iterator);
- if (!found) {
- // Both searches failed, the pool is full; handle it.
- const std::size_t free_resource = ManageOverflow();
-
- // Watch will wait for the resource to be free.
- watches[free_resource]->Watch(fence);
- found = free_resource;
- }
- }
- // Free iterator is hinted to the resource after the one that's been commited.
- free_iterator = (*found + 1) % watches.size();
- return *found;
-}
-
-std::size_t VKFencedPool::ManageOverflow() {
- const std::size_t old_capacity = watches.size();
- Grow();
-
- // The last entry is guaranted to be free, since it's the first element of the freshly
- // allocated resources.
- return old_capacity;
-}
-
-void VKFencedPool::Grow() {
- const std::size_t old_capacity = watches.size();
- watches.resize(old_capacity + grow_step);
- std::generate(watches.begin() + old_capacity, watches.end(),
- []() { return std::make_unique<VKFenceWatch>(); });
- Allocate(old_capacity, old_capacity + grow_step);
-}
-
-VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} {
- GrowFences(FENCES_GROW_STEP);
- command_buffer_pool = std::make_unique<CommandBufferPool>(device);
-}
-
-VKResourceManager::~VKResourceManager() = default;
-
-VKFence& VKResourceManager::CommitFence() {
- const auto StepFences = [&](bool gpu_wait, bool owner_wait) -> VKFence* {
- const auto Tick = [=](auto& fence) { return fence->Tick(gpu_wait, owner_wait); };
- const auto hinted = fences.begin() + fences_iterator;
-
- auto it = std::find_if(hinted, fences.end(), Tick);
- if (it == fences.end()) {
- it = std::find_if(fences.begin(), hinted, Tick);
- if (it == hinted) {
- return nullptr;
- }
- }
- fences_iterator = std::distance(fences.begin(), it) + 1;
- if (fences_iterator >= fences.size())
- fences_iterator = 0;
-
- auto& fence = *it;
- fence->Commit();
- return fence.get();
- };
-
- VKFence* found_fence = StepFences(false, false);
- if (!found_fence) {
- // Try again, this time waiting.
- found_fence = StepFences(true, false);
-
- if (!found_fence) {
- // Allocate new fences and try again.
- LOG_INFO(Render_Vulkan, "Allocating new fences {} -> {}", fences.size(),
- fences.size() + FENCES_GROW_STEP);
-
- GrowFences(FENCES_GROW_STEP);
- found_fence = StepFences(true, false);
- ASSERT(found_fence != nullptr);
- }
- }
- return *found_fence;
-}
-
-VkCommandBuffer VKResourceManager::CommitCommandBuffer(VKFence& fence) {
- return command_buffer_pool->Commit(fence);
-}
-
-void VKResourceManager::GrowFences(std::size_t new_fences_count) {
- const std::size_t previous_size = fences.size();
- fences.resize(previous_size + new_fences_count);
-
- std::generate(fences.begin() + previous_size, fences.end(),
- [this] { return std::make_unique<VKFence>(device); });
-}
-
-} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h
deleted file mode 100644
index f683d2276..000000000
--- a/src/video_core/renderer_vulkan/vk_resource_manager.h
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2018 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <cstddef>
-#include <memory>
-#include <vector>
-#include "video_core/renderer_vulkan/wrapper.h"
-
-namespace Vulkan {
-
-class VKDevice;
-class VKFence;
-class VKResourceManager;
-
-class CommandBufferPool;
-
-/// Interface for a Vulkan resource
-class VKResource {
-public:
- explicit VKResource();
- virtual ~VKResource();
-
- /**
- * Signals the object that an owning fence has been signaled.
- * @param signaling_fence Fence that signals its usage end.
- */
- virtual void OnFenceRemoval(VKFence* signaling_fence) = 0;
-};
-
-/**
- * Fences take ownership of objects, protecting them from GPU-side or driver-side concurrent access.
- * They must be commited from the resource manager. Their usage flow is: commit the fence from the
- * resource manager, protect resources with it and use them, send the fence to an execution queue
- * and Wait for it if needed and then call Release. Used resources will automatically be signaled
- * when they are free to be reused.
- * @brief Protects resources for concurrent usage and signals its release.
- */
-class VKFence {
- friend class VKResourceManager;
-
-public:
- explicit VKFence(const VKDevice& device);
- ~VKFence();
-
- /**
- * Waits for the fence to be signaled.
- * @warning You must have ownership of the fence and it has to be previously sent to a queue to
- * call this function.
- */
- void Wait();
-
- /**
- * Releases ownership of the fence. Pass after it has been sent to an execution queue.
- * Unmanaged usage of the fence after the call will result in undefined behavior because it may
- * be being used for something else.
- */
- void Release();
-
- /// Protects a resource with this fence.
- void Protect(VKResource* resource);
-
- /// Removes protection for a resource.
- void Unprotect(VKResource* resource);
-
- /// Redirects one protected resource to a new address.
- void RedirectProtection(VKResource* old_resource, VKResource* new_resource) noexcept;
-
- /// Retreives the fence.
- operator VkFence() const {
- return *handle;
- }
-
-private:
- /// Take ownership of the fence.
- void Commit();
-
- /**
- * Updates the fence status.
- * @warning Waiting for the owner might soft lock the execution.
- * @param gpu_wait Wait for the fence to be signaled by the driver.
- * @param owner_wait Wait for the owner to signal its freedom.
- * @returns True if the fence is free. Waiting for gpu and owner will always return true.
- */
- bool Tick(bool gpu_wait, bool owner_wait);
-
- const VKDevice& device; ///< Device handler
- vk::Fence handle; ///< Vulkan fence
- std::vector<VKResource*> protected_resources; ///< List of resources protected by this fence
- bool is_owned = false; ///< The fence has been commited but not released yet.
- bool is_used = false; ///< The fence has been commited but it has not been checked to be free.
-};
-
-/**
- * A fence watch is used to keep track of the usage of a fence and protect a resource or set of
- * resources without having to inherit VKResource from their handlers.
- */
-class VKFenceWatch final : public VKResource {
-public:
- explicit VKFenceWatch();
- VKFenceWatch(VKFence& initial_fence);
- VKFenceWatch(VKFenceWatch&&) noexcept;
- VKFenceWatch(const VKFenceWatch&) = delete;
- ~VKFenceWatch() override;
-
- VKFenceWatch& operator=(VKFenceWatch&&) noexcept;
-
- /// Waits for the fence to be released.
- void Wait();
-
- /**
- * Waits for a previous fence and watches a new one.
- * @param new_fence New fence to wait to.
- */
- void Watch(VKFence& new_fence);
-
- /**
- * Checks if it's currently being watched and starts watching it if it's available.
- * @returns True if a watch has started, false if it's being watched.
- */
- bool TryWatch(VKFence& new_fence);
-
- void OnFenceRemoval(VKFence* signaling_fence) override;
-
- /**
- * Do not use it paired with Watch. Use TryWatch instead.
- * Returns true when the watch is free.
- */
- bool IsUsed() const {
- return fence != nullptr;
- }
-
-private:
- VKFence* fence{}; ///< Fence watching this resource. nullptr when the watch is free.
-};
-
-/**
- * Handles a pool of resources protected by fences. Manages resource overflow allocating more
- * resources.
- */
-class VKFencedPool {
-public:
- explicit VKFencedPool(std::size_t grow_step);
- virtual ~VKFencedPool();
-
-protected:
- /**
- * Commits a free resource and protects it with a fence. It may allocate new resources.
- * @param fence Fence that protects the commited resource.
- * @returns Index of the resource commited.
- */
- std::size_t CommitResource(VKFence& fence);
-
- /// Called when a chunk of resources have to be allocated.
- virtual void Allocate(std::size_t begin, std::size_t end) = 0;
-
-private:
- /// Manages pool overflow allocating new resources.
- std::size_t ManageOverflow();
-
- /// Allocates a new page of resources.
- void Grow();
-
- std::size_t grow_step = 0; ///< Number of new resources created after an overflow
- std::size_t free_iterator = 0; ///< Hint to where the next free resources is likely to be found
- std::vector<std::unique_ptr<VKFenceWatch>> watches; ///< Set of watched resources
-};
-
-/**
- * The resource manager handles all resources that can be protected with a fence avoiding
- * driver-side or GPU-side concurrent usage. Usage is documented in VKFence.
- */
-class VKResourceManager final {
-public:
- explicit VKResourceManager(const VKDevice& device);
- ~VKResourceManager();
-
- /// Commits a fence. It has to be sent to a queue and released.
- VKFence& CommitFence();
-
- /// Commits an unused command buffer and protects it with a fence.
- VkCommandBuffer CommitCommandBuffer(VKFence& fence);
-
-private:
- /// Allocates new fences.
- void GrowFences(std::size_t new_fences_count);
-
- const VKDevice& device; ///< Device handler.
- std::size_t fences_iterator = 0; ///< Index where a free fence is likely to be found.
- std::vector<std::unique_ptr<VKFence>> fences; ///< Pool of fences.
- std::unique_ptr<CommandBufferPool> command_buffer_pool; ///< Pool of command buffers.
-};
-
-} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_resource_pool.cpp b/src/video_core/renderer_vulkan/vk_resource_pool.cpp
new file mode 100644
index 000000000..ee274ac59
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_resource_pool.cpp
@@ -0,0 +1,63 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <optional>
+
+#include "video_core/renderer_vulkan/vk_master_semaphore.h"
+#include "video_core/renderer_vulkan/vk_resource_pool.h"
+
+namespace Vulkan {
+
+ResourcePool::ResourcePool(MasterSemaphore& master_semaphore_, size_t grow_step_)
+ : master_semaphore{master_semaphore_}, grow_step{grow_step_} {}
+
+ResourcePool::~ResourcePool() = default;
+
+size_t ResourcePool::CommitResource() {
+ // Refresh semaphore to query updated results
+ master_semaphore.Refresh();
+
+ const auto search = [this](size_t begin, size_t end) -> std::optional<size_t> {
+ for (size_t iterator = begin; iterator < end; ++iterator) {
+ if (master_semaphore.IsFree(ticks[iterator])) {
+ ticks[iterator] = master_semaphore.CurrentTick();
+ return iterator;
+ }
+ }
+ return {};
+ };
+ // Try to find a free resource from the hinted position to the end.
+ auto found = search(free_iterator, ticks.size());
+ if (!found) {
+ // Search from beginning to the hinted position.
+ found = search(0, free_iterator);
+ if (!found) {
+ // Both searches failed, the pool is full; handle it.
+ const size_t free_resource = ManageOverflow();
+
+ ticks[free_resource] = master_semaphore.CurrentTick();
+ found = free_resource;
+ }
+ }
+ // Free iterator is hinted to the resource after the one that's been commited.
+ free_iterator = (*found + 1) % ticks.size();
+ return *found;
+}
+
+size_t ResourcePool::ManageOverflow() {
+ const size_t old_capacity = ticks.size();
+ Grow();
+
+ // The last entry is guaranted to be free, since it's the first element of the freshly
+ // allocated resources.
+ return old_capacity;
+}
+
+void ResourcePool::Grow() {
+ const size_t old_capacity = ticks.size();
+ ticks.resize(old_capacity + grow_step);
+ Allocate(old_capacity, old_capacity + grow_step);
+}
+
+} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_resource_pool.h b/src/video_core/renderer_vulkan/vk_resource_pool.h
new file mode 100644
index 000000000..a018c7ec2
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_resource_pool.h
@@ -0,0 +1,43 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+
+#include "common/common_types.h"
+
+namespace Vulkan {
+
+class MasterSemaphore;
+
+/**
+ * Handles a pool of resources protected by fences. Manages resource overflow allocating more
+ * resources.
+ */
+class ResourcePool {
+public:
+ explicit ResourcePool(MasterSemaphore& master_semaphore, size_t grow_step);
+ virtual ~ResourcePool();
+
+protected:
+ size_t CommitResource();
+
+ /// Called when a chunk of resources have to be allocated.
+ virtual void Allocate(size_t begin, size_t end) = 0;
+
+private:
+ /// Manages pool overflow allocating new resources.
+ size_t ManageOverflow();
+
+ /// Allocates a new page of resources.
+ void Grow();
+
+ MasterSemaphore& master_semaphore;
+ size_t grow_step = 0; ///< Number of new resources created after an overflow
+ size_t free_iterator = 0; ///< Hint to where the next free resources is likely to be found
+ std::vector<u64> ticks; ///< Ticks for each resource
+};
+
+} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index dbbd0961a..1a483dc71 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -10,9 +10,10 @@
#include "common/microprofile.h"
#include "common/thread.h"
+#include "video_core/renderer_vulkan/vk_command_pool.h"
#include "video_core/renderer_vulkan/vk_device.h"
+#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_query_cache.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_state_tracker.h"
#include "video_core/renderer_vulkan/wrapper.h"
@@ -35,10 +36,10 @@ void VKScheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf) {
last = nullptr;
}
-VKScheduler::VKScheduler(const VKDevice& device, VKResourceManager& resource_manager,
- StateTracker& state_tracker)
- : device{device}, resource_manager{resource_manager}, state_tracker{state_tracker},
- next_fence{&resource_manager.CommitFence()} {
+VKScheduler::VKScheduler(const VKDevice& device_, StateTracker& state_tracker_)
+ : device{device_}, state_tracker{state_tracker_},
+ master_semaphore{std::make_unique<MasterSemaphore>(device)},
+ command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} {
AcquireNewChunk();
AllocateNewContext();
worker_thread = std::thread(&VKScheduler::WorkerThread, this);
@@ -50,20 +51,27 @@ VKScheduler::~VKScheduler() {
worker_thread.join();
}
-void VKScheduler::Flush(bool release_fence, VkSemaphore semaphore) {
+u64 VKScheduler::CurrentTick() const noexcept {
+ return master_semaphore->CurrentTick();
+}
+
+bool VKScheduler::IsFree(u64 tick) const noexcept {
+ return master_semaphore->IsFree(tick);
+}
+
+void VKScheduler::Wait(u64 tick) {
+ master_semaphore->Wait(tick);
+}
+
+void VKScheduler::Flush(VkSemaphore semaphore) {
SubmitExecution(semaphore);
- if (release_fence) {
- current_fence->Release();
- }
AllocateNewContext();
}
-void VKScheduler::Finish(bool release_fence, VkSemaphore semaphore) {
+void VKScheduler::Finish(VkSemaphore semaphore) {
+ const u64 presubmit_tick = CurrentTick();
SubmitExecution(semaphore);
- current_fence->Wait();
- if (release_fence) {
- current_fence->Release();
- }
+ Wait(presubmit_tick);
AllocateNewContext();
}
@@ -160,18 +168,38 @@ void VKScheduler::SubmitExecution(VkSemaphore semaphore) {
current_cmdbuf.End();
+ const VkSemaphore timeline_semaphore = master_semaphore->Handle();
+ const u32 num_signal_semaphores = semaphore ? 2U : 1U;
+
+ const u64 signal_value = master_semaphore->CurrentTick();
+ const u64 wait_value = signal_value - 1;
+ const VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+
+ master_semaphore->NextTick();
+
+ const std::array signal_values{signal_value, u64(0)};
+ const std::array signal_semaphores{timeline_semaphore, semaphore};
+
+ const VkTimelineSemaphoreSubmitInfoKHR timeline_si{
+ .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR,
+ .pNext = nullptr,
+ .waitSemaphoreValueCount = 1,
+ .pWaitSemaphoreValues = &wait_value,
+ .signalSemaphoreValueCount = num_signal_semaphores,
+ .pSignalSemaphoreValues = signal_values.data(),
+ };
const VkSubmitInfo submit_info{
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
- .pNext = nullptr,
- .waitSemaphoreCount = 0,
- .pWaitSemaphores = nullptr,
- .pWaitDstStageMask = nullptr,
+ .pNext = &timeline_si,
+ .waitSemaphoreCount = 1,
+ .pWaitSemaphores = &timeline_semaphore,
+ .pWaitDstStageMask = &wait_stage_mask,
.commandBufferCount = 1,
.pCommandBuffers = current_cmdbuf.address(),
- .signalSemaphoreCount = semaphore ? 1U : 0U,
- .pSignalSemaphores = &semaphore,
+ .signalSemaphoreCount = num_signal_semaphores,
+ .pSignalSemaphores = signal_semaphores.data(),
};
- switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info, *current_fence)) {
+ switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info)) {
case VK_SUCCESS:
break;
case VK_ERROR_DEVICE_LOST:
@@ -183,14 +211,9 @@ void VKScheduler::SubmitExecution(VkSemaphore semaphore) {
}
void VKScheduler::AllocateNewContext() {
- ++ticks;
-
std::unique_lock lock{mutex};
- current_fence = next_fence;
- next_fence = &resource_manager.CommitFence();
- current_cmdbuf = vk::CommandBuffer(resource_manager.CommitCommandBuffer(*current_fence),
- device.GetDispatchLoader());
+ current_cmdbuf = vk::CommandBuffer(command_pool->Commit(), device.GetDispatchLoader());
current_cmdbuf.Begin({
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index 970a65566..7be8a19f0 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -16,42 +16,33 @@
namespace Vulkan {
+class CommandPool;
+class MasterSemaphore;
class StateTracker;
class VKDevice;
-class VKFence;
class VKQueryCache;
-class VKResourceManager;
-
-class VKFenceView {
-public:
- VKFenceView() = default;
- VKFenceView(VKFence* const& fence) : fence{fence} {}
-
- VKFence* operator->() const noexcept {
- return fence;
- }
-
- operator VKFence&() const noexcept {
- return *fence;
- }
-
-private:
- VKFence* const& fence;
-};
/// The scheduler abstracts command buffer and fence management with an interface that's able to do
/// OpenGL-like operations on Vulkan command buffers.
class VKScheduler {
public:
- explicit VKScheduler(const VKDevice& device, VKResourceManager& resource_manager,
- StateTracker& state_tracker);
+ explicit VKScheduler(const VKDevice& device, StateTracker& state_tracker);
~VKScheduler();
+ /// Returns the current command buffer tick.
+ [[nodiscard]] u64 CurrentTick() const noexcept;
+
+ /// Returns true when a tick has been triggered by the GPU.
+ [[nodiscard]] bool IsFree(u64 tick) const noexcept;
+
+ /// Waits for the given tick to trigger on the GPU.
+ void Wait(u64 tick);
+
/// Sends the current execution context to the GPU.
- void Flush(bool release_fence = true, VkSemaphore semaphore = nullptr);
+ void Flush(VkSemaphore semaphore = nullptr);
/// Sends the current execution context to the GPU and waits for it to complete.
- void Finish(bool release_fence = true, VkSemaphore semaphore = nullptr);
+ void Finish(VkSemaphore semaphore = nullptr);
/// Waits for the worker thread to finish executing everything. After this function returns it's
/// safe to touch worker resources.
@@ -86,14 +77,9 @@ public:
(void)chunk->Record(command);
}
- /// Gets a reference to the current fence.
- VKFenceView GetFence() const {
- return current_fence;
- }
-
- /// Returns the current command buffer tick.
- u64 Ticks() const {
- return ticks;
+ /// Returns the master timeline semaphore.
+ [[nodiscard]] MasterSemaphore& GetMasterSemaphore() const noexcept {
+ return *master_semaphore;
}
private:
@@ -171,6 +157,13 @@ private:
std::array<u8, 0x8000> data{};
};
+ struct State {
+ VkRenderPass renderpass = nullptr;
+ VkFramebuffer framebuffer = nullptr;
+ VkExtent2D render_area = {0, 0};
+ VkPipeline graphics_pipeline = nullptr;
+ };
+
void WorkerThread();
void SubmitExecution(VkSemaphore semaphore);
@@ -186,30 +179,23 @@ private:
void AcquireNewChunk();
const VKDevice& device;
- VKResourceManager& resource_manager;
StateTracker& state_tracker;
+ std::unique_ptr<MasterSemaphore> master_semaphore;
+ std::unique_ptr<CommandPool> command_pool;
+
VKQueryCache* query_cache = nullptr;
vk::CommandBuffer current_cmdbuf;
- VKFence* current_fence = nullptr;
- VKFence* next_fence = nullptr;
-
- struct State {
- VkRenderPass renderpass = nullptr;
- VkFramebuffer framebuffer = nullptr;
- VkExtent2D render_area = {0, 0};
- VkPipeline graphics_pipeline = nullptr;
- } state;
std::unique_ptr<CommandChunk> chunk;
std::thread worker_thread;
+ State state;
Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_queue;
Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_reserve;
std::mutex mutex;
std::condition_variable cv;
- std::atomic<u64> ticks = 0;
bool quit = false;
};
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
index 5eca0ab91..2fd3b7f39 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -10,36 +10,18 @@
#include "common/bit_util.h"
#include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_device.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
#include "video_core/renderer_vulkan/wrapper.h"
namespace Vulkan {
-VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer, VKFence& fence,
- u64 last_epoch)
- : buffer{std::move(buffer)}, watch{fence}, last_epoch{last_epoch} {}
+VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_)
+ : buffer{std::move(buffer_)} {}
-VKStagingBufferPool::StagingBuffer::StagingBuffer(StagingBuffer&& rhs) noexcept {
- buffer = std::move(rhs.buffer);
- watch = std::move(rhs.watch);
- last_epoch = rhs.last_epoch;
-}
-
-VKStagingBufferPool::StagingBuffer::~StagingBuffer() = default;
-
-VKStagingBufferPool::StagingBuffer& VKStagingBufferPool::StagingBuffer::operator=(
- StagingBuffer&& rhs) noexcept {
- buffer = std::move(rhs.buffer);
- watch = std::move(rhs.watch);
- last_epoch = rhs.last_epoch;
- return *this;
-}
-
-VKStagingBufferPool::VKStagingBufferPool(const VKDevice& device, VKMemoryManager& memory_manager,
- VKScheduler& scheduler)
- : device{device}, memory_manager{memory_manager}, scheduler{scheduler} {}
+VKStagingBufferPool::VKStagingBufferPool(const VKDevice& device_, VKMemoryManager& memory_manager_,
+ VKScheduler& scheduler_)
+ : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {}
VKStagingBufferPool::~VKStagingBufferPool() = default;
@@ -51,7 +33,6 @@ VKBuffer& VKStagingBufferPool::GetUnusedBuffer(std::size_t size, bool host_visib
}
void VKStagingBufferPool::TickFrame() {
- ++epoch;
current_delete_level = (current_delete_level + 1) % NumLevels;
ReleaseCache(true);
@@ -59,11 +40,12 @@ void VKStagingBufferPool::TickFrame() {
}
VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) {
- for (auto& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) {
- if (entry.watch.TryWatch(scheduler.GetFence())) {
- entry.last_epoch = epoch;
- return &*entry.buffer;
+ for (StagingBuffer& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) {
+ if (!scheduler.IsFree(entry.tick)) {
+ continue;
}
+ entry.tick = scheduler.CurrentTick();
+ return &*entry.buffer;
}
return nullptr;
}
@@ -86,8 +68,10 @@ VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_v
});
buffer->commit = memory_manager.Commit(buffer->handle, host_visible);
- auto& entries = GetCache(host_visible)[log2].entries;
- return *entries.emplace_back(std::move(buffer), scheduler.GetFence(), epoch).buffer;
+ std::vector<StagingBuffer>& entries = GetCache(host_visible)[log2].entries;
+ StagingBuffer& entry = entries.emplace_back(std::move(buffer));
+ entry.tick = scheduler.CurrentTick();
+ return *entry.buffer;
}
VKStagingBufferPool::StagingBuffersCache& VKStagingBufferPool::GetCache(bool host_visible) {
@@ -109,9 +93,8 @@ u64 VKStagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, std::size_t lo
auto& entries = staging.entries;
const std::size_t old_size = entries.size();
- const auto is_deleteable = [this](const auto& entry) {
- static constexpr u64 epochs_to_destroy = 180;
- return entry.last_epoch + epochs_to_destroy < epoch && !entry.watch.IsUsed();
+ const auto is_deleteable = [this](const StagingBuffer& entry) {
+ return scheduler.IsFree(entry.tick);
};
const std::size_t begin_offset = staging.delete_index;
const std::size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size);
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
index 3c4901437..2dd5049ac 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
@@ -10,13 +10,11 @@
#include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_memory_manager.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/wrapper.h"
namespace Vulkan {
class VKDevice;
-class VKFenceWatch;
class VKScheduler;
struct VKBuffer final {
@@ -36,16 +34,10 @@ public:
private:
struct StagingBuffer final {
- explicit StagingBuffer(std::unique_ptr<VKBuffer> buffer, VKFence& fence, u64 last_epoch);
- StagingBuffer(StagingBuffer&& rhs) noexcept;
- StagingBuffer(const StagingBuffer&) = delete;
- ~StagingBuffer();
-
- StagingBuffer& operator=(StagingBuffer&& rhs) noexcept;
+ explicit StagingBuffer(std::unique_ptr<VKBuffer> buffer);
std::unique_ptr<VKBuffer> buffer;
- VKFenceWatch watch;
- u64 last_epoch = 0;
+ u64 tick = 0;
};
struct StagingBuffers final {
@@ -73,8 +65,6 @@ private:
StagingBuffersCache host_staging_buffers;
StagingBuffersCache device_staging_buffers;
- u64 epoch = 0;
-
std::size_t current_delete_level = 0;
};
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
index 9151d9fb1..5d2c4a796 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
@@ -42,7 +42,6 @@ Flags MakeInvalidationFlags() {
flags[DepthWriteEnable] = true;
flags[DepthCompareOp] = true;
flags[FrontFace] = true;
- flags[PrimitiveTopology] = true;
flags[StencilOp] = true;
flags[StencilTestEnable] = true;
return flags;
@@ -112,10 +111,6 @@ void SetupDirtyFrontFace(Tables& tables) {
table[OFF(screen_y_control)] = FrontFace;
}
-void SetupDirtyPrimitiveTopology(Tables& tables) {
- tables[0][OFF(draw.topology)] = PrimitiveTopology;
-}
-
void SetupDirtyStencilOp(Tables& tables) {
auto& table = tables[0];
table[OFF(stencil_front_op_fail)] = StencilOp;
@@ -137,12 +132,9 @@ void SetupDirtyStencilTestEnable(Tables& tables) {
} // Anonymous namespace
-StateTracker::StateTracker(Core::System& system)
- : system{system}, invalidation_flags{MakeInvalidationFlags()} {}
-
-void StateTracker::Initialize() {
- auto& dirty = system.GPU().Maxwell3D().dirty;
- auto& tables = dirty.tables;
+StateTracker::StateTracker(Tegra::GPU& gpu)
+ : flags{gpu.Maxwell3D().dirty.flags}, invalidation_flags{MakeInvalidationFlags()} {
+ auto& tables = gpu.Maxwell3D().dirty.tables;
SetupDirtyRenderTargets(tables);
SetupDirtyViewports(tables);
SetupDirtyScissors(tables);
@@ -156,13 +148,8 @@ void StateTracker::Initialize() {
SetupDirtyDepthWriteEnable(tables);
SetupDirtyDepthCompareOp(tables);
SetupDirtyFrontFace(tables);
- SetupDirtyPrimitiveTopology(tables);
SetupDirtyStencilOp(tables);
SetupDirtyStencilTestEnable(tables);
}
-void StateTracker::InvalidateCommandBufferState() {
- system.GPU().Maxwell3D().dirty.flags |= invalidation_flags;
-}
-
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h
index 54ca0d6c6..1de789e57 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.h
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.h
@@ -32,7 +32,6 @@ enum : u8 {
DepthWriteEnable,
DepthCompareOp,
FrontFace,
- PrimitiveTopology,
StencilOp,
StencilTestEnable,
@@ -43,12 +42,15 @@ static_assert(Last <= std::numeric_limits<u8>::max());
} // namespace Dirty
class StateTracker {
-public:
- explicit StateTracker(Core::System& system);
+ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
- void Initialize();
+public:
+ explicit StateTracker(Tegra::GPU& gpu);
- void InvalidateCommandBufferState();
+ void InvalidateCommandBufferState() {
+ flags |= invalidation_flags;
+ current_topology = INVALID_TOPOLOGY;
+ }
bool TouchViewports() {
return Exchange(Dirty::Viewports, false);
@@ -102,10 +104,6 @@ public:
return Exchange(Dirty::FrontFace, false);
}
- bool TouchPrimitiveTopology() {
- return Exchange(Dirty::PrimitiveTopology, false);
- }
-
bool TouchStencilOp() {
return Exchange(Dirty::StencilOp, false);
}
@@ -114,16 +112,24 @@ public:
return Exchange(Dirty::StencilTestEnable, false);
}
+ bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) {
+ const bool has_changed = current_topology != new_topology;
+ current_topology = new_topology;
+ return has_changed;
+ }
+
private:
+ static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u);
+
bool Exchange(std::size_t id, bool new_value) const noexcept {
- auto& flags = system.GPU().Maxwell3D().dirty.flags;
const bool is_dirty = flags[id];
flags[id] = new_value;
return is_dirty;
}
- Core::System& system;
+ Tegra::Engines::Maxwell3D::DirtyState::Flags& flags;
Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags;
+ Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY;
};
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
index a5526a3f5..1b59612b9 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
@@ -11,7 +11,6 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "video_core/renderer_vulkan/vk_device.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/wrapper.h"
@@ -57,9 +56,9 @@ u32 GetMemoryType(const VkPhysicalDeviceMemoryProperties& properties,
} // Anonymous namespace
-VKStreamBuffer::VKStreamBuffer(const VKDevice& device, VKScheduler& scheduler,
+VKStreamBuffer::VKStreamBuffer(const VKDevice& device_, VKScheduler& scheduler_,
VkBufferUsageFlags usage)
- : device{device}, scheduler{scheduler} {
+ : device{device_}, scheduler{scheduler_} {
CreateBuffers(usage);
ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE);
ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE);
@@ -111,7 +110,7 @@ void VKStreamBuffer::Unmap(u64 size) {
}
auto& watch = current_watches[current_watch_cursor++];
watch.upper_bound = offset;
- watch.fence.Watch(scheduler.GetFence());
+ watch.tick = scheduler.CurrentTick();
}
void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) {
@@ -121,7 +120,8 @@ void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) {
// Substract from the preferred heap size some bytes to avoid getting out of memory.
const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size;
- const VkDeviceSize allocable_size = heap_size - 9 * 1024 * 1024;
+ // As per DXVK's example, using `heap_size / 2`
+ const VkDeviceSize allocable_size = heap_size / 2;
buffer = device.GetLogical().CreateBuffer({
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -157,7 +157,7 @@ void VKStreamBuffer::WaitPendingOperations(u64 requested_upper_bound) {
while (requested_upper_bound < wait_bound && wait_cursor < *invalidation_mark) {
auto& watch = previous_watches[wait_cursor];
wait_bound = watch.upper_bound;
- watch.fence.Wait();
+ scheduler.Wait(watch.tick);
++wait_cursor;
}
}
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h
index 689f0d276..5e15ad78f 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.h
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h
@@ -14,7 +14,6 @@
namespace Vulkan {
class VKDevice;
-class VKFence;
class VKFenceWatch;
class VKScheduler;
@@ -44,8 +43,8 @@ public:
}
private:
- struct Watch final {
- VKFenceWatch fence;
+ struct Watch {
+ u64 tick{};
u64 upper_bound{};
};
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 6bfd2abae..9636a7c65 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -12,7 +12,7 @@
#include "core/core.h"
#include "core/frontend/framebuffer_layout.h"
#include "video_core/renderer_vulkan/vk_device.h"
-#include "video_core/renderer_vulkan/vk_resource_manager.h"
+#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/renderer_vulkan/wrapper.h"
@@ -56,8 +56,8 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi
} // Anonymous namespace
-VKSwapchain::VKSwapchain(VkSurfaceKHR surface, const VKDevice& device)
- : surface{surface}, device{device} {}
+VKSwapchain::VKSwapchain(VkSurfaceKHR surface_, const VKDevice& device_, VKScheduler& scheduler_)
+ : surface{surface_}, device{device_}, scheduler{scheduler_} {}
VKSwapchain::~VKSwapchain() = default;
@@ -75,21 +75,18 @@ void VKSwapchain::Create(u32 width, u32 height, bool srgb) {
CreateSemaphores();
CreateImageViews();
- fences.resize(image_count, nullptr);
+ resource_ticks.clear();
+ resource_ticks.resize(image_count);
}
void VKSwapchain::AcquireNextImage() {
device.GetLogical().AcquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(),
*present_semaphores[frame_index], {}, &image_index);
- if (auto& fence = fences[image_index]; fence) {
- fence->Wait();
- fence->Release();
- fence = nullptr;
- }
+ scheduler.Wait(resource_ticks[image_index]);
}
-bool VKSwapchain::Present(VkSemaphore render_semaphore, VKFence& fence) {
+bool VKSwapchain::Present(VkSemaphore render_semaphore) {
const VkSemaphore present_semaphore{*present_semaphores[frame_index]};
const std::array<VkSemaphore, 2> semaphores{present_semaphore, render_semaphore};
const auto present_queue{device.GetPresentQueue()};
@@ -123,8 +120,7 @@ bool VKSwapchain::Present(VkSemaphore render_semaphore, VKFence& fence) {
break;
}
- ASSERT(fences[image_index] == nullptr);
- fences[image_index] = &fence;
+ resource_ticks[image_index] = scheduler.CurrentTick();
frame_index = (frame_index + 1) % static_cast<u32>(image_count);
return recreated;
}
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index a35d61345..6b39befdf 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -16,11 +16,11 @@ struct FramebufferLayout;
namespace Vulkan {
class VKDevice;
-class VKFence;
+class VKScheduler;
class VKSwapchain {
public:
- explicit VKSwapchain(VkSurfaceKHR surface, const VKDevice& device);
+ explicit VKSwapchain(VkSurfaceKHR surface, const VKDevice& device, VKScheduler& scheduler);
~VKSwapchain();
/// Creates (or recreates) the swapchain with a given size.
@@ -31,7 +31,7 @@ public:
/// Presents the rendered image to the swapchain. Returns true when the swapchains had to be
/// recreated. Takes responsability for the ownership of fence.
- bool Present(VkSemaphore render_semaphore, VKFence& fence);
+ bool Present(VkSemaphore render_semaphore);
/// Returns true when the framebuffer layout has changed.
bool HasFramebufferChanged(const Layout::FramebufferLayout& framebuffer) const;
@@ -74,6 +74,7 @@ private:
const VkSurfaceKHR surface;
const VKDevice& device;
+ VKScheduler& scheduler;
vk::SwapchainKHR swapchain;
@@ -81,7 +82,7 @@ private:
std::vector<VkImage> images;
std::vector<vk::ImageView> image_views;
std::vector<vk::Framebuffer> framebuffers;
- std::vector<VKFence*> fences;
+ std::vector<u64> resource_ticks;
std::vector<vk::Semaphore> present_semaphores;
u32 image_index{};
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 2c6f54101..f2c8f2ae1 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -188,12 +188,10 @@ u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, Tegra::Texture::Swizzl
} // Anonymous namespace
-CachedSurface::CachedSurface(Core::System& system, const VKDevice& device,
- VKResourceManager& resource_manager, VKMemoryManager& memory_manager,
+CachedSurface::CachedSurface(const VKDevice& device, VKMemoryManager& memory_manager,
VKScheduler& scheduler, VKStagingBufferPool& staging_pool,
GPUVAddr gpu_addr, const SurfaceParams& params)
- : SurfaceBase<View>{gpu_addr, params, device.IsOptimalAstcSupported()}, system{system},
- device{device}, resource_manager{resource_manager},
+ : SurfaceBase<View>{gpu_addr, params, device.IsOptimalAstcSupported()}, device{device},
memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{staging_pool} {
if (params.IsBuffer()) {
buffer = CreateBuffer(device, params, host_memory_size);
@@ -490,19 +488,20 @@ VkImageView CachedSurfaceView::GetAttachment() {
return *render_target;
}
-VKTextureCache::VKTextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- const VKDevice& device, VKResourceManager& resource_manager,
- VKMemoryManager& memory_manager, VKScheduler& scheduler,
- VKStagingBufferPool& staging_pool)
- : TextureCache(system, rasterizer, device.IsOptimalAstcSupported()), device{device},
- resource_manager{resource_manager}, memory_manager{memory_manager}, scheduler{scheduler},
- staging_pool{staging_pool} {}
+VKTextureCache::VKTextureCache(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::Engines::Maxwell3D& maxwell3d,
+ Tegra::MemoryManager& gpu_memory, const VKDevice& device_,
+ VKMemoryManager& memory_manager_, VKScheduler& scheduler_,
+ VKStagingBufferPool& staging_pool_)
+ : TextureCache(rasterizer, maxwell3d, gpu_memory, device_.IsOptimalAstcSupported()),
+ device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{
+ staging_pool_} {}
VKTextureCache::~VKTextureCache() = default;
Surface VKTextureCache::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) {
- return std::make_shared<CachedSurface>(system, device, resource_manager, memory_manager,
- scheduler, staging_pool, gpu_addr, params);
+ return std::make_shared<CachedSurface>(device, memory_manager, scheduler, staging_pool,
+ gpu_addr, params);
}
void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface,
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 807e26c8a..39202feba 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -15,10 +15,6 @@
#include "video_core/texture_cache/surface_base.h"
#include "video_core/texture_cache/texture_cache.h"
-namespace Core {
-class System;
-}
-
namespace VideoCore {
class RasterizerInterface;
}
@@ -27,7 +23,6 @@ namespace Vulkan {
class RasterizerVulkan;
class VKDevice;
-class VKResourceManager;
class VKScheduler;
class VKStagingBufferPool;
@@ -45,8 +40,7 @@ class CachedSurface final : public VideoCommon::SurfaceBase<View> {
friend CachedSurfaceView;
public:
- explicit CachedSurface(Core::System& system, const VKDevice& device,
- VKResourceManager& resource_manager, VKMemoryManager& memory_manager,
+ explicit CachedSurface(const VKDevice& device, VKMemoryManager& memory_manager,
VKScheduler& scheduler, VKStagingBufferPool& staging_pool,
GPUVAddr gpu_addr, const SurfaceParams& params);
~CachedSurface();
@@ -101,9 +95,7 @@ private:
VkImageSubresourceRange GetImageSubresourceRange() const;
- Core::System& system;
const VKDevice& device;
- VKResourceManager& resource_manager;
VKMemoryManager& memory_manager;
VKScheduler& scheduler;
VKStagingBufferPool& staging_pool;
@@ -201,10 +193,10 @@ private:
class VKTextureCache final : public TextureCacheBase {
public:
- explicit VKTextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- const VKDevice& device, VKResourceManager& resource_manager,
- VKMemoryManager& memory_manager, VKScheduler& scheduler,
- VKStagingBufferPool& staging_pool);
+ explicit VKTextureCache(VideoCore::RasterizerInterface& rasterizer,
+ Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory,
+ const VKDevice& device, VKMemoryManager& memory_manager,
+ VKScheduler& scheduler, VKStagingBufferPool& staging_pool);
~VKTextureCache();
private:
@@ -219,7 +211,6 @@ private:
void BufferCopy(Surface& src_surface, Surface& dst_surface) override;
const VKDevice& device;
- VKResourceManager& resource_manager;
VKMemoryManager& memory_manager;
VKScheduler& scheduler;
VKStagingBufferPool& staging_pool;
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index 56055af1b..c034558a3 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -6,6 +6,7 @@
#include <exception>
#include <memory>
#include <optional>
+#include <string_view>
#include <utility>
#include <vector>
@@ -18,21 +19,42 @@ namespace Vulkan::vk {
namespace {
+template <typename Func>
+void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld,
+ Func&& func) {
+ // Calling GetProperties calls Vulkan more than needed. But they are supposed to be cheap
+ // functions.
+ std::stable_sort(devices.begin(), devices.end(),
+ [&dld, &func](VkPhysicalDevice lhs, VkPhysicalDevice rhs) {
+ return func(vk::PhysicalDevice(lhs, dld).GetProperties(),
+ vk::PhysicalDevice(rhs, dld).GetProperties());
+ });
+}
+
+void SortPhysicalDevicesPerVendor(std::vector<VkPhysicalDevice>& devices,
+ const InstanceDispatch& dld,
+ std::initializer_list<u32> vendor_ids) {
+ for (auto it = vendor_ids.end(); it != vendor_ids.begin();) {
+ --it;
+ SortPhysicalDevices(devices, dld, [id = *it](const auto& lhs, const auto& rhs) {
+ return lhs.vendorID == id && rhs.vendorID != id;
+ });
+ }
+}
+
void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) {
- std::stable_sort(devices.begin(), devices.end(), [&](auto lhs, auto rhs) {
- // This will call Vulkan more than needed, but these calls are cheap.
- const auto lhs_properties = vk::PhysicalDevice(lhs, dld).GetProperties();
- const auto rhs_properties = vk::PhysicalDevice(rhs, dld).GetProperties();
-
- // Prefer discrete GPUs, Nvidia over AMD, AMD over Intel, Intel over the rest.
- const bool preferred =
- (lhs_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
- rhs_properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) ||
- (lhs_properties.vendorID == 0x10DE && rhs_properties.vendorID != 0x10DE) ||
- (lhs_properties.vendorID == 0x1002 && rhs_properties.vendorID != 0x1002) ||
- (lhs_properties.vendorID == 0x8086 && rhs_properties.vendorID != 0x8086);
- return !preferred;
+ // Sort by name, this will set a base and make GPUs with higher numbers appear first
+ // (e.g. GTX 1650 will intentionally be listed before a GTX 1080).
+ SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) {
+ return std::string_view{lhs.deviceName} > std::string_view{rhs.deviceName};
});
+ // Prefer discrete over non-discrete
+ SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) {
+ return lhs.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
+ rhs.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
+ });
+ // Prefer Nvidia over AMD, AMD over Intel, Intel over the rest.
+ SortPhysicalDevicesPerVendor(devices, dld, {0x10DE, 0x1002, 0x8086});
}
template <typename T>
@@ -149,6 +171,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkGetFenceStatus);
X(vkGetImageMemoryRequirements);
X(vkGetQueryPoolResults);
+ X(vkGetSemaphoreCounterValueKHR);
X(vkMapMemory);
X(vkQueueSubmit);
X(vkResetFences);
@@ -157,6 +180,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkUpdateDescriptorSetWithTemplateKHR);
X(vkUpdateDescriptorSets);
X(vkWaitForFences);
+ X(vkWaitSemaphoresKHR);
#undef X
}
@@ -263,6 +287,22 @@ const char* ToString(VkResult result) noexcept {
return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT";
case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
+ case VkResult::VK_ERROR_UNKNOWN:
+ return "VK_ERROR_UNKNOWN";
+ case VkResult::VK_ERROR_INCOMPATIBLE_VERSION_KHR:
+ return "VK_ERROR_INCOMPATIBLE_VERSION_KHR";
+ case VkResult::VK_THREAD_IDLE_KHR:
+ return "VK_THREAD_IDLE_KHR";
+ case VkResult::VK_THREAD_DONE_KHR:
+ return "VK_THREAD_DONE_KHR";
+ case VkResult::VK_OPERATION_DEFERRED_KHR:
+ return "VK_OPERATION_DEFERRED_KHR";
+ case VkResult::VK_OPERATION_NOT_DEFERRED_KHR:
+ return "VK_OPERATION_NOT_DEFERRED_KHR";
+ case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT:
+ return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
+ case VkResult::VK_RESULT_MAX_ENUM:
+ return "VK_RESULT_MAX_ENUM";
}
return "Unknown";
}
@@ -558,7 +598,10 @@ Semaphore Device::CreateSemaphore() const {
.pNext = nullptr,
.flags = 0,
};
+ return CreateSemaphore(ci);
+}
+Semaphore Device::CreateSemaphore(const VkSemaphoreCreateInfo& ci) const {
VkSemaphore object;
Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object));
return Semaphore(object, handle, *dld);
@@ -644,7 +687,7 @@ ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) cons
return ShaderModule(object, handle, *dld);
}
-Event Device::CreateNewEvent() const {
+Event Device::CreateEvent() const {
static constexpr VkEventCreateInfo ci{
.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
.pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
index 748a94d2f..f64919623 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -267,6 +267,7 @@ struct DeviceDispatch : public InstanceDispatch {
PFN_vkGetFenceStatus vkGetFenceStatus;
PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
PFN_vkGetQueryPoolResults vkGetQueryPoolResults;
+ PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR;
PFN_vkMapMemory vkMapMemory;
PFN_vkQueueSubmit vkQueueSubmit;
PFN_vkResetFences vkResetFences;
@@ -275,6 +276,7 @@ struct DeviceDispatch : public InstanceDispatch {
PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR;
PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
PFN_vkWaitForFences vkWaitForFences;
+ PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR;
};
/// Loads instance agnostic function pointers.
@@ -550,7 +552,6 @@ using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>;
using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>;
using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>;
using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>;
-using Semaphore = Handle<VkSemaphore, VkDevice, DeviceDispatch>;
using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>;
using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>;
@@ -582,7 +583,8 @@ public:
/// Construct a queue handle.
constexpr Queue(VkQueue queue, const DeviceDispatch& dld) noexcept : queue{queue}, dld{&dld} {}
- VkResult Submit(Span<VkSubmitInfo> submit_infos, VkFence fence) const noexcept {
+ VkResult Submit(Span<VkSubmitInfo> submit_infos,
+ VkFence fence = VK_NULL_HANDLE) const noexcept {
return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence);
}
@@ -674,6 +676,44 @@ public:
}
};
+class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> {
+ using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle;
+
+public:
+ [[nodiscard]] u64 GetCounter() const {
+ u64 value;
+ Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value));
+ return value;
+ }
+
+ /**
+ * Waits for a timeline semaphore on the host.
+ *
+ * @param value Value to wait
+ * @param timeout Time in nanoseconds to timeout
+ * @return True on successful wait, false on timeout
+ */
+ bool Wait(u64 value, u64 timeout = std::numeric_limits<u64>::max()) const {
+ const VkSemaphoreWaitInfoKHR wait_info{
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR,
+ .pNext = nullptr,
+ .flags = 0,
+ .semaphoreCount = 1,
+ .pSemaphores = &handle,
+ .pValues = &value,
+ };
+ const VkResult result = dld->vkWaitSemaphoresKHR(owner, &wait_info, timeout);
+ switch (result) {
+ case VK_SUCCESS:
+ return true;
+ case VK_TIMEOUT:
+ return false;
+ default:
+ throw Exception(result);
+ }
+ }
+};
+
class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {
using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle;
@@ -694,6 +734,8 @@ public:
Semaphore CreateSemaphore() const;
+ Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const;
+
Fence CreateFence(const VkFenceCreateInfo& ci) const;
DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const;
@@ -721,7 +763,7 @@ public:
ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const;
- Event CreateNewEvent() const;
+ Event CreateEvent() const;
SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const;
diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h
index cca13bcde..8e5a22ab3 100644
--- a/src/video_core/shader/ast.h
+++ b/src/video_core/shader/ast.h
@@ -199,55 +199,48 @@ public:
}
std::optional<u32> GetGotoLabel() const {
- auto inner = std::get_if<ASTGoto>(&data);
- if (inner) {
+ if (const auto* inner = std::get_if<ASTGoto>(&data)) {
return {inner->label};
}
- return {};
+ return std::nullopt;
}
Expr GetGotoCondition() const {
- auto inner = std::get_if<ASTGoto>(&data);
- if (inner) {
+ if (const auto* inner = std::get_if<ASTGoto>(&data)) {
return inner->condition;
}
return nullptr;
}
void MarkLabelUnused() {
- auto inner = std::get_if<ASTLabel>(&data);
- if (inner) {
+ if (auto* inner = std::get_if<ASTLabel>(&data)) {
inner->unused = true;
}
}
bool IsLabelUnused() const {
- auto inner = std::get_if<ASTLabel>(&data);
- if (inner) {
+ if (const auto* inner = std::get_if<ASTLabel>(&data)) {
return inner->unused;
}
return true;
}
std::optional<u32> GetLabelIndex() const {
- auto inner = std::get_if<ASTLabel>(&data);
- if (inner) {
+ if (const auto* inner = std::get_if<ASTLabel>(&data)) {
return {inner->index};
}
- return {};
+ return std::nullopt;
}
Expr GetIfCondition() const {
- auto inner = std::get_if<ASTIfThen>(&data);
- if (inner) {
+ if (const auto* inner = std::get_if<ASTIfThen>(&data)) {
return inner->condition;
}
return nullptr;
}
void SetGotoCondition(Expr new_condition) {
- auto inner = std::get_if<ASTGoto>(&data);
- if (inner) {
+ if (auto* inner = std::get_if<ASTGoto>(&data)) {
inner->condition = std::move(new_condition);
}
}
diff --git a/src/video_core/shader/async_shaders.cpp b/src/video_core/shader/async_shaders.cpp
index f815584f7..aabd62c5c 100644
--- a/src/video_core/shader/async_shaders.cpp
+++ b/src/video_core/shader/async_shaders.cpp
@@ -73,11 +73,11 @@ void AsyncShaders::KillWorkers() {
worker_threads.clear();
}
-bool AsyncShaders::HasWorkQueued() {
+bool AsyncShaders::HasWorkQueued() const {
return !pending_queue.empty();
}
-bool AsyncShaders::HasCompletedWork() {
+bool AsyncShaders::HasCompletedWork() const {
std::shared_lock lock{completed_mutex};
return !finished_work.empty();
}
@@ -102,7 +102,7 @@ bool AsyncShaders::IsShaderAsync(const Tegra::GPU& gpu) const {
}
std::vector<AsyncShaders::Result> AsyncShaders::GetCompletedWork() {
- std::vector<AsyncShaders::Result> results;
+ std::vector<Result> results;
{
std::unique_lock lock{completed_mutex};
results.assign(std::make_move_iterator(finished_work.begin()),
diff --git a/src/video_core/shader/async_shaders.h b/src/video_core/shader/async_shaders.h
index d5ae814d5..7a99e1dc5 100644
--- a/src/video_core/shader/async_shaders.h
+++ b/src/video_core/shader/async_shaders.h
@@ -5,11 +5,21 @@
#pragma once
#include <condition_variable>
-#include <deque>
#include <memory>
#include <shared_mutex>
#include <thread>
-#include "common/bit_field.h"
+
+// This header includes both Vulkan and OpenGL headers, this has to be fixed
+// Unfortunately, including OpenGL will include Windows.h that defines macros that can cause issues.
+// Forcefully include glad early and undefine macros
+#include <glad/glad.h>
+#ifdef CreateEvent
+#undef CreateEvent
+#endif
+#ifdef CreateSemaphore
+#undef CreateSemaphore
+#endif
+
#include "common/common_types.h"
#include "video_core/renderer_opengl/gl_device.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
@@ -17,7 +27,6 @@
#include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
-#include "video_core/renderer_vulkan/vk_update_descriptor.h"
namespace Core::Frontend {
class EmuWindow;
@@ -70,20 +79,20 @@ public:
void KillWorkers();
/// Check to see if any shaders have actually been compiled
- bool HasCompletedWork();
+ [[nodiscard]] bool HasCompletedWork() const;
/// Deduce if a shader can be build on another thread of MUST be built in sync. We cannot build
/// every shader async as some shaders are only built and executed once. We try to "guess" which
/// shader would be used only once
- bool IsShaderAsync(const Tegra::GPU& gpu) const;
+ [[nodiscard]] bool IsShaderAsync(const Tegra::GPU& gpu) const;
/// Pulls completed compiled shaders
- std::vector<Result> GetCompletedWork();
+ [[nodiscard]] std::vector<Result> GetCompletedWork();
void QueueOpenGLShader(const OpenGL::Device& device, Tegra::Engines::ShaderType shader_type,
u64 uid, std::vector<u64> code, std::vector<u64> code_b, u32 main_offset,
- VideoCommon::Shader::CompilerSettings compiler_settings,
- const VideoCommon::Shader::Registry& registry, VAddr cpu_addr);
+ CompilerSettings compiler_settings, const Registry& registry,
+ VAddr cpu_addr);
void QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, const Vulkan::VKDevice& device,
Vulkan::VKScheduler& scheduler,
@@ -97,7 +106,7 @@ private:
void ShaderCompilerThread(Core::Frontend::GraphicsContext* context);
/// Check our worker queue to see if we have any work queued already
- bool HasWorkQueued();
+ [[nodiscard]] bool HasWorkQueued() const;
struct WorkerParams {
Backend backend;
@@ -108,8 +117,8 @@ private:
std::vector<u64> code;
std::vector<u64> code_b;
u32 main_offset;
- VideoCommon::Shader::CompilerSettings compiler_settings;
- std::optional<VideoCommon::Shader::Registry> registry;
+ CompilerSettings compiler_settings;
+ std::optional<Registry> registry;
VAddr cpu_address;
// For Vulkan
@@ -125,13 +134,13 @@ private:
};
std::condition_variable cv;
- std::mutex queue_mutex;
- std::shared_mutex completed_mutex;
+ mutable std::mutex queue_mutex;
+ mutable std::shared_mutex completed_mutex;
std::atomic<bool> is_thread_exiting{};
std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list;
std::vector<std::thread> worker_threads;
std::queue<WorkerParams> pending_queue;
- std::vector<AsyncShaders::Result> finished_work;
+ std::vector<Result> finished_work;
Core::Frontend::EmuWindow& emu_window;
};
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index 336397cdb..4c8971615 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -547,13 +547,13 @@ bool TryQuery(CFGRebuildState& state) {
gather_labels(q2.ssy_stack, state.ssy_labels, block);
gather_labels(q2.pbk_stack, state.pbk_labels, block);
if (std::holds_alternative<SingleBranch>(*block.branch)) {
- const auto branch = std::get_if<SingleBranch>(block.branch.get());
+ auto* branch = std::get_if<SingleBranch>(block.branch.get());
if (!branch->condition.IsUnconditional()) {
q2.address = block.end + 1;
state.queries.push_back(q2);
}
- Query conditional_query{q2};
+ auto& conditional_query = state.queries.emplace_back(q2);
if (branch->is_sync) {
if (branch->address == unassigned_branch) {
branch->address = conditional_query.ssy_stack.top();
@@ -567,21 +567,21 @@ bool TryQuery(CFGRebuildState& state) {
conditional_query.pbk_stack.pop();
}
conditional_query.address = branch->address;
- state.queries.push_back(std::move(conditional_query));
return true;
}
- const auto multi_branch = std::get_if<MultiBranch>(block.branch.get());
+
+ const auto* multi_branch = std::get_if<MultiBranch>(block.branch.get());
for (const auto& branch_case : multi_branch->branches) {
- Query conditional_query{q2};
+ auto& conditional_query = state.queries.emplace_back(q2);
conditional_query.address = branch_case.address;
- state.queries.push_back(std::move(conditional_query));
}
+
return true;
}
void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) {
- const auto get_expr = ([&](const Condition& cond) -> Expr {
- Expr result{};
+ const auto get_expr = [](const Condition& cond) -> Expr {
+ Expr result;
if (cond.cc != ConditionCode::T) {
result = MakeExpr<ExprCondCode>(cond.cc);
}
@@ -594,10 +594,10 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) {
}
Expr extra = MakeExpr<ExprPredicate>(pred);
if (negate) {
- extra = MakeExpr<ExprNot>(extra);
+ extra = MakeExpr<ExprNot>(std::move(extra));
}
if (result) {
- return MakeExpr<ExprAnd>(extra, result);
+ return MakeExpr<ExprAnd>(std::move(extra), std::move(result));
}
return extra;
}
@@ -605,9 +605,10 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) {
return result;
}
return MakeExpr<ExprBoolean>(true);
- });
+ };
+
if (std::holds_alternative<SingleBranch>(*branch_info)) {
- const auto branch = std::get_if<SingleBranch>(branch_info.get());
+ const auto* branch = std::get_if<SingleBranch>(branch_info.get());
if (branch->address < 0) {
if (branch->kill) {
mm.InsertReturn(get_expr(branch->condition), true);
@@ -619,7 +620,7 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) {
mm.InsertGoto(get_expr(branch->condition), branch->address);
return;
}
- const auto multi_branch = std::get_if<MultiBranch>(branch_info.get());
+ const auto* multi_branch = std::get_if<MultiBranch>(branch_info.get());
for (const auto& branch_case : multi_branch->branches) {
mm.InsertGoto(MakeExpr<ExprGprEqual>(multi_branch->gpr, branch_case.cmp_value),
branch_case.address);
diff --git a/src/video_core/shader/decode/arithmetic_half.cpp b/src/video_core/shader/decode/arithmetic_half.cpp
index a276aee44..88103fede 100644
--- a/src/video_core/shader/decode/arithmetic_half.cpp
+++ b/src/video_core/shader/decode/arithmetic_half.cpp
@@ -53,6 +53,9 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) {
absolute_a = ((instr.value >> 44) & 1) != 0;
absolute_b = ((instr.value >> 54) & 1) != 0;
break;
+ default:
+ UNREACHABLE();
+ break;
}
Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.alu_half.type_a);
diff --git a/src/video_core/shader/decode/arithmetic_integer_immediate.cpp b/src/video_core/shader/decode/arithmetic_integer_immediate.cpp
index 73880db0e..2a30aab2b 100644
--- a/src/video_core/shader/decode/arithmetic_integer_immediate.cpp
+++ b/src/video_core/shader/decode/arithmetic_integer_immediate.cpp
@@ -28,23 +28,26 @@ u32 ShaderIR::DecodeArithmeticIntegerImmediate(NodeBlock& bb, u32 pc) {
case OpCode::Id::IADD32I: {
UNIMPLEMENTED_IF_MSG(instr.iadd32i.saturate, "IADD32I saturation is not implemented");
- op_a = GetOperandAbsNegInteger(op_a, false, instr.iadd32i.negate_a, true);
+ op_a = GetOperandAbsNegInteger(std::move(op_a), false, instr.iadd32i.negate_a != 0, true);
- const Node value = Operation(OperationCode::IAdd, PRECISE, op_a, op_b);
+ Node value = Operation(OperationCode::IAdd, PRECISE, std::move(op_a), std::move(op_b));
- SetInternalFlagsFromInteger(bb, value, instr.op_32.generates_cc);
- SetRegister(bb, instr.gpr0, value);
+ SetInternalFlagsFromInteger(bb, value, instr.op_32.generates_cc != 0);
+ SetRegister(bb, instr.gpr0, std::move(value));
break;
}
case OpCode::Id::LOP32I: {
- if (instr.alu.lop32i.invert_a)
- op_a = Operation(OperationCode::IBitwiseNot, NO_PRECISE, op_a);
+ if (instr.alu.lop32i.invert_a) {
+ op_a = Operation(OperationCode::IBitwiseNot, NO_PRECISE, std::move(op_a));
+ }
- if (instr.alu.lop32i.invert_b)
- op_b = Operation(OperationCode::IBitwiseNot, NO_PRECISE, op_b);
+ if (instr.alu.lop32i.invert_b) {
+ op_b = Operation(OperationCode::IBitwiseNot, NO_PRECISE, std::move(op_b));
+ }
- WriteLogicOperation(bb, instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
- PredicateResultMode::None, Pred::UnusedIndex, instr.op_32.generates_cc);
+ WriteLogicOperation(bb, instr.gpr0, instr.alu.lop32i.operation, std::move(op_a),
+ std::move(op_b), PredicateResultMode::None, Pred::UnusedIndex,
+ instr.op_32.generates_cc != 0);
break;
}
default:
@@ -58,14 +61,14 @@ u32 ShaderIR::DecodeArithmeticIntegerImmediate(NodeBlock& bb, u32 pc) {
void ShaderIR::WriteLogicOperation(NodeBlock& bb, Register dest, LogicOperation logic_op, Node op_a,
Node op_b, PredicateResultMode predicate_mode, Pred predicate,
bool sets_cc) {
- const Node result = [&]() {
+ Node result = [&] {
switch (logic_op) {
case LogicOperation::And:
- return Operation(OperationCode::IBitwiseAnd, PRECISE, op_a, op_b);
+ return Operation(OperationCode::IBitwiseAnd, PRECISE, std::move(op_a), std::move(op_b));
case LogicOperation::Or:
- return Operation(OperationCode::IBitwiseOr, PRECISE, op_a, op_b);
+ return Operation(OperationCode::IBitwiseOr, PRECISE, std::move(op_a), std::move(op_b));
case LogicOperation::Xor:
- return Operation(OperationCode::IBitwiseXor, PRECISE, op_a, op_b);
+ return Operation(OperationCode::IBitwiseXor, PRECISE, std::move(op_a), std::move(op_b));
case LogicOperation::PassB:
return op_b;
default:
@@ -84,8 +87,8 @@ void ShaderIR::WriteLogicOperation(NodeBlock& bb, Register dest, LogicOperation
return;
case PredicateResultMode::NotZero: {
// Set the predicate to true if the result is not zero.
- const Node compare = Operation(OperationCode::LogicalINotEqual, result, Immediate(0));
- SetPredicate(bb, static_cast<u64>(predicate), compare);
+ Node compare = Operation(OperationCode::LogicalINotEqual, std::move(result), Immediate(0));
+ SetPredicate(bb, static_cast<u64>(predicate), std::move(compare));
break;
}
default:
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp
index e75ca4fdb..618d309d2 100644
--- a/src/video_core/shader/decode/image.cpp
+++ b/src/video_core/shader/decode/image.cpp
@@ -119,6 +119,8 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor,
return descriptor.r_type;
}
break;
+ default:
+ break;
}
UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
return ComponentType::FLOAT;
@@ -220,9 +222,10 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) {
return (component == 0 || component == 1) ? 8 : 0;
case TextureFormat::G4R4:
return (component == 0 || component == 1) ? 4 : 0;
+ default:
+ UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
+ return 0;
}
- UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
- return 0;
}
std::size_t GetImageComponentMask(TextureFormat format) {
@@ -257,9 +260,10 @@ std::size_t GetImageComponentMask(TextureFormat format) {
case TextureFormat::R8:
case TextureFormat::R1:
return std::size_t{R};
+ default:
+ UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
+ return std::size_t{R | G | B | A};
}
- UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
- return std::size_t{R | G | B | A};
}
std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) {
@@ -463,7 +467,10 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
return OperationCode::AtomicImageXor;
case Tegra::Shader::ImageAtomicOperation::Exch:
return OperationCode::AtomicImageExchange;
+ default:
+ break;
}
+ break;
default:
break;
}
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index e4739394d..e2bba88dd 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -386,7 +386,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
break;
}
case OpCode::Id::RED: {
- UNIMPLEMENTED_IF_MSG(instr.red.type != GlobalAtomicType::U32);
+ UNIMPLEMENTED_IF_MSG(instr.red.type != GlobalAtomicType::U32, "type={}",
+ static_cast<int>(instr.red.type.Value()));
const auto [real_address, base_address, descriptor] =
TrackGlobalMemory(bb, instr, true, true);
if (!real_address || !base_address) {
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp
index 29ebf65ba..4e932a4b6 100644
--- a/src/video_core/shader/decode/texture.cpp
+++ b/src/video_core/shader/decode/texture.cpp
@@ -292,33 +292,36 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
break;
}
- std::vector<Node> coords;
-
- // TODO: Add coordinates for different samplers once other texture types are implemented.
- switch (texture_type) {
- case TextureType::Texture1D:
- coords.push_back(GetRegister(instr.gpr8));
- break;
- case TextureType::Texture2D:
- coords.push_back(GetRegister(instr.gpr8.Value() + 0));
- coords.push_back(GetRegister(instr.gpr8.Value() + 1));
- break;
- default:
- UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast<int>(texture_type));
+ const u64 base_index = is_array ? 1 : 0;
+ const u64 num_components = [texture_type] {
+ switch (texture_type) {
+ case TextureType::Texture1D:
+ return 1;
+ case TextureType::Texture2D:
+ return 2;
+ case TextureType::TextureCube:
+ return 3;
+ default:
+ UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast<int>(texture_type));
+ return 2;
+ }
+ }();
+ // TODO: What's the array component used for?
- // Fallback to interpreting as a 2D texture for now
- coords.push_back(GetRegister(instr.gpr8.Value() + 0));
- coords.push_back(GetRegister(instr.gpr8.Value() + 1));
+ std::vector<Node> coords;
+ coords.reserve(num_components);
+ for (u64 component = 0; component < num_components; ++component) {
+ coords.push_back(GetRegister(instr.gpr8.Value() + base_index + component));
}
+
u32 indexer = 0;
for (u32 element = 0; element < 2; ++element) {
if (!instr.tmml.IsComponentEnabled(element)) {
continue;
}
- auto params = coords;
MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element, index_var};
- const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params));
- SetTemporary(bb, indexer++, value);
+ Node value = Operation(OperationCode::TextureQueryLod, meta, coords);
+ SetTemporary(bb, indexer++, std::move(value));
}
for (u32 i = 0; i < indexer; ++i) {
SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
@@ -763,7 +766,7 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
const auto texture_type{instr.tld.texture_type};
- const bool is_array{instr.tld.is_array};
+ const bool is_array{instr.tld.is_array != 0};
const bool lod_enabled{instr.tld.GetTextureProcessMode() == TextureProcessMode::LL};
const std::size_t coord_count{GetCoordCount(texture_type)};
diff --git a/src/video_core/shader/memory_util.cpp b/src/video_core/shader/memory_util.cpp
index 5071c83ca..e18ccba8e 100644
--- a/src/video_core/shader/memory_util.cpp
+++ b/src/video_core/shader/memory_util.cpp
@@ -16,11 +16,10 @@
namespace VideoCommon::Shader {
-GPUVAddr GetShaderAddress(Core::System& system,
+GPUVAddr GetShaderAddress(Tegra::Engines::Maxwell3D& maxwell3d,
Tegra::Engines::Maxwell3D::Regs::ShaderProgram program) {
- const auto& gpu{system.GPU().Maxwell3D()};
- const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]};
- return gpu.regs.code_address.CodeAddress() + shader_config.offset;
+ const auto& shader_config{maxwell3d.regs.shader_config[static_cast<std::size_t>(program)]};
+ return maxwell3d.regs.code_address.CodeAddress() + shader_config.offset;
}
bool IsSchedInstruction(std::size_t offset, std::size_t main_offset) {
diff --git a/src/video_core/shader/memory_util.h b/src/video_core/shader/memory_util.h
index be90d24fd..4624d38e6 100644
--- a/src/video_core/shader/memory_util.h
+++ b/src/video_core/shader/memory_util.h
@@ -11,10 +11,6 @@
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/shader_type.h"
-namespace Core {
-class System;
-}
-
namespace Tegra {
class MemoryManager;
}
@@ -27,7 +23,7 @@ constexpr u32 STAGE_MAIN_OFFSET = 10;
constexpr u32 KERNEL_MAIN_OFFSET = 0;
/// Gets the address for the specified shader stage program
-GPUVAddr GetShaderAddress(Core::System& system,
+GPUVAddr GetShaderAddress(Tegra::Engines::Maxwell3D& maxwell3d,
Tegra::Engines::Maxwell3D::Regs::ShaderProgram program);
/// Gets if the current instruction offset is a scheduler instruction
diff --git a/src/video_core/shader/registry.cpp b/src/video_core/shader/registry.cpp
index cdf274e54..148d91fcb 100644
--- a/src/video_core/shader/registry.cpp
+++ b/src/video_core/shader/registry.cpp
@@ -24,44 +24,45 @@ GraphicsInfo MakeGraphicsInfo(ShaderType shader_stage, ConstBufferEngineInterfac
if (shader_stage == ShaderType::Compute) {
return {};
}
- auto& graphics = static_cast<Tegra::Engines::Maxwell3D&>(engine);
-
- GraphicsInfo info;
- info.tfb_layouts = graphics.regs.tfb_layouts;
- info.tfb_varying_locs = graphics.regs.tfb_varying_locs;
- info.primitive_topology = graphics.regs.draw.topology;
- info.tessellation_primitive = graphics.regs.tess_mode.prim;
- info.tessellation_spacing = graphics.regs.tess_mode.spacing;
- info.tfb_enabled = graphics.regs.tfb_enabled;
- info.tessellation_clockwise = graphics.regs.tess_mode.cw;
- return info;
+
+ auto& graphics = dynamic_cast<Tegra::Engines::Maxwell3D&>(engine);
+
+ return {
+ .tfb_layouts = graphics.regs.tfb_layouts,
+ .tfb_varying_locs = graphics.regs.tfb_varying_locs,
+ .primitive_topology = graphics.regs.draw.topology,
+ .tessellation_primitive = graphics.regs.tess_mode.prim,
+ .tessellation_spacing = graphics.regs.tess_mode.spacing,
+ .tfb_enabled = graphics.regs.tfb_enabled != 0,
+ .tessellation_clockwise = graphics.regs.tess_mode.cw.Value() != 0,
+ };
}
ComputeInfo MakeComputeInfo(ShaderType shader_stage, ConstBufferEngineInterface& engine) {
if (shader_stage != ShaderType::Compute) {
return {};
}
- auto& compute = static_cast<Tegra::Engines::KeplerCompute&>(engine);
+
+ auto& compute = dynamic_cast<Tegra::Engines::KeplerCompute&>(engine);
const auto& launch = compute.launch_description;
- ComputeInfo info;
- info.workgroup_size = {launch.block_dim_x, launch.block_dim_y, launch.block_dim_z};
- info.local_memory_size_in_words = launch.local_pos_alloc;
- info.shared_memory_size_in_words = launch.shared_alloc;
- return info;
+ return {
+ .workgroup_size = {launch.block_dim_x, launch.block_dim_y, launch.block_dim_z},
+ .shared_memory_size_in_words = launch.shared_alloc,
+ .local_memory_size_in_words = launch.local_pos_alloc,
+ };
}
} // Anonymous namespace
-Registry::Registry(Tegra::Engines::ShaderType shader_stage, const SerializedRegistryInfo& info)
+Registry::Registry(ShaderType shader_stage, const SerializedRegistryInfo& info)
: stage{shader_stage}, stored_guest_driver_profile{info.guest_driver_profile},
bound_buffer{info.bound_buffer}, graphics_info{info.graphics}, compute_info{info.compute} {}
-Registry::Registry(Tegra::Engines::ShaderType shader_stage,
- Tegra::Engines::ConstBufferEngineInterface& engine)
- : stage{shader_stage}, engine{&engine}, bound_buffer{engine.GetBoundBuffer()},
- graphics_info{MakeGraphicsInfo(shader_stage, engine)}, compute_info{MakeComputeInfo(
- shader_stage, engine)} {}
+Registry::Registry(ShaderType shader_stage, ConstBufferEngineInterface& engine_)
+ : stage{shader_stage}, engine{&engine_}, bound_buffer{engine_.GetBoundBuffer()},
+ graphics_info{MakeGraphicsInfo(shader_stage, engine_)}, compute_info{MakeComputeInfo(
+ shader_stage, engine_)} {}
Registry::~Registry() = default;
@@ -113,8 +114,7 @@ std::optional<Tegra::Engines::SamplerDescriptor> Registry::ObtainSeparateSampler
return value;
}
-std::optional<Tegra::Engines::SamplerDescriptor> Registry::ObtainBindlessSampler(u32 buffer,
- u32 offset) {
+std::optional<SamplerDescriptor> Registry::ObtainBindlessSampler(u32 buffer, u32 offset) {
const std::pair key = {buffer, offset};
const auto iter = bindless_samplers.find(key);
if (iter != bindless_samplers.end()) {
diff --git a/src/video_core/shader/registry.h b/src/video_core/shader/registry.h
index 231206765..4bebefdde 100644
--- a/src/video_core/shader/registry.h
+++ b/src/video_core/shader/registry.h
@@ -94,7 +94,7 @@ public:
explicit Registry(Tegra::Engines::ShaderType shader_stage, const SerializedRegistryInfo& info);
explicit Registry(Tegra::Engines::ShaderType shader_stage,
- Tegra::Engines::ConstBufferEngineInterface& engine);
+ Tegra::Engines::ConstBufferEngineInterface& engine_);
~Registry();
diff --git a/src/video_core/shader/track.cpp b/src/video_core/shader/track.cpp
index d5ed81442..6be3ea92b 100644
--- a/src/video_core/shader/track.cpp
+++ b/src/video_core/shader/track.cpp
@@ -205,12 +205,12 @@ std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code,
const auto result = TrackRegister(&std::get<GprNode>(*tracked), code, cursor - 1);
const auto& found = result.first;
if (!found) {
- return {};
+ return std::nullopt;
}
if (const auto immediate = std::get_if<ImmediateNode>(&*found)) {
return immediate->GetValue();
}
- return {};
+ return std::nullopt;
}
std::pair<Node, s64> ShaderIR::TrackRegister(const GprNode* tracked, const NodeBlock& code,
diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp
index dfcf36e0b..b44c09d71 100644
--- a/src/video_core/texture_cache/surface_base.cpp
+++ b/src/video_core/texture_cache/surface_base.cpp
@@ -115,20 +115,24 @@ std::optional<std::pair<u32, u32>> SurfaceBaseImpl::GetLayerMipmap(
if (gpu_addr == candidate_gpu_addr) {
return {{0, 0}};
}
+
if (candidate_gpu_addr < gpu_addr) {
- return {};
+ return std::nullopt;
}
+
const auto relative_address{static_cast<GPUVAddr>(candidate_gpu_addr - gpu_addr)};
const auto layer{static_cast<u32>(relative_address / layer_size)};
if (layer >= params.depth) {
- return {};
+ return std::nullopt;
}
+
const GPUVAddr mipmap_address = relative_address - layer_size * layer;
const auto mipmap_it =
Common::BinaryFind(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address);
if (mipmap_it == mipmap_offsets.end()) {
- return {};
+ return std::nullopt;
}
+
const auto level{static_cast<u32>(std::distance(mipmap_offsets.begin(), mipmap_it))};
return std::make_pair(layer, level);
}
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index e614a92df..e8515321b 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -163,13 +163,11 @@ SurfaceParams SurfaceParams::CreateForImage(const FormatLookupTable& lookup_tabl
return params;
}
-SurfaceParams SurfaceParams::CreateForDepthBuffer(Core::System& system) {
- const auto& regs = system.GPU().Maxwell3D().regs;
-
+SurfaceParams SurfaceParams::CreateForDepthBuffer(Tegra::Engines::Maxwell3D& maxwell3d) {
+ const auto& regs = maxwell3d.regs;
const auto block_depth = std::min(regs.zeta.memory_layout.block_depth.Value(), 5U);
const bool is_layered = regs.zeta_layers > 1 && block_depth == 0;
const auto pixel_format = PixelFormatFromDepthFormat(regs.zeta.format);
-
return {
.is_tiled = regs.zeta.memory_layout.type ==
Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear,
@@ -191,8 +189,9 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer(Core::System& system) {
};
}
-SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::size_t index) {
- const auto& config{system.GPU().Maxwell3D().regs.rt[index]};
+SurfaceParams SurfaceParams::CreateForFramebuffer(Tegra::Engines::Maxwell3D& maxwell3d,
+ std::size_t index) {
+ const auto& config{maxwell3d.regs.rt[index]};
SurfaceParams params;
params.is_tiled =
config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h
index 118aa689e..4466c3c34 100644
--- a/src/video_core/texture_cache/surface_params.h
+++ b/src/video_core/texture_cache/surface_params.h
@@ -33,10 +33,11 @@ public:
const VideoCommon::Shader::Image& entry);
/// Creates SurfaceCachedParams for a depth buffer configuration.
- static SurfaceParams CreateForDepthBuffer(Core::System& system);
+ static SurfaceParams CreateForDepthBuffer(Tegra::Engines::Maxwell3D& maxwell3d);
/// Creates SurfaceCachedParams from a framebuffer configuration.
- static SurfaceParams CreateForFramebuffer(Core::System& system, std::size_t index);
+ static SurfaceParams CreateForFramebuffer(Tegra::Engines::Maxwell3D& maxwell3d,
+ std::size_t index);
/// Creates SurfaceCachedParams from a Fermi2D surface configuration.
static SurfaceParams CreateForFermiCopySurface(
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 96c4e4cc2..ea835c59f 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -135,8 +135,7 @@ public:
return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
}
- const std::optional<VAddr> cpu_addr =
- system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
if (!cpu_addr) {
return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
}
@@ -160,8 +159,7 @@ public:
if (!gpu_addr) {
return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
}
- const std::optional<VAddr> cpu_addr =
- system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
if (!cpu_addr) {
return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
}
@@ -183,11 +181,11 @@ public:
TView GetDepthBufferSurface(bool preserve_contents) {
std::lock_guard lock{mutex};
- auto& maxwell3d = system.GPU().Maxwell3D();
- if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer]) {
+ auto& dirty = maxwell3d.dirty;
+ if (!dirty.flags[VideoCommon::Dirty::ZetaBuffer]) {
return depth_buffer.view;
}
- maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer] = false;
+ dirty.flags[VideoCommon::Dirty::ZetaBuffer] = false;
const auto& regs{maxwell3d.regs};
const auto gpu_addr{regs.zeta.Address()};
@@ -195,13 +193,12 @@ public:
SetEmptyDepthBuffer();
return {};
}
- const std::optional<VAddr> cpu_addr =
- system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
if (!cpu_addr) {
SetEmptyDepthBuffer();
return {};
}
- const auto depth_params{SurfaceParams::CreateForDepthBuffer(system)};
+ const auto depth_params{SurfaceParams::CreateForDepthBuffer(maxwell3d)};
auto surface_view = GetSurface(gpu_addr, *cpu_addr, depth_params, preserve_contents, true);
if (depth_buffer.target)
depth_buffer.target->MarkAsRenderTarget(false, NO_RT);
@@ -215,7 +212,6 @@ public:
TView GetColorBufferSurface(std::size_t index, bool preserve_contents) {
std::lock_guard lock{mutex};
ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
- auto& maxwell3d = system.GPU().Maxwell3D();
if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ColorBuffer0 + index]) {
return render_targets[index].view;
}
@@ -235,15 +231,14 @@ public:
return {};
}
- const std::optional<VAddr> cpu_addr =
- system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
if (!cpu_addr) {
SetEmptyColorBuffer(index);
return {};
}
auto surface_view =
- GetSurface(gpu_addr, *cpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
+ GetSurface(gpu_addr, *cpu_addr, SurfaceParams::CreateForFramebuffer(maxwell3d, index),
preserve_contents, true);
if (render_targets[index].target) {
auto& surface = render_targets[index].target;
@@ -300,9 +295,8 @@ public:
const GPUVAddr dst_gpu_addr = dst_config.Address();
DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr);
- const auto& memory_manager = system.GPU().MemoryManager();
- const std::optional<VAddr> dst_cpu_addr = memory_manager.GpuToCpuAddress(dst_gpu_addr);
- const std::optional<VAddr> src_cpu_addr = memory_manager.GpuToCpuAddress(src_gpu_addr);
+ const std::optional<VAddr> dst_cpu_addr = gpu_memory.GpuToCpuAddress(dst_gpu_addr);
+ const std::optional<VAddr> src_cpu_addr = gpu_memory.GpuToCpuAddress(src_gpu_addr);
std::pair dst_surface = GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, true, false);
TView src_surface = GetSurface(src_gpu_addr, *src_cpu_addr, src_params, true, false).second;
ImageBlit(src_surface, dst_surface.second, copy_config);
@@ -358,9 +352,11 @@ public:
}
protected:
- explicit TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
- bool is_astc_supported)
- : system{system}, is_astc_supported{is_astc_supported}, rasterizer{rasterizer} {
+ explicit TextureCache(VideoCore::RasterizerInterface& rasterizer_,
+ Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_,
+ bool is_astc_supported_)
+ : is_astc_supported{is_astc_supported_}, rasterizer{rasterizer_}, maxwell3d{maxwell3d_},
+ gpu_memory{gpu_memory_} {
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
SetEmptyColorBuffer(i);
}
@@ -395,7 +391,7 @@ protected:
virtual void BufferCopy(TSurface& src_surface, TSurface& dst_surface) = 0;
void ManageRenderTargetUnregister(TSurface& surface) {
- auto& dirty = system.GPU().Maxwell3D().dirty;
+ auto& dirty = maxwell3d.dirty;
const u32 index = surface->GetRenderTarget();
if (index == DEPTH_RT) {
dirty.flags[VideoCommon::Dirty::ZetaBuffer] = true;
@@ -408,8 +404,7 @@ protected:
void Register(TSurface surface) {
const GPUVAddr gpu_addr = surface->GetGpuAddr();
const std::size_t size = surface->GetSizeInBytes();
- const std::optional<VAddr> cpu_addr =
- system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
if (!cpu_addr) {
LOG_CRITICAL(HW_GPU, "Failed to register surface with unmapped gpu_address 0x{:016x}",
gpu_addr);
@@ -459,7 +454,6 @@ protected:
return new_surface;
}
- Core::System& system;
const bool is_astc_supported;
private:
@@ -954,8 +948,7 @@ private:
* @param params The parameters on the candidate surface.
**/
Deduction DeduceSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) {
- const std::optional<VAddr> cpu_addr =
- system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
+ const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
if (!cpu_addr) {
Deduction result{};
@@ -1112,7 +1105,7 @@ private:
void LoadSurface(const TSurface& surface) {
staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes());
- surface->LoadBuffer(system.GPU().MemoryManager(), staging_cache);
+ surface->LoadBuffer(gpu_memory, staging_cache);
surface->UploadTexture(staging_cache.GetBuffer(0));
surface->MarkAsModified(false, Tick());
}
@@ -1123,7 +1116,7 @@ private:
}
staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes());
surface->DownloadTexture(staging_cache.GetBuffer(0));
- surface->FlushBuffer(system.GPU().MemoryManager(), staging_cache);
+ surface->FlushBuffer(gpu_memory, staging_cache);
surface->MarkAsModified(false, Tick());
}
@@ -1253,6 +1246,8 @@ private:
}
VideoCore::RasterizerInterface& rasterizer;
+ Tegra::Engines::Maxwell3D& maxwell3d;
+ Tegra::MemoryManager& gpu_memory;
FormatLookupTable format_lookup_table;
FormatCompatibility format_compatibility;
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 45f360bdd..a14df06a3 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <memory>
+
#include "common/logging/log.h"
#include "core/core.h"
#include "core/settings.h"
@@ -16,37 +17,49 @@
#include "video_core/video_core.h"
namespace {
-std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window,
- Core::System& system,
- Core::Frontend::GraphicsContext& context) {
+
+std::unique_ptr<VideoCore::RendererBase> CreateRenderer(
+ Core::System& system, Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
+ std::unique_ptr<Core::Frontend::GraphicsContext> context) {
+ auto& telemetry_session = system.TelemetrySession();
+ auto& cpu_memory = system.Memory();
+
switch (Settings::values.renderer_backend.GetValue()) {
case Settings::RendererBackend::OpenGL:
- return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system, context);
+ return std::make_unique<OpenGL::RendererOpenGL>(telemetry_session, emu_window, cpu_memory,
+ gpu, std::move(context));
#ifdef HAS_VULKAN
case Settings::RendererBackend::Vulkan:
- return std::make_unique<Vulkan::RendererVulkan>(emu_window, system);
+ return std::make_unique<Vulkan::RendererVulkan>(telemetry_session, emu_window, cpu_memory,
+ gpu, std::move(context));
#endif
default:
return nullptr;
}
}
+
} // Anonymous namespace
namespace VideoCore {
std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) {
+ std::unique_ptr<Tegra::GPU> gpu;
+ if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
+ gpu = std::make_unique<VideoCommon::GPUAsynch>(system);
+ } else {
+ gpu = std::make_unique<VideoCommon::GPUSynch>(system);
+ }
+
auto context = emu_window.CreateSharedContext();
const auto scope = context->Acquire();
- auto renderer = CreateRenderer(emu_window, system, *context);
+
+ auto renderer = CreateRenderer(system, emu_window, *gpu, std::move(context));
if (!renderer->Init()) {
return nullptr;
}
- if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
- return std::make_unique<VideoCommon::GPUAsynch>(system, std::move(renderer),
- std::move(context));
- }
- return std::make_unique<VideoCommon::GPUSynch>(system, std::move(renderer), std::move(context));
+ gpu->BindRenderer(std::move(renderer));
+ return gpu;
}
u16 GetResolutionScaleFactor(const RendererBase& renderer) {
diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt
index 06ab7c59d..7e484b906 100644
--- a/src/web_service/CMakeLists.txt
+++ b/src/web_service/CMakeLists.txt
@@ -5,6 +5,7 @@ add_library(web_service STATIC
verify_login.h
web_backend.cpp
web_backend.h
+ web_result.h
)
create_target_directory_groups(web_service)
diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp
index c89a3a0db..6215c914f 100644
--- a/src/web_service/telemetry_json.cpp
+++ b/src/web_service/telemetry_json.cpp
@@ -4,9 +4,9 @@
#include <nlohmann/json.hpp>
#include "common/detached_tasks.h"
-#include "common/web_result.h"
#include "web_service/telemetry_json.h"
#include "web_service/web_backend.h"
+#include "web_service/web_result.h"
namespace WebService {
@@ -125,7 +125,7 @@ bool TelemetryJson::SubmitTestcase() {
Client client(impl->host, impl->username, impl->token);
auto value = client.PostJson("/gamedb/testcase", content, false);
- return value.result_code == Common::WebResult::Code::Success;
+ return value.result_code == WebResult::Code::Success;
}
} // namespace WebService
diff --git a/src/web_service/verify_login.cpp b/src/web_service/verify_login.cpp
index bfaa5b70a..ceb55ca6b 100644
--- a/src/web_service/verify_login.cpp
+++ b/src/web_service/verify_login.cpp
@@ -3,9 +3,9 @@
// Refer to the license.txt file included.
#include <nlohmann/json.hpp>
-#include "common/web_result.h"
#include "web_service/verify_login.h"
#include "web_service/web_backend.h"
+#include "web_service/web_result.h"
namespace WebService {
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp
index 09d1651ac..534960d09 100644
--- a/src/web_service/web_backend.cpp
+++ b/src/web_service/web_backend.cpp
@@ -6,13 +6,14 @@
#include <cstdlib>
#include <mutex>
#include <string>
+
#include <LUrlParser.h>
#include <fmt/format.h>
#include <httplib.h>
-#include "common/common_types.h"
+
#include "common/logging/log.h"
-#include "common/web_result.h"
#include "web_service/web_backend.h"
+#include "web_service/web_result.h"
namespace WebService {
@@ -33,17 +34,16 @@ struct Client::Impl {
}
/// A generic function handles POST, GET and DELETE request together
- Common::WebResult GenericRequest(const std::string& method, const std::string& path,
- const std::string& data, bool allow_anonymous,
- const std::string& accept) {
+ WebResult GenericRequest(const std::string& method, const std::string& path,
+ const std::string& data, bool allow_anonymous,
+ const std::string& accept) {
if (jwt.empty()) {
UpdateJWT();
}
if (jwt.empty() && !allow_anonymous) {
LOG_ERROR(WebService, "Credentials must be provided for authenticated requests");
- return Common::WebResult{Common::WebResult::Code::CredentialsMissing,
- "Credentials needed", ""};
+ return WebResult{WebResult::Code::CredentialsMissing, "Credentials needed", ""};
}
auto result = GenericRequest(method, path, data, accept, jwt);
@@ -62,33 +62,30 @@ struct Client::Impl {
* username + token is used if jwt is empty but username and token are
* not empty anonymous if all of jwt, username and token are empty
*/
- Common::WebResult GenericRequest(const std::string& method, const std::string& path,
- const std::string& data, const std::string& accept,
- const std::string& jwt = "", const std::string& username = "",
- const std::string& token = "") {
+ WebResult GenericRequest(const std::string& method, const std::string& path,
+ const std::string& data, const std::string& accept,
+ const std::string& jwt = "", const std::string& username = "",
+ const std::string& token = "") {
if (cli == nullptr) {
- auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);
- int port;
+ const auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);
+ int port{};
if (parsedUrl.m_Scheme == "http") {
if (!parsedUrl.GetPort(&port)) {
port = HTTP_PORT;
}
- cli = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port);
} else if (parsedUrl.m_Scheme == "https") {
if (!parsedUrl.GetPort(&port)) {
port = HTTPS_PORT;
}
- cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port);
} else {
LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme);
- return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme", ""};
+ return WebResult{WebResult::Code::InvalidURL, "Bad URL scheme", ""};
}
+ cli = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port);
}
- if (cli == nullptr) {
- LOG_ERROR(WebService, "Invalid URL {}", host + path);
- return Common::WebResult{Common::WebResult::Code::InvalidURL, "Invalid URL", ""};
- }
- cli->set_timeout_sec(TIMEOUT_SECONDS);
+ cli->set_connection_timeout(TIMEOUT_SECONDS);
+ cli->set_read_timeout(TIMEOUT_SECONDS);
+ cli->set_write_timeout(TIMEOUT_SECONDS);
httplib::Headers params;
if (!jwt.empty()) {
@@ -106,7 +103,7 @@ struct Client::Impl {
std::string(API_VERSION.begin(), API_VERSION.end()));
if (method != "GET") {
params.emplace(std::string("Content-Type"), std::string("application/json"));
- };
+ }
httplib::Request request;
request.method = method;
@@ -118,29 +115,28 @@ struct Client::Impl {
if (!cli->send(request, response)) {
LOG_ERROR(WebService, "{} to {} returned null", method, host + path);
- return Common::WebResult{Common::WebResult::Code::LibError, "Null response", ""};
+ return WebResult{WebResult::Code::LibError, "Null response", ""};
}
if (response.status >= 400) {
LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path,
response.status);
- return Common::WebResult{Common::WebResult::Code::HttpError,
- std::to_string(response.status), ""};
+ return WebResult{WebResult::Code::HttpError, std::to_string(response.status), ""};
}
auto content_type = response.headers.find("content-type");
if (content_type == response.headers.end()) {
LOG_ERROR(WebService, "{} to {} returned no content", method, host + path);
- return Common::WebResult{Common::WebResult::Code::WrongContent, "", ""};
+ return WebResult{WebResult::Code::WrongContent, "", ""};
}
if (content_type->second.find(accept) == std::string::npos) {
LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path,
content_type->second);
- return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content", ""};
+ return WebResult{WebResult::Code::WrongContent, "Wrong content", ""};
}
- return Common::WebResult{Common::WebResult::Code::Success, "", response.body};
+ return WebResult{WebResult::Code::Success, "", response.body};
}
// Retrieve a new JWT from given username and token
@@ -150,7 +146,7 @@ struct Client::Impl {
}
auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token);
- if (result.result_code != Common::WebResult::Code::Success) {
+ if (result.result_code != WebResult::Code::Success) {
LOG_ERROR(WebService, "UpdateJWT failed");
} else {
std::lock_guard lock{jwt_cache.mutex};
@@ -180,29 +176,28 @@ Client::Client(std::string host, std::string username, std::string token)
Client::~Client() = default;
-Common::WebResult Client::PostJson(const std::string& path, const std::string& data,
- bool allow_anonymous) {
+WebResult Client::PostJson(const std::string& path, const std::string& data, bool allow_anonymous) {
return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json");
}
-Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) {
+WebResult Client::GetJson(const std::string& path, bool allow_anonymous) {
return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json");
}
-Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data,
- bool allow_anonymous) {
+WebResult Client::DeleteJson(const std::string& path, const std::string& data,
+ bool allow_anonymous) {
return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json");
}
-Common::WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) {
+WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) {
return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain");
}
-Common::WebResult Client::GetImage(const std::string& path, bool allow_anonymous) {
+WebResult Client::GetImage(const std::string& path, bool allow_anonymous) {
return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png");
}
-Common::WebResult Client::GetExternalJWT(const std::string& audience) {
+WebResult Client::GetExternalJWT(const std::string& audience) {
return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false,
"text/html");
}
diff --git a/src/web_service/web_backend.h b/src/web_service/web_backend.h
index 04121f17e..81f58583c 100644
--- a/src/web_service/web_backend.h
+++ b/src/web_service/web_backend.h
@@ -7,12 +7,10 @@
#include <memory>
#include <string>
-namespace Common {
-struct WebResult;
-}
-
namespace WebService {
+struct WebResult;
+
class Client {
public:
Client(std::string host, std::string username, std::string token);
@@ -25,8 +23,7 @@ public:
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
* @return the result of the request.
*/
- Common::WebResult PostJson(const std::string& path, const std::string& data,
- bool allow_anonymous);
+ WebResult PostJson(const std::string& path, const std::string& data, bool allow_anonymous);
/**
* Gets JSON from the specified path.
@@ -34,7 +31,7 @@ public:
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
* @return the result of the request.
*/
- Common::WebResult GetJson(const std::string& path, bool allow_anonymous);
+ WebResult GetJson(const std::string& path, bool allow_anonymous);
/**
* Deletes JSON to the specified path.
@@ -43,8 +40,7 @@ public:
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
* @return the result of the request.
*/
- Common::WebResult DeleteJson(const std::string& path, const std::string& data,
- bool allow_anonymous);
+ WebResult DeleteJson(const std::string& path, const std::string& data, bool allow_anonymous);
/**
* Gets a plain string from the specified path.
@@ -52,7 +48,7 @@ public:
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
* @return the result of the request.
*/
- Common::WebResult GetPlain(const std::string& path, bool allow_anonymous);
+ WebResult GetPlain(const std::string& path, bool allow_anonymous);
/**
* Gets an PNG image from the specified path.
@@ -60,14 +56,14 @@ public:
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
* @return the result of the request.
*/
- Common::WebResult GetImage(const std::string& path, bool allow_anonymous);
+ WebResult GetImage(const std::string& path, bool allow_anonymous);
/**
* Requests an external JWT for the specific audience provided.
* @param audience the audience of the JWT requested.
* @return the result of the request.
*/
- Common::WebResult GetExternalJWT(const std::string& audience);
+ WebResult GetExternalJWT(const std::string& audience);
private:
struct Impl;
diff --git a/src/common/web_result.h b/src/web_service/web_result.h
index 8bfa2141d..3aeeb5288 100644
--- a/src/common/web_result.h
+++ b/src/web_service/web_result.h
@@ -7,7 +7,7 @@
#include <string>
#include "common/common_types.h"
-namespace Common {
+namespace WebService {
struct WebResult {
enum class Code : u32 {
Success,
@@ -22,4 +22,4 @@ struct WebResult {
std::string result_string;
std::string returned_data;
};
-} // namespace Common
+} // namespace WebService
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 656096c9f..cc0291b15 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -9,6 +9,9 @@ add_executable(yuzu
about_dialog.cpp
about_dialog.h
aboutdialog.ui
+ applets/controller.cpp
+ applets/controller.h
+ applets/controller.ui
applets/error.cpp
applets/error.h
applets/profile_select.cpp
@@ -39,6 +42,9 @@ add_executable(yuzu
configuration/configure_debug.cpp
configuration/configure_debug.h
configuration/configure_debug.ui
+ configuration/configure_debug_controller.cpp
+ configuration/configure_debug_controller.h
+ configuration/configure_debug_controller.ui
configuration/configure_dialog.cpp
configuration/configure_dialog.h
configuration/configure_filesystem.cpp
@@ -59,12 +65,18 @@ add_executable(yuzu
configuration/configure_input.cpp
configuration/configure_input.h
configuration/configure_input.ui
+ configuration/configure_input_advanced.cpp
+ configuration/configure_input_advanced.h
+ configuration/configure_input_advanced.ui
+ configuration/configure_input_dialog.cpp
+ configuration/configure_input_dialog.h
+ configuration/configure_input_dialog.ui
configuration/configure_input_player.cpp
configuration/configure_input_player.h
configuration/configure_input_player.ui
- configuration/configure_input_simple.cpp
- configuration/configure_input_simple.h
- configuration/configure_input_simple.ui
+ configuration/configure_motion_touch.cpp
+ configuration/configure_motion_touch.h
+ configuration/configure_motion_touch.ui
configuration/configure_mouse_advanced.cpp
configuration/configure_mouse_advanced.h
configuration/configure_mouse_advanced.ui
@@ -83,9 +95,13 @@ add_executable(yuzu
configuration/configure_system.cpp
configuration/configure_system.h
configuration/configure_system.ui
+ configuration/configure_touch_from_button.cpp
+ configuration/configure_touch_from_button.h
+ configuration/configure_touch_from_button.ui
configuration/configure_touchscreen_advanced.cpp
configuration/configure_touchscreen_advanced.h
configuration/configure_touchscreen_advanced.ui
+ configuration/configure_touch_widget.h
configuration/configure_ui.cpp
configuration/configure_ui.h
configuration/configure_ui.ui
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
new file mode 100644
index 000000000..9d45f2a01
--- /dev/null
+++ b/src/yuzu/applets/controller.cpp
@@ -0,0 +1,601 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+
+#include "common/assert.h"
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/hle/lock.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/sm/sm.h"
+#include "ui_controller.h"
+#include "yuzu/applets/controller.h"
+#include "yuzu/configuration/configure_input_dialog.h"
+#include "yuzu/main.h"
+
+namespace {
+
+constexpr std::array<std::array<bool, 4>, 8> led_patterns = {{
+ {1, 0, 0, 0},
+ {1, 1, 0, 0},
+ {1, 1, 1, 0},
+ {1, 1, 1, 1},
+ {1, 0, 0, 1},
+ {1, 0, 1, 0},
+ {1, 0, 1, 1},
+ {0, 1, 1, 0},
+}};
+
+void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
+ bool connected) {
+ Core::System& system{Core::System::GetInstance()};
+
+ if (!system.IsPoweredOn()) {
+ return;
+ }
+
+ Service::SM::ServiceManager& sm = system.ServiceManager();
+
+ auto& npad =
+ sm.GetService<Service::HID::Hid>("hid")
+ ->GetAppletResource()
+ ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
+
+ npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
+}
+
+// Returns true if the given controller type is compatible with the given parameters.
+bool IsControllerCompatible(Settings::ControllerType controller_type,
+ Core::Frontend::ControllerParameters parameters) {
+ switch (controller_type) {
+ case Settings::ControllerType::ProController:
+ return parameters.allow_pro_controller;
+ case Settings::ControllerType::DualJoyconDetached:
+ return parameters.allow_dual_joycons;
+ case Settings::ControllerType::LeftJoycon:
+ return parameters.allow_left_joycon;
+ case Settings::ControllerType::RightJoycon:
+ return parameters.allow_right_joycon;
+ case Settings::ControllerType::Handheld:
+ return parameters.enable_single_mode && parameters.allow_handheld;
+ default:
+ return false;
+ }
+}
+
+/// Maps the controller type combobox index to Controller Type enum
+constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) {
+ switch (index) {
+ case 0:
+ default:
+ return Settings::ControllerType::ProController;
+ case 1:
+ return Settings::ControllerType::DualJoyconDetached;
+ case 2:
+ return Settings::ControllerType::LeftJoycon;
+ case 3:
+ return Settings::ControllerType::RightJoycon;
+ case 4:
+ return Settings::ControllerType::Handheld;
+ }
+}
+
+/// Maps the Controller Type enum to controller type combobox index
+constexpr int GetIndexFromControllerType(Settings::ControllerType type) {
+ switch (type) {
+ case Settings::ControllerType::ProController:
+ default:
+ return 0;
+ case Settings::ControllerType::DualJoyconDetached:
+ return 1;
+ case Settings::ControllerType::LeftJoycon:
+ return 2;
+ case Settings::ControllerType::RightJoycon:
+ return 3;
+ case Settings::ControllerType::Handheld:
+ return 4;
+ }
+}
+
+} // namespace
+
+QtControllerSelectorDialog::QtControllerSelectorDialog(
+ QWidget* parent, Core::Frontend::ControllerParameters parameters_,
+ InputCommon::InputSubsystem* input_subsystem_)
+ : QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()),
+ parameters(std::move(parameters_)), input_subsystem(input_subsystem_) {
+ ui->setupUi(this);
+
+ player_widgets = {
+ ui->widgetPlayer1, ui->widgetPlayer2, ui->widgetPlayer3, ui->widgetPlayer4,
+ ui->widgetPlayer5, ui->widgetPlayer6, ui->widgetPlayer7, ui->widgetPlayer8,
+ };
+
+ player_groupboxes = {
+ ui->groupPlayer1Connected, ui->groupPlayer2Connected, ui->groupPlayer3Connected,
+ ui->groupPlayer4Connected, ui->groupPlayer5Connected, ui->groupPlayer6Connected,
+ ui->groupPlayer7Connected, ui->groupPlayer8Connected,
+ };
+
+ connected_controller_icons = {
+ ui->controllerPlayer1, ui->controllerPlayer2, ui->controllerPlayer3, ui->controllerPlayer4,
+ ui->controllerPlayer5, ui->controllerPlayer6, ui->controllerPlayer7, ui->controllerPlayer8,
+ };
+
+ led_patterns_boxes = {{
+ {ui->checkboxPlayer1LED1, ui->checkboxPlayer1LED2, ui->checkboxPlayer1LED3,
+ ui->checkboxPlayer1LED4},
+ {ui->checkboxPlayer2LED1, ui->checkboxPlayer2LED2, ui->checkboxPlayer2LED3,
+ ui->checkboxPlayer2LED4},
+ {ui->checkboxPlayer3LED1, ui->checkboxPlayer3LED2, ui->checkboxPlayer3LED3,
+ ui->checkboxPlayer3LED4},
+ {ui->checkboxPlayer4LED1, ui->checkboxPlayer4LED2, ui->checkboxPlayer4LED3,
+ ui->checkboxPlayer4LED4},
+ {ui->checkboxPlayer5LED1, ui->checkboxPlayer5LED2, ui->checkboxPlayer5LED3,
+ ui->checkboxPlayer5LED4},
+ {ui->checkboxPlayer6LED1, ui->checkboxPlayer6LED2, ui->checkboxPlayer6LED3,
+ ui->checkboxPlayer6LED4},
+ {ui->checkboxPlayer7LED1, ui->checkboxPlayer7LED2, ui->checkboxPlayer7LED3,
+ ui->checkboxPlayer7LED4},
+ {ui->checkboxPlayer8LED1, ui->checkboxPlayer8LED2, ui->checkboxPlayer8LED3,
+ ui->checkboxPlayer8LED4},
+ }};
+
+ explain_text_labels = {
+ ui->labelPlayer1Explain, ui->labelPlayer2Explain, ui->labelPlayer3Explain,
+ ui->labelPlayer4Explain, ui->labelPlayer5Explain, ui->labelPlayer6Explain,
+ ui->labelPlayer7Explain, ui->labelPlayer8Explain,
+ };
+
+ emulated_controllers = {
+ ui->comboPlayer1Emulated, ui->comboPlayer2Emulated, ui->comboPlayer3Emulated,
+ ui->comboPlayer4Emulated, ui->comboPlayer5Emulated, ui->comboPlayer6Emulated,
+ ui->comboPlayer7Emulated, ui->comboPlayer8Emulated,
+ };
+
+ player_labels = {
+ ui->labelPlayer1, ui->labelPlayer2, ui->labelPlayer3, ui->labelPlayer4,
+ ui->labelPlayer5, ui->labelPlayer6, ui->labelPlayer7, ui->labelPlayer8,
+ };
+
+ connected_controller_labels = {
+ ui->labelConnectedPlayer1, ui->labelConnectedPlayer2, ui->labelConnectedPlayer3,
+ ui->labelConnectedPlayer4, ui->labelConnectedPlayer5, ui->labelConnectedPlayer6,
+ ui->labelConnectedPlayer7, ui->labelConnectedPlayer8,
+ };
+
+ connected_controller_checkboxes = {
+ ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected,
+ ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected,
+ ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
+ };
+
+ // Setup/load everything prior to setting up connections.
+ // This avoids unintentionally changing the states of elements while loading them in.
+ SetSupportedControllers();
+ DisableUnsupportedPlayers();
+ LoadConfiguration();
+
+ for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
+ SetExplainText(i);
+ UpdateControllerIcon(i);
+ UpdateLEDPattern(i);
+ UpdateBorderColor(i);
+
+ connect(player_groupboxes[i], &QGroupBox::toggled, [this, i](bool checked) {
+ if (checked) {
+ for (std::size_t index = 0; index <= i; ++index) {
+ connected_controller_checkboxes[index]->setChecked(checked);
+ }
+ } else {
+ for (std::size_t index = i; index < NUM_PLAYERS; ++index) {
+ connected_controller_checkboxes[index]->setChecked(checked);
+ }
+ }
+ });
+
+ connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
+ [this, i](int) {
+ UpdateControllerIcon(i);
+ UpdateControllerState(i);
+ UpdateLEDPattern(i);
+ CheckIfParametersMet();
+ });
+
+ connect(connected_controller_checkboxes[i], &QCheckBox::stateChanged, [this, i](int state) {
+ player_groupboxes[i]->setChecked(state == Qt::Checked);
+ UpdateControllerIcon(i);
+ UpdateControllerState(i);
+ UpdateLEDPattern(i);
+ UpdateBorderColor(i);
+ CheckIfParametersMet();
+ });
+
+ if (i == 0) {
+ connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
+ [this](int index) {
+ UpdateDockedState(GetControllerTypeFromIndex(index) ==
+ Settings::ControllerType::Handheld);
+ });
+ }
+ }
+
+ connect(ui->inputConfigButton, &QPushButton::clicked, this,
+ &QtControllerSelectorDialog::CallConfigureInputDialog);
+
+ connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
+ &QtControllerSelectorDialog::ApplyConfiguration);
+
+ // If keep_controllers_connected is false, forcefully disconnect all controllers
+ if (!parameters.keep_controllers_connected) {
+ for (auto player : player_groupboxes) {
+ player->setChecked(false);
+ }
+ }
+
+ CheckIfParametersMet();
+
+ resize(0, 0);
+}
+
+QtControllerSelectorDialog::~QtControllerSelectorDialog() = default;
+
+void QtControllerSelectorDialog::ApplyConfiguration() {
+ // Update the controller state once more, just to be sure they are properly applied.
+ for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
+ UpdateControllerState(index);
+ }
+
+ const bool pre_docked_mode = Settings::values.use_docked_mode;
+ Settings::values.use_docked_mode = ui->radioDocked->isChecked();
+ OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
+
+ Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
+}
+
+void QtControllerSelectorDialog::LoadConfiguration() {
+ for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
+ const auto connected = Settings::values.players[index].connected ||
+ (index == 0 && Settings::values.players[8].connected);
+ player_groupboxes[index]->setChecked(connected);
+ connected_controller_checkboxes[index]->setChecked(connected);
+ emulated_controllers[index]->setCurrentIndex(
+ GetIndexFromControllerType(Settings::values.players[index].controller_type));
+ }
+
+ UpdateDockedState(Settings::values.players[8].connected);
+
+ ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
+}
+
+void QtControllerSelectorDialog::CallConfigureInputDialog() {
+ const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
+
+ ConfigureInputDialog dialog(this, max_supported_players, input_subsystem);
+
+ dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
+ Qt::WindowSystemMenuHint);
+ dialog.setWindowModality(Qt::WindowModal);
+ dialog.exec();
+
+ dialog.ApplyConfiguration();
+
+ LoadConfiguration();
+ CheckIfParametersMet();
+}
+
+void QtControllerSelectorDialog::CheckIfParametersMet() {
+ // Here, we check and validate the current configuration against all applicable parameters.
+ const auto num_connected_players = static_cast<int>(
+ std::count_if(player_groupboxes.begin(), player_groupboxes.end(),
+ [this](const QGroupBox* player) { return player->isChecked(); }));
+
+ const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players;
+ const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
+
+ // First, check against the number of connected players.
+ if (num_connected_players < min_supported_players ||
+ num_connected_players > max_supported_players) {
+ parameters_met = false;
+ ui->buttonBox->setEnabled(parameters_met);
+ return;
+ }
+
+ // Next, check against all connected controllers.
+ const auto all_controllers_compatible = [this] {
+ for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
+ // Skip controllers that are not used, we only care about the currently connected ones.
+ if (!player_groupboxes[index]->isChecked() || !player_groupboxes[index]->isEnabled()) {
+ continue;
+ }
+
+ const auto compatible = IsControllerCompatible(
+ GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex()),
+ parameters);
+
+ // If any controller is found to be incompatible, return false early.
+ if (!compatible) {
+ return false;
+ }
+ }
+
+ // Reaching here means all currently connected controllers are compatible.
+ return true;
+ }();
+
+ if (!all_controllers_compatible) {
+ parameters_met = false;
+ ui->buttonBox->setEnabled(parameters_met);
+ return;
+ }
+
+ parameters_met = true;
+ ui->buttonBox->setEnabled(parameters_met);
+}
+
+void QtControllerSelectorDialog::SetSupportedControllers() {
+ const QString theme = [this] {
+ if (QIcon::themeName().contains(QStringLiteral("dark"))) {
+ return QStringLiteral("_dark");
+ } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
+ return QStringLiteral("_midnight");
+ } else {
+ return QString{};
+ }
+ }();
+
+ if (parameters.enable_single_mode && parameters.allow_handheld) {
+ ui->controllerSupported1->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_handheld%0); ").arg(theme));
+ } else {
+ ui->controllerSupported1->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_handheld%0_disabled); ").arg(theme));
+ }
+
+ if (parameters.allow_dual_joycons) {
+ ui->controllerSupported2->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ").arg(theme));
+ } else {
+ ui->controllerSupported2->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_dual_joycon%0_disabled); ").arg(theme));
+ }
+
+ if (parameters.allow_left_joycon) {
+ ui->controllerSupported3->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_joycon_left%0); ").arg(theme));
+ } else {
+ ui->controllerSupported3->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_joycon_left%0_disabled); ").arg(theme));
+ }
+
+ if (parameters.allow_right_joycon) {
+ ui->controllerSupported4->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_joycon_right%0); ").arg(theme));
+ } else {
+ ui->controllerSupported4->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme));
+ }
+
+ if (parameters.allow_pro_controller) {
+ ui->controllerSupported5->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme));
+ } else {
+ ui->controllerSupported5->setStyleSheet(
+ QStringLiteral("image: url(:/controller/applet_pro_controller%0_disabled); ")
+ .arg(theme));
+ }
+
+ // enable_single_mode overrides min_players and max_players.
+ if (parameters.enable_single_mode) {
+ ui->numberSupportedLabel->setText(QStringLiteral("1"));
+ return;
+ }
+
+ if (parameters.min_players == parameters.max_players) {
+ ui->numberSupportedLabel->setText(QStringLiteral("%1").arg(parameters.max_players));
+ } else {
+ ui->numberSupportedLabel->setText(
+ QStringLiteral("%1 - %2").arg(parameters.min_players).arg(parameters.max_players));
+ }
+}
+
+void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) {
+ if (!player_groupboxes[player_index]->isChecked()) {
+ connected_controller_icons[player_index]->setStyleSheet(QString{});
+ player_labels[player_index]->show();
+ return;
+ }
+
+ const QString stylesheet = [this, player_index] {
+ switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex())) {
+ case Settings::ControllerType::ProController:
+ return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
+ case Settings::ControllerType::DualJoyconDetached:
+ return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
+ case Settings::ControllerType::LeftJoycon:
+ return QStringLiteral("image: url(:/controller/applet_joycon_left%0); ");
+ case Settings::ControllerType::RightJoycon:
+ return QStringLiteral("image: url(:/controller/applet_joycon_right%0); ");
+ case Settings::ControllerType::Handheld:
+ return QStringLiteral("image: url(:/controller/applet_handheld%0); ");
+ default:
+ return QString{};
+ }
+ }();
+
+ const QString theme = [this] {
+ if (QIcon::themeName().contains(QStringLiteral("dark"))) {
+ return QStringLiteral("_dark");
+ } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
+ return QStringLiteral("_midnight");
+ } else {
+ return QString{};
+ }
+ }();
+
+ connected_controller_icons[player_index]->setStyleSheet(stylesheet.arg(theme));
+ player_labels[player_index]->hide();
+}
+
+void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
+ auto& player = Settings::values.players[player_index];
+
+ player.controller_type =
+ GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex());
+ player.connected = player_groupboxes[player_index]->isChecked();
+
+ // Player 2-8
+ if (player_index != 0) {
+ UpdateController(player.controller_type, player_index, player.connected);
+ return;
+ }
+
+ // Player 1 and Handheld
+ auto& handheld = Settings::values.players[8];
+ // If Handheld is selected, copy all the settings from Player 1 to Handheld.
+ if (player.controller_type == Settings::ControllerType::Handheld) {
+ handheld = player;
+ handheld.connected = player_groupboxes[player_index]->isChecked();
+ player.connected = false; // Disconnect Player 1
+ } else {
+ player.connected = player_groupboxes[player_index]->isChecked();
+ handheld.connected = false; // Disconnect Handheld
+ }
+
+ UpdateController(player.controller_type, player_index, player.connected);
+ UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected);
+}
+
+void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
+ if (!player_groupboxes[player_index]->isChecked() ||
+ GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()) ==
+ Settings::ControllerType::Handheld) {
+ led_patterns_boxes[player_index][0]->setChecked(false);
+ led_patterns_boxes[player_index][1]->setChecked(false);
+ led_patterns_boxes[player_index][2]->setChecked(false);
+ led_patterns_boxes[player_index][3]->setChecked(false);
+ return;
+ }
+
+ led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]);
+ led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]);
+ led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]);
+ led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]);
+}
+
+void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) {
+ if (!parameters.enable_border_color ||
+ player_index >= static_cast<std::size_t>(parameters.max_players) ||
+ player_groupboxes[player_index]->styleSheet().contains(QStringLiteral("QGroupBox"))) {
+ return;
+ }
+
+ player_groupboxes[player_index]->setStyleSheet(
+ player_groupboxes[player_index]->styleSheet().append(
+ QStringLiteral("QGroupBox#groupPlayer%1Connected:checked "
+ "{ border: 1px solid rgba(%2, %3, %4, %5); }")
+ .arg(player_index + 1)
+ .arg(parameters.border_colors[player_index][0])
+ .arg(parameters.border_colors[player_index][1])
+ .arg(parameters.border_colors[player_index][2])
+ .arg(parameters.border_colors[player_index][3])));
+}
+
+void QtControllerSelectorDialog::SetExplainText(std::size_t player_index) {
+ if (!parameters.enable_explain_text ||
+ player_index >= static_cast<std::size_t>(parameters.max_players)) {
+ return;
+ }
+
+ explain_text_labels[player_index]->setText(QString::fromStdString(
+ Common::StringFromFixedZeroTerminatedBuffer(parameters.explain_text[player_index].data(),
+ parameters.explain_text[player_index].size())));
+}
+
+void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) {
+ // Disallow changing the console mode if the controller type is handheld.
+ ui->radioDocked->setEnabled(!is_handheld);
+ ui->radioUndocked->setEnabled(!is_handheld);
+
+ ui->radioDocked->setChecked(Settings::values.use_docked_mode);
+ ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
+
+ // Also force into undocked mode if the controller type is handheld.
+ if (is_handheld) {
+ ui->radioUndocked->setChecked(true);
+ }
+}
+
+void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
+ const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
+
+ switch (max_supported_players) {
+ case 0:
+ default:
+ UNREACHABLE();
+ return;
+ case 1:
+ ui->widgetSpacer->hide();
+ ui->widgetSpacer2->hide();
+ ui->widgetSpacer3->hide();
+ ui->widgetSpacer4->hide();
+ break;
+ case 2:
+ ui->widgetSpacer->hide();
+ ui->widgetSpacer2->hide();
+ ui->widgetSpacer3->hide();
+ break;
+ case 3:
+ ui->widgetSpacer->hide();
+ ui->widgetSpacer2->hide();
+ break;
+ case 4:
+ ui->widgetSpacer->hide();
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ break;
+ }
+
+ for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) {
+ // Disconnect any unsupported players here and disable or hide them if applicable.
+ Settings::values.players[index].connected = false;
+ UpdateController(Settings::values.players[index].controller_type, index, false);
+ // Hide the player widgets when max_supported_controllers is less than or equal to 4.
+ if (max_supported_players <= 4) {
+ player_widgets[index]->hide();
+ }
+
+ // Disable and hide the following to prevent these from interaction.
+ player_widgets[index]->setDisabled(true);
+ connected_controller_checkboxes[index]->setDisabled(true);
+ connected_controller_labels[index]->hide();
+ connected_controller_checkboxes[index]->hide();
+ }
+}
+
+QtControllerSelector::QtControllerSelector(GMainWindow& parent) {
+ connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent,
+ &GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection);
+ connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this,
+ &QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection);
+}
+
+QtControllerSelector::~QtControllerSelector() = default;
+
+void QtControllerSelector::ReconfigureControllers(
+ std::function<void()> callback, Core::Frontend::ControllerParameters parameters) const {
+ this->callback = std::move(callback);
+ emit MainWindowReconfigureControllers(parameters);
+}
+
+void QtControllerSelector::MainWindowReconfigureFinished() {
+ // Acquire the HLE mutex
+ std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
+ callback();
+}
diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h
new file mode 100644
index 000000000..2d6d588c6
--- /dev/null
+++ b/src/yuzu/applets/controller.h
@@ -0,0 +1,133 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <QDialog>
+#include "core/frontend/applets/controller.h"
+
+class GMainWindow;
+class QCheckBox;
+class QComboBox;
+class QDialogButtonBox;
+class QGroupBox;
+class QLabel;
+
+namespace InputCommon {
+class InputSubsystem;
+}
+
+namespace Ui {
+class QtControllerSelectorDialog;
+}
+
+class QtControllerSelectorDialog final : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit QtControllerSelectorDialog(QWidget* parent,
+ Core::Frontend::ControllerParameters parameters_,
+ InputCommon::InputSubsystem* input_subsystem_);
+ ~QtControllerSelectorDialog() override;
+
+private:
+ // Applies the current configuration.
+ void ApplyConfiguration();
+
+ // Loads the current input configuration into the frontend applet.
+ void LoadConfiguration();
+
+ // Initializes the "Configure Input" Dialog.
+ void CallConfigureInputDialog();
+
+ // Checks the current configuration against the given parameters and
+ // sets the value of parameters_met.
+ void CheckIfParametersMet();
+
+ // Sets the controller icons for "Supported Controller Types".
+ void SetSupportedControllers();
+
+ // Updates the controller icons per player.
+ void UpdateControllerIcon(std::size_t player_index);
+
+ // Updates the controller state (type and connection status) per player.
+ void UpdateControllerState(std::size_t player_index);
+
+ // Updates the LED pattern per player.
+ void UpdateLEDPattern(std::size_t player_index);
+
+ // Updates the border color per player.
+ void UpdateBorderColor(std::size_t player_index);
+
+ // Sets the "Explain Text" per player.
+ void SetExplainText(std::size_t player_index);
+
+ // Updates the console mode.
+ void UpdateDockedState(bool is_handheld);
+
+ // Disables and disconnects unsupported players based on the given parameters.
+ void DisableUnsupportedPlayers();
+
+ std::unique_ptr<Ui::QtControllerSelectorDialog> ui;
+
+ // Parameters sent in from the backend HLE applet.
+ Core::Frontend::ControllerParameters parameters;
+
+ InputCommon::InputSubsystem* input_subsystem;
+
+ // This is true if and only if all parameters are met. Otherwise, this is false.
+ // This determines whether the "OK" button can be clicked to exit the applet.
+ bool parameters_met{false};
+
+ static constexpr std::size_t NUM_PLAYERS = 8;
+
+ // Widgets encapsulating the groupboxes and comboboxes per player.
+ std::array<QWidget*, NUM_PLAYERS> player_widgets;
+
+ // Groupboxes encapsulating the controller icons and LED patterns per player.
+ std::array<QGroupBox*, NUM_PLAYERS> player_groupboxes;
+
+ // Icons for currently connected controllers/players.
+ std::array<QWidget*, NUM_PLAYERS> connected_controller_icons;
+
+ // Labels that represent the player numbers in place of the controller icons.
+ std::array<QLabel*, NUM_PLAYERS> player_labels;
+
+ // LED patterns for currently connected controllers/players.
+ std::array<std::array<QCheckBox*, 4>, NUM_PLAYERS> led_patterns_boxes;
+
+ // Labels representing additional information known as "Explain Text" per player.
+ std::array<QLabel*, NUM_PLAYERS> explain_text_labels;
+
+ // Comboboxes with a list of emulated controllers per player.
+ std::array<QComboBox*, NUM_PLAYERS> emulated_controllers;
+
+ // Labels representing the number of connected controllers
+ // above the "Connected Controllers" checkboxes.
+ std::array<QLabel*, NUM_PLAYERS> connected_controller_labels;
+
+ // Checkboxes representing the "Connected Controllers".
+ std::array<QCheckBox*, NUM_PLAYERS> connected_controller_checkboxes;
+};
+
+class QtControllerSelector final : public QObject, public Core::Frontend::ControllerApplet {
+ Q_OBJECT
+
+public:
+ explicit QtControllerSelector(GMainWindow& parent);
+ ~QtControllerSelector() override;
+
+ void ReconfigureControllers(std::function<void()> callback,
+ Core::Frontend::ControllerParameters parameters) const override;
+
+signals:
+ void MainWindowReconfigureControllers(Core::Frontend::ControllerParameters parameters) const;
+
+private:
+ void MainWindowReconfigureFinished();
+
+ mutable std::function<void()> callback;
+};
diff --git a/src/yuzu/applets/controller.ui b/src/yuzu/applets/controller.ui
new file mode 100644
index 000000000..c4108a979
--- /dev/null
+++ b/src/yuzu/applets/controller.ui
@@ -0,0 +1,2672 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtControllerSelectorDialog</class>
+ <widget class="QDialog" name="QtControllerSelectorDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>839</width>
+ <height>630</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Controller Applet</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="mainControllerApplet" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,3,0">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="topControllerApplet" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>10</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>10</number>
+ </property>
+ <item>
+ <spacer name="controllerAppletHorizontalSpacer2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="controllersSupported" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_21">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="controllersSupportedLabel">
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Supported Controller Types:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="controllerSupported1" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="controllerSupported2" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="controllerSupported3" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="controllerSupported4" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="controllerSupported5" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="playersSupported" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>70</width>
+ <height>70</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_20">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>16</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>16</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="maxSupportedLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Players:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="numberSupportedLabel">
+ <property name="font">
+ <font>
+ <pointsize>14</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>1 - 8</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="controllerAppletHorizontalSpacer3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="middleControllerApplet" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <item row="1" column="7">
+ <widget class="QWidget" name="widgetPlayer4" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_27">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="groupPlayer4Connected">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_7" stretch="1,0">
+ <property name="spacing">
+ <number>7</number>
+ </property>
+ <property name="leftMargin">
+ <number>14</number>
+ </property>
+ <property name="topMargin">
+ <number>7</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="controllerPlayer4" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_15">
+ <property name="topMargin">
+ <number>16</number>
+ </property>
+ <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
+ <widget class="QLabel" name="labelPlayer4">
+ <property name="text">
+ <string>P4</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="Player4LEDs" native="true">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_10">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer4LED1"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer4LED2"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer4LED3"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer4LED4"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Player4Explain" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_39">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelPlayer4Explain">
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer4Emulated">
+ <item>
+ <property name="text">
+ <string>Pro Controller</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dual Joycons</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left Joycon</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right Joycon</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer4Profile">
+ <item>
+ <property name="text">
+ <string>Use Current Config</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QWidget" name="widgetPlayer2" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_29">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="groupPlayer2Connected">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_5" stretch="1,0">
+ <property name="spacing">
+ <number>7</number>
+ </property>
+ <property name="leftMargin">
+ <number>14</number>
+ </property>
+ <property name="topMargin">
+ <number>7</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="controllerPlayer2" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_13">
+ <property name="topMargin">
+ <number>16</number>
+ </property>
+ <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
+ <widget class="QLabel" name="labelPlayer2">
+ <property name="text">
+ <string>P2</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="Player2LEDs" native="true">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer2LED1"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer2LED2"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer2LED3"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer2LED4"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Player2Explain" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_37">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelPlayer2Explain">
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer2Emulated">
+ <item>
+ <property name="text">
+ <string>Pro Controller</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dual Joycons</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left Joycon</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right Joycon</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer2Profile">
+ <item>
+ <property name="text">
+ <string>Use Current Config</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QWidget" name="widgetPlayer1" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_30">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="groupPlayer1Connected">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4" stretch="1,0">
+ <property name="spacing">
+ <number>7</number>
+ </property>
+ <property name="leftMargin">
+ <number>14</number>
+ </property>
+ <property name="topMargin">
+ <number>7</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="controllerPlayer1" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_12">
+ <property name="topMargin">
+ <number>16</number>
+ </property>
+ <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
+ <widget class="QLabel" name="labelPlayer1">
+ <property name="text">
+ <string>P1</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="Player1LEDs" native="true">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer1LED1">
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer1LED2"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer1LED3"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer1LED4"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Player1Explain" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_36">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelPlayer1Explain">
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer1Emulated">
+ <item>
+ <property name="text">
+ <string>Pro Controller</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dual Joycons</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left Joycon</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right Joycon</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Handheld</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer1Profile">
+ <item>
+ <property name="text">
+ <string>Use Current Config</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="8">
+ <widget class="QWidget" name="widgetSpacer2" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>25</width>
+ <height>0</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_31">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="controllerAppletHorizontalSpacer8">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>25</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QWidget" name="widgetSpacer4" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_33">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="controllerAppletHorizontalSpacer6">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="6">
+ <widget class="QWidget" name="widgetSpacer3" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_32">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="controllerAppletHorizontalSpacer7">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="5">
+ <widget class="QWidget" name="widgetPlayer3" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_28">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="groupPlayer3Connected">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_6" stretch="1,0">
+ <property name="spacing">
+ <number>7</number>
+ </property>
+ <property name="leftMargin">
+ <number>14</number>
+ </property>
+ <property name="topMargin">
+ <number>7</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="controllerPlayer3" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_14">
+ <property name="topMargin">
+ <number>16</number>
+ </property>
+ <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
+ <widget class="QLabel" name="labelPlayer3">
+ <property name="text">
+ <string>P3</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="Player3LEDs" native="true">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_9">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer3LED1"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer3LED2"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer3LED3"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer3LED4"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Player3Explain" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_38">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelPlayer3Explain">
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer3Emulated">
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ <item>
+ <property name="text">
+ <string>Pro Controller</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dual Joycons</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left Joycon</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right Joycon</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer3Profile">
+ <item>
+ <property name="text">
+ <string>Use Current Config</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QWidget" name="widgetSpacer5" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>25</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_34">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="controllerAppletVerticalSpacer3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>25</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="6" column="5">
+ <widget class="QWidget" name="widgetPlayer7" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_25">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="groupPlayer7Connected">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_10" stretch="1,0">
+ <property name="spacing">
+ <number>7</number>
+ </property>
+ <property name="leftMargin">
+ <number>14</number>
+ </property>
+ <property name="topMargin">
+ <number>7</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="controllerPlayer7" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_18">
+ <property name="topMargin">
+ <number>16</number>
+ </property>
+ <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
+ <widget class="QLabel" name="labelPlayer7">
+ <property name="text">
+ <string>P7</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="Player7LEDs" native="true">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_13">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer7LED1"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer7LED2"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer7LED3"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer7LED4"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Player7Explain" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_42">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelPlayer7Explain">
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer7Emulated">
+ <item>
+ <property name="text">
+ <string>Pro Controller</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dual Joycons</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left Joycon</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right Joycon</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer7Profile">
+ <item>
+ <property name="text">
+ <string>Use Current Config</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="6" column="7">
+ <widget class="QWidget" name="widgetPlayer8" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_26">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="groupPlayer8Connected">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_11" stretch="1,0">
+ <property name="spacing">
+ <number>7</number>
+ </property>
+ <property name="leftMargin">
+ <number>14</number>
+ </property>
+ <property name="topMargin">
+ <number>7</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="controllerPlayer8" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_19">
+ <property name="topMargin">
+ <number>16</number>
+ </property>
+ <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
+ <widget class="QLabel" name="labelPlayer8">
+ <property name="text">
+ <string>P8</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="Player8LEDs" native="true">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_14">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer8LED1"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer8LED2"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer8LED3"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer8LED4"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Player8Explain" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_35">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelPlayer8Explain">
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer8Emulated">
+ <item>
+ <property name="text">
+ <string>Pro Controller</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dual Joycons</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left Joycon</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right Joycon</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer8Profile">
+ <item>
+ <property name="text">
+ <string>Use Current Config</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QWidget" name="widgetPlayer5" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_23">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="groupPlayer5Connected">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_8" stretch="1,0">
+ <property name="spacing">
+ <number>7</number>
+ </property>
+ <property name="leftMargin">
+ <number>14</number>
+ </property>
+ <property name="topMargin">
+ <number>7</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="controllerPlayer5" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_16">
+ <property name="topMargin">
+ <number>16</number>
+ </property>
+ <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
+ <widget class="QLabel" name="labelPlayer5">
+ <property name="text">
+ <string>P5</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="Player5LEDs" native="true">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_11">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer5LED1">
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer5LED2"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer5LED3"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer5LED4"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Player5Explain" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_40">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelPlayer5Explain">
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer5Emulated">
+ <item>
+ <property name="text">
+ <string>Pro Controller</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dual Joycons</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left Joycon</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right Joycon</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer5Profile">
+ <item>
+ <property name="text">
+ <string>Use Current Config</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="6" column="3">
+ <widget class="QWidget" name="widgetPlayer6" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_24">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="groupPlayer6Connected">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_9" stretch="1,0">
+ <property name="spacing">
+ <number>7</number>
+ </property>
+ <property name="leftMargin">
+ <number>14</number>
+ </property>
+ <property name="topMargin">
+ <number>7</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="controllerPlayer6" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_17">
+ <property name="topMargin">
+ <number>16</number>
+ </property>
+ <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
+ <widget class="QLabel" name="labelPlayer6">
+ <property name="text">
+ <string>P6</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="Player6LEDs" native="true">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_12">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer6LED1"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer6LED2"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer6LED3"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkboxPlayer6LED4"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Player6Explain" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_41">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelPlayer6Explain">
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer6Emulated">
+ <item>
+ <property name="text">
+ <string>Pro Controller</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dual Joycons</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left Joycon</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right Joycon</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboPlayer6Profile">
+ <item>
+ <property name="text">
+ <string>Use Current Config</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="10" column="1">
+ <widget class="QWidget" name="widgetSpacer" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>25</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_22">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="controllerAppletVerticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>25</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QWidget" name="widgetSpacer6" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_15">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="controllerAppletHorizontalSpacer5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QWidget" name="widgetSpacer7" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>25</width>
+ <height>0</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_16">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="controllerAppletHorizontalSpacer4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>25</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QWidget" name="widgetSpacer9" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>25</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_17">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="controllerAppletVerticalSpacer2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>25</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="bottomControllerApplet" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <property name="spacing">
+ <number>15</number>
+ </property>
+ <property name="leftMargin">
+ <number>15</number>
+ </property>
+ <property name="topMargin">
+ <number>8</number>
+ </property>
+ <property name="rightMargin">
+ <number>15</number>
+ </property>
+ <property name="bottomMargin">
+ <number>15</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="handheldGroup">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Console Mode</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="radioDocked">
+ <property name="text">
+ <string>Docked</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="radioUndocked">
+ <property name="text">
+ <string>Undocked</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="vibrationGroup">
+ <property name="title">
+ <string>Vibration</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QSpinBox" name="vibrationSpin">
+ <property name="minimumSize">
+ <size>
+ <width>65</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>65</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>200</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="motionGroup">
+ <property name="title">
+ <string>Motion</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="motionButton">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="inputConfigGroup">
+ <property name="title">
+ <string>Input Config</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="inputConfigButton">
+ <property name="maximumSize">
+ <size>
+ <width>65</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Open</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="connectedControllers" native="true">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <property name="leftMargin">
+ <number>5</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item row="1" column="4">
+ <widget class="QCheckBox" name="checkboxPlayer4Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelControllers">
+ <property name="text">
+ <string>Controllers</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QCheckBox" name="checkboxPlayer2Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="labelConnectedPlayer1">
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QCheckBox" name="checkboxPlayer3Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="checkboxPlayer1Connected">
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="labelConnectedPlayer2">
+ <property name="text">
+ <string>2</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QLabel" name="labelConnectedPlayer4">
+ <property name="text">
+ <string>4</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="labelConnectedPlayer3">
+ <property name="text">
+ <string>3</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelConnected">
+ <property name="text">
+ <string>Connected</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="7">
+ <widget class="QCheckBox" name="checkboxPlayer7Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="5">
+ <widget class="QLabel" name="labelConnectedPlayer5">
+ <property name="text">
+ <string>5</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="6">
+ <widget class="QCheckBox" name="checkboxPlayer6Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="7">
+ <widget class="QLabel" name="labelConnectedPlayer7">
+ <property name="text">
+ <string>7</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="5">
+ <widget class="QCheckBox" name="checkboxPlayer5Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="6">
+ <widget class="QLabel" name="labelConnectedPlayer6">
+ <property name="text">
+ <string>6</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="8">
+ <widget class="QLabel" name="labelConnectedPlayer8">
+ <property name="text">
+ <string>8</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="8">
+ <widget class="QCheckBox" name="checkboxPlayer8Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="controllerAppletHorizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item alignment="Qt::AlignBottom">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>QtControllerSelectorDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 8fc322b30..408eac2b7 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -30,6 +30,7 @@
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/frontend/framebuffer_layout.h"
+#include "core/hle/kernel/process.h"
#include "core/settings.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
@@ -63,7 +64,8 @@ void EmuThread::run() {
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
system.Renderer().Rasterizer().LoadDiskResources(
- stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
+ system.CurrentProcess()->GetTitleID(), stop_run,
+ [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total);
});
@@ -216,15 +218,6 @@ public:
virtual ~RenderWidget() = default;
- /// Called on the UI thread when this Widget is ready to draw
- /// Dervied classes can override this to draw the latest frame.
- virtual void Present() {}
-
- void paintEvent(QPaintEvent* event) override {
- Present();
- update();
- }
-
QPaintEngine* paintEngine() const override {
return nullptr;
}
@@ -243,20 +236,8 @@ public:
context = std::move(context_);
}
- void Present() override {
- if (!isVisible()) {
- return;
- }
-
- context->MakeCurrent();
- if (Core::System::GetInstance().Renderer().TryPresent(100)) {
- context->SwapBuffers();
- glFinish();
- }
- }
-
private:
- std::unique_ptr<Core::Frontend::GraphicsContext> context{};
+ std::unique_ptr<Core::Frontend::GraphicsContext> context;
};
#ifdef HAS_VULKAN
@@ -304,8 +285,9 @@ static Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow*
return wsi;
}
-GRenderWindow::GRenderWindow(GMainWindow* parent_, EmuThread* emu_thread_)
- : QWidget(parent_), emu_thread(emu_thread_) {
+GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
+ std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_)
+ : QWidget(parent), emu_thread(emu_thread_), input_subsystem{std::move(input_subsystem_)} {
setWindowTitle(QStringLiteral("yuzu %1 | %2-%3")
.arg(QString::fromUtf8(Common::g_build_name),
QString::fromUtf8(Common::g_scm_branch),
@@ -314,15 +296,15 @@ GRenderWindow::GRenderWindow(GMainWindow* parent_, EmuThread* emu_thread_)
auto layout = new QHBoxLayout(this);
layout->setMargin(0);
setLayout(layout);
- InputCommon::Init();
+ input_subsystem->Initialize();
this->setMouseTracking(true);
- connect(this, &GRenderWindow::FirstFrameDisplayed, parent_, &GMainWindow::OnLoadComplete);
+ connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
}
GRenderWindow::~GRenderWindow() {
- InputCommon::Shutdown();
+ input_subsystem->Shutdown();
}
void GRenderWindow::PollEvents() {
@@ -391,11 +373,11 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
}
void GRenderWindow::keyPressEvent(QKeyEvent* event) {
- InputCommon::GetKeyboard()->PressKey(event->key());
+ input_subsystem->GetKeyboard()->PressKey(event->key());
}
void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
- InputCommon::GetKeyboard()->ReleaseKey(event->key());
+ input_subsystem->GetKeyboard()->ReleaseKey(event->key());
}
void GRenderWindow::mousePressEvent(QMouseEvent* event) {
@@ -409,7 +391,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
const auto [x, y] = ScaleTouch(pos);
this->TouchPressed(x, y);
} else if (event->button() == Qt::RightButton) {
- InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y());
+ input_subsystem->GetMotionEmu()->BeginTilt(pos.x(), pos.y());
}
QWidget::mousePressEvent(event);
}
@@ -423,7 +405,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
auto pos = event->pos();
const auto [x, y] = ScaleTouch(pos);
this->TouchMoved(x, y);
- InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y());
+ input_subsystem->GetMotionEmu()->Tilt(pos.x(), pos.y());
QWidget::mouseMoveEvent(event);
}
@@ -436,7 +418,7 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
if (event->button() == Qt::LeftButton) {
this->TouchReleased();
} else if (event->button() == Qt::RightButton) {
- InputCommon::GetMotionEmu()->EndTilt();
+ input_subsystem->GetMotionEmu()->EndTilt();
}
}
@@ -451,7 +433,7 @@ void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
int active_points = 0;
// average all active touch points
- for (const auto tp : event->touchPoints()) {
+ for (const auto& tp : event->touchPoints()) {
if (tp.state() & (Qt::TouchPointPressed | Qt::TouchPointMoved | Qt::TouchPointStationary)) {
active_points++;
pos += tp.pos();
@@ -485,7 +467,7 @@ bool GRenderWindow::event(QEvent* event) {
void GRenderWindow::focusOutEvent(QFocusEvent* event) {
QWidget::focusOutEvent(event);
- InputCommon::GetKeyboard()->ReleaseAllKeys();
+ input_subsystem->GetKeyboard()->ReleaseAllKeys();
}
void GRenderWindow::resizeEvent(QResizeEvent* event) {
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 6c59b4d5c..ca35cf831 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -6,6 +6,7 @@
#include <atomic>
#include <condition_variable>
+#include <memory>
#include <mutex>
#include <QImage>
@@ -23,6 +24,10 @@ class QKeyEvent;
class QTouchEvent;
class QStringList;
+namespace InputCommon {
+class InputSubsystem;
+}
+
namespace VideoCore {
enum class LoadCallbackStage;
}
@@ -121,7 +126,8 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
Q_OBJECT
public:
- GRenderWindow(GMainWindow* parent, EmuThread* emu_thread);
+ explicit GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
+ std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_);
~GRenderWindow() override;
// EmuWindow implementation.
@@ -183,6 +189,7 @@ private:
QStringList GetUnsupportedGLExtensions() const;
EmuThread* emu_thread;
+ std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
// Main context that will be shared with all other contexts that are requested.
// If this is used in a shared context setting, then this should not be used directly, but
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index a372190cc..d2913d613 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -6,7 +6,6 @@
#include <QKeySequence>
#include <QSettings>
#include "common/file_util.h"
-#include "configure_input_simple.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "input_common/main.h"
@@ -32,29 +31,36 @@ Config::~Config() {
}
const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
- Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_3, Qt::Key_4, Qt::Key_Q,
- Qt::Key_W, Qt::Key_1, Qt::Key_2, Qt::Key_N, Qt::Key_M, Qt::Key_F, Qt::Key_T,
- Qt::Key_H, Qt::Key_G, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, Qt::Key_Down, Qt::Key_J,
- Qt::Key_I, Qt::Key_L, Qt::Key_K, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V,
+ Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_3, Qt::Key_4, Qt::Key_Q,
+ Qt::Key_W, Qt::Key_1, Qt::Key_2, Qt::Key_N, Qt::Key_M, Qt::Key_F, Qt::Key_T,
+ Qt::Key_H, Qt::Key_G, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V,
};
-const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
+const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = {
+ Qt::Key_7,
+ Qt::Key_8,
+};
+
+const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
{
Qt::Key_Up,
Qt::Key_Down,
Qt::Key_Left,
Qt::Key_Right,
- Qt::Key_E,
},
{
Qt::Key_I,
Qt::Key_K,
Qt::Key_J,
Qt::Key_L,
- Qt::Key_R,
},
}};
+const std::array<int, 2> Config::default_stick_mod = {
+ Qt::Key_E,
+ Qt::Key_R,
+};
+
const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons =
{
Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal,
@@ -243,10 +249,10 @@ void Config::ReadPlayerValues() {
player.connected =
ReadSetting(QStringLiteral("player_%1_connected").arg(p), false).toBool();
- player.type = static_cast<Settings::ControllerType>(
+ player.controller_type = static_cast<Settings::ControllerType>(
qt_config
->value(QStringLiteral("player_%1_type").arg(p),
- static_cast<u8>(Settings::ControllerType::DualJoycon))
+ static_cast<u8>(Settings::ControllerType::ProController))
.toUInt());
player.body_color_left = qt_config
@@ -283,10 +289,26 @@ void Config::ReadPlayerValues() {
}
}
+ for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
+ const std::string default_param =
+ InputCommon::GenerateKeyboardParam(default_motions[i]);
+ auto& player_motions = player.motions[i];
+
+ player_motions = qt_config
+ ->value(QStringLiteral("player_%1_").arg(p) +
+ QString::fromUtf8(Settings::NativeMotion::mapping[i]),
+ QString::fromStdString(default_param))
+ .toString()
+ .toStdString();
+ if (player_motions.empty()) {
+ player_motions = default_param;
+ }
+ }
+
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
- default_analogs[i][3], default_analogs[i][4], 0.5f);
+ default_analogs[i][3], default_stick_mod[i], 0.5f);
auto& player_analogs = player.analogs[i];
player_analogs = qt_config
@@ -300,12 +322,6 @@ void Config::ReadPlayerValues() {
}
}
}
-
- std::stable_partition(
- Settings::values.players.begin(),
- Settings::values.players.begin() +
- Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
- [](const auto& player) { return player.connected; });
}
void Config::ReadDebugValues() {
@@ -330,7 +346,7 @@ void Config::ReadDebugValues() {
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
- default_analogs[i][3], default_analogs[i][4], 0.5f);
+ default_analogs[i][3], default_stick_mod[i], 0.5f);
auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i];
debug_pad_analogs = qt_config
@@ -397,13 +413,6 @@ void Config::ReadTouchscreenValues() {
ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt();
}
-void Config::ApplyDefaultProfileIfInputInvalid() {
- if (!std::any_of(Settings::values.players.begin(), Settings::values.players.end(),
- [](const Settings::PlayerInput& in) { return in.connected; })) {
- ApplyInputProfileConfiguration(UISettings::values.profile_index);
- }
-}
-
void Config::ReadAudioValues() {
qt_config->beginGroup(QStringLiteral("Audio"));
@@ -432,12 +441,65 @@ void Config::ReadControlValues() {
ReadKeyboardValues();
ReadMouseValues();
ReadTouchscreenValues();
+ ReadMotionTouchValues();
+
+ Settings::values.vibration_enabled =
+ ReadSetting(QStringLiteral("vibration_enabled"), true).toBool();
+ Settings::values.motion_enabled = ReadSetting(QStringLiteral("motion_enabled"), true).toBool();
+ Settings::values.use_docked_mode =
+ ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
+
+ qt_config->endGroup();
+}
+
+void Config::ReadMotionTouchValues() {
+ int num_touch_from_button_maps =
+ qt_config->beginReadArray(QStringLiteral("touch_from_button_maps"));
+
+ if (num_touch_from_button_maps > 0) {
+ const auto append_touch_from_button_map = [this] {
+ Settings::TouchFromButtonMap map;
+ map.name = ReadSetting(QStringLiteral("name"), QStringLiteral("default"))
+ .toString()
+ .toStdString();
+ const int num_touch_maps = qt_config->beginReadArray(QStringLiteral("entries"));
+ map.buttons.reserve(num_touch_maps);
+ for (int i = 0; i < num_touch_maps; i++) {
+ qt_config->setArrayIndex(i);
+ std::string touch_mapping =
+ ReadSetting(QStringLiteral("bind")).toString().toStdString();
+ map.buttons.emplace_back(std::move(touch_mapping));
+ }
+ qt_config->endArray(); // entries
+ Settings::values.touch_from_button_maps.emplace_back(std::move(map));
+ };
+
+ for (int i = 0; i < num_touch_from_button_maps; ++i) {
+ qt_config->setArrayIndex(i);
+ append_touch_from_button_map();
+ }
+ } else {
+ Settings::values.touch_from_button_maps.emplace_back(
+ Settings::TouchFromButtonMap{"default", {}});
+ num_touch_from_button_maps = 1;
+ }
+ qt_config->endArray();
Settings::values.motion_device =
ReadSetting(QStringLiteral("motion_device"),
QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"))
.toString()
.toStdString();
+ Settings::values.touch_device =
+ ReadSetting(QStringLiteral("touch_device"), QStringLiteral("engine:emu_window"))
+ .toString()
+ .toStdString();
+ Settings::values.use_touch_from_button =
+ ReadSetting(QStringLiteral("use_touch_from_button"), false).toBool();
+ Settings::values.touch_from_button_map_index =
+ ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt();
+ Settings::values.touch_from_button_map_index =
+ std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
Settings::values.udp_input_address =
ReadSetting(QStringLiteral("udp_input_address"),
QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR))
@@ -448,10 +510,6 @@ void Config::ReadControlValues() {
.toInt());
Settings::values.udp_pad_index =
static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt());
- Settings::values.use_docked_mode =
- ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
-
- qt_config->endGroup();
}
void Config::ReadCoreValues() {
@@ -501,7 +559,7 @@ void Config::ReadDataStorageValues() {
Settings::values.gamecard_current_game =
ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
Settings::values.gamecard_path =
- ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString();
+ ReadSetting(QStringLiteral("gamecard_path"), QString{}).toString().toStdString();
qt_config->endGroup();
}
@@ -515,7 +573,7 @@ void Config::ReadDebuggingValues() {
Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool();
Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt();
Settings::values.program_args =
- ReadSetting(QStringLiteral("program_args"), QStringLiteral("")).toString().toStdString();
+ ReadSetting(QStringLiteral("program_args"), QString{}).toString().toStdString();
Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool();
Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool();
Settings::values.reporting_services =
@@ -548,8 +606,7 @@ void Config::ReadDisabledAddOnValues() {
const auto d_size = qt_config->beginReadArray(QStringLiteral("disabled"));
for (int j = 0; j < d_size; ++j) {
qt_config->setArrayIndex(j);
- out.push_back(
- ReadSetting(QStringLiteral("d"), QStringLiteral("")).toString().toStdString());
+ out.push_back(ReadSetting(QStringLiteral("d"), QString{}).toString().toStdString());
}
qt_config->endArray();
Settings::values.disabled_addons.insert_or_assign(title_id, out);
@@ -635,6 +692,11 @@ void Config::ReadCpuValues() {
ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
Settings::values.cpuopt_reduce_misalign_checks =
ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
+
+ Settings::values.cpuopt_unsafe_unfuse_fma =
+ ReadSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"), true).toBool();
+ Settings::values.cpuopt_unsafe_reduce_fp_error =
+ ReadSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true).toBool();
}
qt_config->endGroup();
@@ -783,14 +845,11 @@ void Config::ReadUIValues() {
UISettings::values.first_start = ReadSetting(QStringLiteral("firstStart"), true).toBool();
UISettings::values.callout_flags = ReadSetting(QStringLiteral("calloutFlags"), 0).toUInt();
UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool();
- UISettings::values.profile_index = ReadSetting(QStringLiteral("profileIndex"), 0).toUInt();
UISettings::values.pause_when_in_background =
ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool();
UISettings::values.hide_mouse =
ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool();
- ApplyDefaultProfileIfInputInvalid();
-
qt_config->endGroup();
}
@@ -864,8 +923,9 @@ void Config::SavePlayerValues() {
const auto& player = Settings::values.players[p];
WriteSetting(QStringLiteral("player_%1_connected").arg(p), player.connected, false);
- WriteSetting(QStringLiteral("player_%1_type").arg(p), static_cast<u8>(player.type),
- static_cast<u8>(Settings::ControllerType::DualJoycon));
+ WriteSetting(QStringLiteral("player_%1_type").arg(p),
+ static_cast<u8>(player.controller_type),
+ static_cast<u8>(Settings::ControllerType::ProController));
WriteSetting(QStringLiteral("player_%1_body_color_left").arg(p), player.body_color_left,
Settings::JOYCON_BODY_NEON_BLUE);
@@ -884,10 +944,18 @@ void Config::SavePlayerValues() {
QString::fromStdString(player.buttons[i]),
QString::fromStdString(default_param));
}
+ for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
+ const std::string default_param =
+ InputCommon::GenerateKeyboardParam(default_motions[i]);
+ WriteSetting(QStringLiteral("player_%1_").arg(p) +
+ QString::fromStdString(Settings::NativeMotion::mapping[i]),
+ QString::fromStdString(player.motions[i]),
+ QString::fromStdString(default_param));
+ }
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
- default_analogs[i][3], default_analogs[i][4], 0.5f);
+ default_analogs[i][3], default_stick_mod[i], 0.5f);
WriteSetting(QStringLiteral("player_%1_").arg(p) +
QString::fromStdString(Settings::NativeAnalog::mapping[i]),
QString::fromStdString(player.analogs[i]),
@@ -908,7 +976,7 @@ void Config::SaveDebugValues() {
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
- default_analogs[i][3], default_analogs[i][4], 0.5f);
+ default_analogs[i][3], default_stick_mod[i], 0.5f);
WriteSetting(QStringLiteral("debug_pad_") +
QString::fromStdString(Settings::NativeAnalog::mapping[i]),
QString::fromStdString(Settings::values.debug_pad_analogs[i]),
@@ -942,6 +1010,43 @@ void Config::SaveTouchscreenValues() {
WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15);
}
+void Config::SaveMotionTouchValues() {
+ WriteSetting(QStringLiteral("motion_device"),
+ QString::fromStdString(Settings::values.motion_device),
+ QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
+ WriteSetting(QStringLiteral("touch_device"),
+ QString::fromStdString(Settings::values.touch_device),
+ QStringLiteral("engine:emu_window"));
+ WriteSetting(QStringLiteral("use_touch_from_button"), Settings::values.use_touch_from_button,
+ false);
+ WriteSetting(QStringLiteral("touch_from_button_map"),
+ Settings::values.touch_from_button_map_index, 0);
+ WriteSetting(QStringLiteral("udp_input_address"),
+ QString::fromStdString(Settings::values.udp_input_address),
+ QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR));
+ WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port,
+ InputCommon::CemuhookUDP::DEFAULT_PORT);
+ WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0);
+
+ qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
+ for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
+ qt_config->setArrayIndex(static_cast<int>(p));
+ WriteSetting(QStringLiteral("name"),
+ QString::fromStdString(Settings::values.touch_from_button_maps[p].name),
+ QStringLiteral("default"));
+ qt_config->beginWriteArray(QStringLiteral("entries"));
+ for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size();
+ ++q) {
+ qt_config->setArrayIndex(static_cast<int>(q));
+ WriteSetting(
+ QStringLiteral("bind"),
+ QString::fromStdString(Settings::values.touch_from_button_maps[p].buttons[q]));
+ }
+ qt_config->endArray();
+ }
+ qt_config->endArray();
+}
+
void Config::SaveValues() {
if (global) {
SaveControlValues();
@@ -984,17 +1089,17 @@ void Config::SaveControlValues() {
SaveDebugValues();
SaveMouseValues();
SaveTouchscreenValues();
+ SaveMotionTouchValues();
+ WriteSetting(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true);
+ WriteSetting(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true);
WriteSetting(QStringLiteral("motion_device"),
QString::fromStdString(Settings::values.motion_device),
QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
+ WriteSetting(QStringLiteral("touch_device"),
+ QString::fromStdString(Settings::values.touch_device),
+ QStringLiteral("engine:emu_window"));
WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
- WriteSetting(QStringLiteral("udp_input_address"),
- QString::fromStdString(Settings::values.udp_input_address),
- QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR));
- WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port,
- InputCommon::CemuhookUDP::DEFAULT_PORT);
- WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0);
WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
qt_config->endGroup();
@@ -1031,7 +1136,7 @@ void Config::SaveDataStorageValues() {
WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game,
false);
WriteSetting(QStringLiteral("gamecard_path"),
- QString::fromStdString(Settings::values.gamecard_path), QStringLiteral(""));
+ QString::fromStdString(Settings::values.gamecard_path), QString{});
qt_config->endGroup();
}
@@ -1044,7 +1149,7 @@ void Config::SaveDebuggingValues() {
WriteSetting(QStringLiteral("use_gdbstub"), Settings::values.use_gdbstub, false);
WriteSetting(QStringLiteral("gdbstub_port"), Settings::values.gdbstub_port, 24689);
WriteSetting(QStringLiteral("program_args"),
- QString::fromStdString(Settings::values.program_args), QStringLiteral(""));
+ QString::fromStdString(Settings::values.program_args), QString{});
WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
@@ -1071,8 +1176,7 @@ void Config::SaveDisabledAddOnValues() {
qt_config->beginWriteArray(QStringLiteral("disabled"));
for (std::size_t j = 0; j < elem.second.size(); ++j) {
qt_config->setArrayIndex(static_cast<int>(j));
- WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]),
- QStringLiteral(""));
+ WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), QString{});
}
qt_config->endArray();
++i;
@@ -1132,6 +1236,11 @@ void Config::SaveCpuValues() {
WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
Settings::values.cpuopt_reduce_misalign_checks, true);
+
+ WriteSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
+ Settings::values.cpuopt_unsafe_unfuse_fma, true);
+ WriteSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
+ Settings::values.cpuopt_unsafe_reduce_fp_error, true);
}
qt_config->endGroup();
@@ -1256,7 +1365,6 @@ void Config::SaveUIValues() {
WriteSetting(QStringLiteral("firstStart"), UISettings::values.first_start, true);
WriteSetting(QStringLiteral("calloutFlags"), UISettings::values.callout_flags, 0);
WriteSetting(QStringLiteral("showConsole"), UISettings::values.show_console, false);
- WriteSetting(QStringLiteral("profileIndex"), UISettings::values.profile_index, 0);
WriteSetting(QStringLiteral("pauseWhenInBackground"),
UISettings::values.pause_when_in_background, false);
WriteSetting(QStringLiteral("hideInactiveMouse"), UISettings::values.hide_mouse, false);
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index e5f39b040..5d8e45d78 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -23,7 +23,9 @@ public:
void Save();
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
- static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
+ static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
+ static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
+ static const std::array<int, 2> default_stick_mod;
static const std::array<int, Settings::NativeMouseButton::NumMouseButtons>
default_mouse_buttons;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
@@ -37,7 +39,7 @@ private:
void ReadKeyboardValues();
void ReadMouseValues();
void ReadTouchscreenValues();
- void ApplyDefaultProfileIfInputInvalid();
+ void ReadMotionTouchValues();
// Read functions bases off the respective config section names.
void ReadAudioValues();
@@ -64,6 +66,7 @@ private:
void SaveDebugValues();
void SaveMouseValues();
void SaveTouchscreenValues();
+ void SaveMotionTouchValues();
// Save functions based off the respective config section names.
void SaveAudioValues();
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index 5f5d8e571..fcf42cdcb 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>382</width>
+ <width>650</width>
<height>650</height>
</rect>
</property>
@@ -26,13 +26,13 @@
<widget class="QListWidget" name="selectorList">
<property name="minimumSize">
<size>
- <width>150</width>
+ <width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
- <width>150</width>
+ <width>120</width>
<height>16777215</height>
</size>
</property>
@@ -44,76 +44,121 @@
<number>0</number>
</property>
<widget class="ConfigureGeneral" name="generalTab">
+ <property name="accessibleName">
+ <string>General</string>
+ </property>
<attribute name="title">
<string>General</string>
</attribute>
</widget>
<widget class="ConfigureUi" name="uiTab">
+ <property name="accessibleName">
+ <string>UI</string>
+ </property>
<attribute name="title">
<string>Game List</string>
</attribute>
</widget>
<widget class="ConfigureSystem" name="systemTab">
+ <property name="accessibleName">
+ <string>System</string>
+ </property>
<attribute name="title">
<string>System</string>
</attribute>
</widget>
<widget class="ConfigureProfileManager" name="profileManagerTab">
+ <property name="accessibleName">
+ <string>Profiles</string>
+ </property>
<attribute name="title">
<string>Profiles</string>
</attribute>
</widget>
<widget class="ConfigureFilesystem" name="filesystemTab">
+ <property name="accessibleName">
+ <string>Filesystem</string>
+ </property>
<attribute name="title">
<string>Filesystem</string>
</attribute>
</widget>
- <widget class="ConfigureInputSimple" name="inputTab">
+ <widget class="ConfigureInput" name="inputTab">
+ <property name="accessibleName">
+ <string>Controls</string>
+ </property>
<attribute name="title">
- <string>Input</string>
+ <string>Controls</string>
</attribute>
</widget>
<widget class="ConfigureHotkeys" name="hotkeysTab">
+ <property name="accessibleName">
+ <string>Hotkeys</string>
+ </property>
<attribute name="title">
<string>Hotkeys</string>
</attribute>
</widget>
<widget class="ConfigureCpu" name="cpuTab">
+ <property name="accessibleName">
+ <string>CPU</string>
+ </property>
<attribute name="title">
<string>CPU</string>
</attribute>
</widget>
<widget class="ConfigureCpuDebug" name="cpuDebugTab">
+ <property name="accessibleName">
+ <string>Debug</string>
+ </property>
<attribute name="title">
<string>Debug</string>
</attribute>
</widget>
<widget class="ConfigureGraphics" name="graphicsTab">
+ <property name="accessibleName">
+ <string>Graphics</string>
+ </property>
<attribute name="title">
<string>Graphics</string>
</attribute>
</widget>
<widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab">
+ <property name="accessibleName">
+ <string>Advanced</string>
+ </property>
<attribute name="title">
<string>GraphicsAdvanced</string>
</attribute>
</widget>
<widget class="ConfigureAudio" name="audioTab">
+ <property name="accessibleName">
+ <string>Audio</string>
+ </property>
<attribute name="title">
<string>Audio</string>
</attribute>
</widget>
<widget class="ConfigureDebug" name="debugTab">
+ <property name="accessibleName">
+ <string>Debug</string>
+ </property>
<attribute name="title">
<string>Debug</string>
</attribute>
</widget>
<widget class="ConfigureWeb" name="webTab">
+ <property name="accessibleName">
+ <string>Web</string>
+ </property>
<attribute name="title">
<string>Web</string>
</attribute>
</widget>
<widget class="ConfigureService" name="serviceTab">
+ <property name="accessibleName">
+ <string>Services</string>
+ </property>
<attribute name="title">
<string>Services</string>
</attribute>
@@ -205,9 +250,9 @@
<container>1</container>
</customwidget>
<customwidget>
- <class>ConfigureInputSimple</class>
+ <class>ConfigureInput</class>
<extends>QWidget</extends>
- <header>configuration/configure_input_simple.h</header>
+ <header>configuration/configure_input.h</header>
<container>1</container>
</customwidget>
<customwidget>
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 7493e5ffb..37fcd6adc 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -19,6 +19,8 @@ ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::Config
connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
&ConfigureCpu::AccuracyUpdated);
+ connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this,
+ &ConfigureCpu::UpdateGroup);
}
ConfigureCpu::~ConfigureCpu() = default;
@@ -28,6 +30,12 @@ void ConfigureCpu::SetConfiguration() {
ui->accuracy->setEnabled(runtime_lock);
ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy));
+ UpdateGroup(static_cast<int>(Settings::values.cpu_accuracy));
+
+ ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock);
+ ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma);
+ ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock);
+ ui->cpuopt_unsafe_reduce_fp_error->setChecked(Settings::values.cpuopt_unsafe_reduce_fp_error);
}
void ConfigureCpu::AccuracyUpdated(int index) {
@@ -38,14 +46,21 @@ void ConfigureCpu::AccuracyUpdated(int index) {
QMessageBox::Yes | QMessageBox::No);
if (result == QMessageBox::No) {
ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate));
- return;
+ UpdateGroup(static_cast<int>(Settings::CPUAccuracy::Accurate));
}
}
}
+void ConfigureCpu::UpdateGroup(int index) {
+ ui->unsafe_group->setVisible(static_cast<Settings::CPUAccuracy>(index) ==
+ Settings::CPUAccuracy::Unsafe);
+}
+
void ConfigureCpu::ApplyConfiguration() {
Settings::values.cpu_accuracy =
static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex());
+ Settings::values.cpuopt_unsafe_unfuse_fma = ui->cpuopt_unsafe_unfuse_fma->isChecked();
+ Settings::values.cpuopt_unsafe_reduce_fp_error = ui->cpuopt_unsafe_reduce_fp_error->isChecked();
}
void ConfigureCpu::changeEvent(QEvent* event) {
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index e4741d3a4..3c5683d81 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -26,6 +26,7 @@ private:
void RetranslateUI();
void AccuracyUpdated(int index);
+ void UpdateGroup(int index);
void SetConfiguration();
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index bf6ea79bb..ebdd2e6e9 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -40,6 +40,11 @@
</item>
<item>
<property name="text">
+ <string>Unsafe</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
<string>Enable Debug Mode</string>
</property>
</item>
@@ -63,6 +68,53 @@
</layout>
</item>
<item>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QGroupBox" name="unsafe_group">
+ <property name="title">
+ <string>Unsafe CPU Optimization Settings</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QLabel">
+ <property name="wordWrap">
+ <bool>1</bool>
+ </property>
+ <property name="text">
+ <string>These settings reduce accuracy for speed.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma">
+ <property name="text">
+ <string>Unfuse FMA (improve performance on CPUs without FMA)</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
+ </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error">
+ <property name="text">
+ <string>Faster FRSQRTE and FRECPE</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
+ </string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/yuzu/configuration/configure_debug_controller.cpp b/src/yuzu/configuration/configure_debug_controller.cpp
new file mode 100644
index 000000000..0097c9a29
--- /dev/null
+++ b/src/yuzu/configuration/configure_debug_controller.cpp
@@ -0,0 +1,40 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "ui_configure_debug_controller.h"
+#include "yuzu/configuration/configure_debug_controller.h"
+
+ConfigureDebugController::ConfigureDebugController(QWidget* parent,
+ InputCommon::InputSubsystem* input_subsystem)
+ : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()),
+ debug_controller(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, true)) {
+ ui->setupUi(this);
+
+ ui->controllerLayout->addWidget(debug_controller);
+
+ connect(ui->clear_all_button, &QPushButton::clicked, this,
+ [this] { debug_controller->ClearAll(); });
+ connect(ui->restore_defaults_button, &QPushButton::clicked, this,
+ [this] { debug_controller->RestoreDefaults(); });
+
+ RetranslateUI();
+}
+
+ConfigureDebugController::~ConfigureDebugController() = default;
+
+void ConfigureDebugController::ApplyConfiguration() {
+ debug_controller->ApplyConfiguration();
+}
+
+void ConfigureDebugController::changeEvent(QEvent* event) {
+ if (event->type() == QEvent::LanguageChange) {
+ RetranslateUI();
+ }
+
+ QDialog::changeEvent(event);
+}
+
+void ConfigureDebugController::RetranslateUI() {
+ ui->retranslateUi(this);
+}
diff --git a/src/yuzu/configuration/configure_debug_controller.h b/src/yuzu/configuration/configure_debug_controller.h
new file mode 100644
index 000000000..34dcf705f
--- /dev/null
+++ b/src/yuzu/configuration/configure_debug_controller.h
@@ -0,0 +1,38 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QDialog>
+#include "yuzu/configuration/configure_input_player.h"
+
+class QPushButton;
+
+namespace InputCommon {
+class InputSubsystem;
+}
+
+namespace Ui {
+class ConfigureDebugController;
+}
+
+class ConfigureDebugController : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ConfigureDebugController(QWidget* parent,
+ InputCommon::InputSubsystem* input_subsystem);
+ ~ConfigureDebugController() override;
+
+ void ApplyConfiguration();
+
+private:
+ void changeEvent(QEvent* event) override;
+ void RetranslateUI();
+
+ std::unique_ptr<Ui::ConfigureDebugController> ui;
+
+ ConfigureInputPlayer* debug_controller;
+};
diff --git a/src/yuzu/configuration/configure_debug_controller.ui b/src/yuzu/configuration/configure_debug_controller.ui
new file mode 100644
index 000000000..a95ed50ff
--- /dev/null
+++ b/src/yuzu/configuration/configure_debug_controller.ui
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureDebugController</class>
+ <widget class="QDialog" name="ConfigureDebugController">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>780</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Debug Controller</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="controllerLayout"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="clear_all_button">
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="restore_defaults_button">
+ <property name="text">
+ <string>Defaults</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ConfigureDebugController</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>140</x>
+ <y>318</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>140</x>
+ <y>169</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ConfigureDebugController</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>140</x>
+ <y>318</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>140</x>
+ <y>169</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 4e30dc51e..8186929a6 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -12,7 +12,8 @@
#include "yuzu/configuration/configure_input_player.h"
#include "yuzu/hotkeys.h"
-ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
+ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
+ InputCommon::InputSubsystem* input_subsystem)
: QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) {
Settings::configuring_global = true;
@@ -20,6 +21,8 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
ui->hotkeysTab->Populate(registry);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ ui->inputTab->Initialize(input_subsystem);
+
SetConfiguration();
PopulateSelectionList();
@@ -80,12 +83,12 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
void ConfigureDialog::PopulateSelectionList() {
const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
- {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}},
+ {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}},
{tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
{tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}},
{tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
{tr("Audio"), {ui->audioTab}},
- {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}},
+ {tr("Controls"), ui->inputTab->GetSubTabs()}},
};
[[maybe_unused]] const QSignalBlocker blocker(ui->selectorList);
@@ -117,7 +120,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
{ui->generalTab, tr("General")},
{ui->systemTab, tr("System")},
{ui->profileManagerTab, tr("Profiles")},
- {ui->inputTab, tr("Input")},
+ {ui->inputTab, tr("Controls")},
{ui->hotkeysTab, tr("Hotkeys")},
{ui->cpuTab, tr("CPU")},
{ui->cpuDebugTab, tr("Debug")},
@@ -138,6 +141,6 @@ void ConfigureDialog::UpdateVisibleTabs() {
const QList<QWidget*> tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole));
for (const auto tab : tabs) {
- ui->tabWidget->addTab(tab, widgets.at(tab));
+ ui->tabWidget->addTab(tab, tab->accessibleName());
}
}
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 4289bc225..570c3b941 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -9,6 +9,10 @@
class HotkeyRegistry;
+namespace InputCommon {
+class InputSubsystem;
+}
+
namespace Ui {
class ConfigureDialog;
}
@@ -17,7 +21,8 @@ class ConfigureDialog : public QDialog {
Q_OBJECT
public:
- explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry);
+ explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
+ InputCommon::InputSubsystem* input_subsystem);
~ConfigureDialog() override;
void ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index f2977719c..2725fcb2b 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -8,18 +8,33 @@
#include <QSignalBlocker>
#include <QTimer>
-#include "configuration/configure_touchscreen_advanced.h"
#include "core/core.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
-#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/sm/sm.h"
#include "ui_configure_input.h"
+#include "ui_configure_input_advanced.h"
#include "ui_configure_input_player.h"
+#include "yuzu/configuration/configure_debug_controller.h"
#include "yuzu/configuration/configure_input.h"
+#include "yuzu/configuration/configure_input_advanced.h"
#include "yuzu/configuration/configure_input_player.h"
+#include "yuzu/configuration/configure_motion_touch.h"
#include "yuzu/configuration/configure_mouse_advanced.h"
+#include "yuzu/configuration/configure_touchscreen_advanced.h"
+
+namespace {
+template <typename Dialog, typename... Args>
+void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
+ Dialog dialog(&parent, std::forward<Args>(args)...);
+
+ const auto res = dialog.exec();
+ if (res == QDialog::Accepted) {
+ dialog.ApplyConfiguration();
+ }
+}
+} // Anonymous namespace
void OnDockedModeChanged(bool last_state, bool new_state) {
if (last_state == new_state) {
@@ -48,97 +63,120 @@ void OnDockedModeChanged(bool last_state, bool new_state) {
}
}
-namespace {
-template <typename Dialog, typename... Args>
-void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
- parent.ApplyConfiguration();
- Dialog dialog(&parent, std::forward<Args>(args)...);
-
- const auto res = dialog.exec();
- if (res == QDialog::Accepted) {
- dialog.ApplyConfiguration();
- }
-}
-} // Anonymous namespace
-
ConfigureInput::ConfigureInput(QWidget* parent)
- : QDialog(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
ui->setupUi(this);
+}
- players_controller = {
- ui->player1_combobox, ui->player2_combobox, ui->player3_combobox, ui->player4_combobox,
- ui->player5_combobox, ui->player6_combobox, ui->player7_combobox, ui->player8_combobox,
+ConfigureInput::~ConfigureInput() = default;
+
+void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
+ std::size_t max_players) {
+ player_controllers = {
+ new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem),
+ new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem),
+ new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem),
+ new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem),
+ new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem),
+ new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem),
+ new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem),
+ new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem),
};
- players_configure = {
- ui->player1_configure, ui->player2_configure, ui->player3_configure, ui->player4_configure,
- ui->player5_configure, ui->player6_configure, ui->player7_configure, ui->player8_configure,
+ player_tabs = {
+ ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4,
+ ui->tabPlayer5, ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8,
};
- RetranslateUI();
- LoadConfiguration();
- UpdateUIEnabled();
+ player_connected = {
+ ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected,
+ ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected,
+ ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
+ };
- connect(ui->restore_defaults_button, &QPushButton::clicked, this,
- &ConfigureInput::RestoreDefaults);
+ std::array<QLabel*, 8> player_connected_labels = {
+ ui->label, ui->label_3, ui->label_4, ui->label_5,
+ ui->label_6, ui->label_7, ui->label_8, ui->label_9,
+ };
- for (auto* enabled : players_controller) {
- connect(enabled, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
- &ConfigureInput::UpdateUIEnabled);
- }
- connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
- connect(ui->handheld_connected, &QCheckBox::stateChanged, this,
- &ConfigureInput::UpdateUIEnabled);
- connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
- connect(ui->keyboard_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
- connect(ui->debug_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
- connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this,
- &ConfigureInput::UpdateUIEnabled);
-
- for (std::size_t i = 0; i < players_configure.size(); ++i) {
- connect(players_configure[i], &QPushButton::clicked, this,
- [this, i] { CallConfigureDialog<ConfigureInputPlayer>(*this, i, false); });
+ for (std::size_t i = 0; i < player_tabs.size(); ++i) {
+ player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
+ player_tabs[i]->layout()->addWidget(player_controllers[i]);
+ connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) {
+ if (is_connected) {
+ for (std::size_t index = 0; index <= i; ++index) {
+ player_connected[index]->setChecked(is_connected);
+ }
+ } else {
+ for (std::size_t index = i; index < player_tabs.size(); ++index) {
+ player_connected[index]->setChecked(is_connected);
+ }
+ }
+ });
+ connect(player_controllers[i], &ConfigureInputPlayer::RefreshInputDevices,
+ [this] { UpdateAllInputDevices(); });
+ connect(player_connected[i], &QCheckBox::stateChanged, [this, i](int state) {
+ player_controllers[i]->ConnectPlayer(state == Qt::Checked);
+ });
+
+ // Remove/hide all the elements that exceed max_players, if applicable.
+ if (i >= max_players) {
+ ui->tabWidget->removeTab(static_cast<int>(max_players));
+ player_connected[i]->hide();
+ player_connected_labels[i]->hide();
+ }
}
+ // Only the first player can choose handheld mode so connect the signal just to player 1
+ connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged,
+ [this](bool is_handheld) { UpdateDockedState(is_handheld); });
+
+ advanced = new ConfigureInputAdvanced(this);
+ ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
+ ui->tabAdvanced->layout()->addWidget(advanced);
+ connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] {
+ CallConfigureDialog<ConfigureDebugController>(*this, input_subsystem);
+ });
+ connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] {
+ CallConfigureDialog<ConfigureMouseAdvanced>(*this, input_subsystem);
+ });
+ connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog,
+ [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
+ connect(advanced, &ConfigureInputAdvanced::CallMotionTouchConfigDialog,
+ [this, input_subsystem] {
+ CallConfigureDialog<ConfigureMotionTouch>(*this, input_subsystem);
+ });
- connect(ui->handheld_configure, &QPushButton::clicked, this,
- [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 8, false); });
-
- connect(ui->debug_configure, &QPushButton::clicked, this,
- [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 9, true); });
+ connect(ui->motionButton, &QPushButton::clicked, [this, input_subsystem] {
+ CallConfigureDialog<ConfigureMotionTouch>(*this, input_subsystem);
+ });
- connect(ui->mouse_advanced, &QPushButton::clicked, this,
- [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); });
+ connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
+ connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); });
- connect(ui->touchscreen_advanced, &QPushButton::clicked, this,
- [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
+ RetranslateUI();
+ LoadConfiguration();
}
-ConfigureInput::~ConfigureInput() = default;
+QList<QWidget*> ConfigureInput::GetSubTabs() const {
+ return {
+ ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, ui->tabPlayer5,
+ ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8, ui->tabAdvanced,
+ };
+}
void ConfigureInput::ApplyConfiguration() {
- for (std::size_t i = 0; i < players_controller.size(); ++i) {
- const auto controller_type_index = players_controller[i]->currentIndex();
-
- Settings::values.players[i].connected = controller_type_index != 0;
-
- if (controller_type_index > 0) {
- Settings::values.players[i].type =
- static_cast<Settings::ControllerType>(controller_type_index - 1);
- } else {
- Settings::values.players[i].type = Settings::ControllerType::DualJoycon;
- }
+ for (auto controller : player_controllers) {
+ controller->ApplyConfiguration();
}
+ advanced->ApplyConfiguration();
+
const bool pre_docked_mode = Settings::values.use_docked_mode;
- Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
+ Settings::values.use_docked_mode = ui->radioDocked->isChecked();
OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
- Settings::values
- .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
- .connected = ui->handheld_connected->isChecked();
- Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
- Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
- Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
- Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
+
+ Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
+ Settings::values.motion_enabled = ui->motionGroup->isChecked();
}
void ConfigureInput::changeEvent(QEvent* event) {
@@ -146,94 +184,64 @@ void ConfigureInput::changeEvent(QEvent* event) {
RetranslateUI();
}
- QDialog::changeEvent(event);
+ QWidget::changeEvent(event);
}
void ConfigureInput::RetranslateUI() {
ui->retranslateUi(this);
- RetranslateControllerComboBoxes();
}
-void ConfigureInput::RetranslateControllerComboBoxes() {
- for (auto* controller_box : players_controller) {
- [[maybe_unused]] const QSignalBlocker blocker(controller_box);
-
- controller_box->clear();
- controller_box->addItems({tr("None"), tr("Pro Controller"), tr("Dual Joycons"),
- tr("Single Right Joycon"), tr("Single Left Joycon")});
- }
-
+void ConfigureInput::LoadConfiguration() {
LoadPlayerControllerIndices();
-}
+ UpdateDockedState(Settings::values.players[8].connected);
-void ConfigureInput::UpdateUIEnabled() {
- bool hit_disabled = false;
- for (auto* player : players_controller) {
- player->setDisabled(hit_disabled);
- if (hit_disabled) {
- player->setCurrentIndex(0);
- }
- if (!hit_disabled && player->currentIndex() == 0) {
- hit_disabled = true;
- }
- }
+ ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
+ ui->motionGroup->setChecked(Settings::values.motion_enabled);
+}
- for (std::size_t i = 0; i < players_controller.size(); ++i) {
- players_configure[i]->setEnabled(players_controller[i]->currentIndex() != 0);
+void ConfigureInput::LoadPlayerControllerIndices() {
+ for (std::size_t i = 0; i < player_connected.size(); ++i) {
+ const auto connected = Settings::values.players[i].connected ||
+ (i == 0 && Settings::values.players[8].connected);
+ player_connected[i]->setChecked(connected);
}
+}
- ui->handheld_connected->setChecked(ui->handheld_connected->isChecked() &&
- !ui->use_docked_mode->isChecked());
- ui->handheld_connected->setEnabled(!ui->use_docked_mode->isChecked());
- ui->handheld_configure->setEnabled(ui->handheld_connected->isChecked() &&
- !ui->use_docked_mode->isChecked());
- ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
- ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
- ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
+void ConfigureInput::ClearAll() {
+ // We don't have a good way to know what tab is active, but we can find out by getting the
+ // parent of the consoleInputSettings
+ auto* player_tab = static_cast<ConfigureInputPlayer*>(ui->consoleInputSettings->parent());
+ player_tab->ClearAll();
}
-void ConfigureInput::LoadConfiguration() {
- std::stable_partition(
- Settings::values.players.begin(),
- Settings::values.players.begin() +
- Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
- [](const auto& player) { return player.connected; });
+void ConfigureInput::RestoreDefaults() {
+ // We don't have a good way to know what tab is active, but we can find out by getting the
+ // parent of the consoleInputSettings
+ auto* player_tab = static_cast<ConfigureInputPlayer*>(ui->consoleInputSettings->parent());
+ player_tab->RestoreDefaults();
+
+ ui->radioDocked->setChecked(true);
+ ui->radioUndocked->setChecked(false);
+ ui->vibrationGroup->setChecked(true);
+ ui->motionGroup->setChecked(true);
+}
- LoadPlayerControllerIndices();
+void ConfigureInput::UpdateDockedState(bool is_handheld) {
+ // Disallow changing the console mode if the controller type is handheld.
+ ui->radioDocked->setEnabled(!is_handheld);
+ ui->radioUndocked->setEnabled(!is_handheld);
- ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
- ui->handheld_connected->setChecked(
- Settings::values
- .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
- .connected);
- ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
- ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
- ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
- ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
-
- UpdateUIEnabled();
-}
+ ui->radioDocked->setChecked(Settings::values.use_docked_mode);
+ ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
-void ConfigureInput::LoadPlayerControllerIndices() {
- for (std::size_t i = 0; i < players_controller.size(); ++i) {
- const auto connected = Settings::values.players[i].connected;
- players_controller[i]->setCurrentIndex(
- connected ? static_cast<u8>(Settings::values.players[i].type) + 1 : 0);
+ // Also force into undocked mode if the controller type is handheld.
+ if (is_handheld) {
+ ui->radioUndocked->setChecked(true);
}
}
-void ConfigureInput::RestoreDefaults() {
- players_controller[0]->setCurrentIndex(2);
-
- for (std::size_t i = 1; i < players_controller.size(); ++i) {
- players_controller[i]->setCurrentIndex(0);
+void ConfigureInput::UpdateAllInputDevices() {
+ for (const auto& player : player_controllers) {
+ player->UpdateInputDevices();
}
-
- ui->use_docked_mode->setCheckState(Qt::Unchecked);
- ui->handheld_connected->setCheckState(Qt::Unchecked);
- ui->mouse_enabled->setCheckState(Qt::Unchecked);
- ui->keyboard_enabled->setCheckState(Qt::Unchecked);
- ui->debug_enabled->setCheckState(Qt::Unchecked);
- ui->touchscreen_enabled->setCheckState(Qt::Checked);
- UpdateUIEnabled();
}
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index 2f70cb3ca..0e8b2fd4e 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -7,37 +7,50 @@
#include <array>
#include <memory>
-#include <QDialog>
#include <QKeyEvent>
+#include <QWidget>
+
+#include "yuzu/configuration/configure_input_advanced.h"
+#include "yuzu/configuration/configure_input_player.h"
#include "ui_configure_input.h"
-class QPushButton;
+class QCheckBox;
class QString;
class QTimer;
+namespace InputCommon {
+class InputSubsystem;
+}
+
namespace Ui {
class ConfigureInput;
}
void OnDockedModeChanged(bool last_state, bool new_state);
-class ConfigureInput : public QDialog {
+class ConfigureInput : public QWidget {
Q_OBJECT
public:
explicit ConfigureInput(QWidget* parent = nullptr);
~ConfigureInput() override;
- /// Save all button configurations to settings file
+ /// Initializes the input dialog with the given input subsystem.
+ void Initialize(InputCommon::InputSubsystem* input_subsystem_, std::size_t max_players = 8);
+
+ /// Save all button configurations to settings file.
void ApplyConfiguration();
+ QList<QWidget*> GetSubTabs() const;
+
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
- void RetranslateControllerComboBoxes();
+ void ClearAll();
- void UpdateUIEnabled();
+ void UpdateDockedState(bool is_handheld);
+ void UpdateAllInputDevices();
/// Load configuration settings.
void LoadConfiguration();
@@ -48,6 +61,8 @@ private:
std::unique_ptr<Ui::ConfigureInput> ui;
- std::array<QComboBox*, 8> players_controller;
- std::array<QPushButton*, 8> players_configure;
+ std::array<ConfigureInputPlayer*, 8> player_controllers;
+ std::array<QWidget*, 8> player_tabs;
+ std::array<QCheckBox*, 8> player_connected;
+ ConfigureInputAdvanced* advanced;
};
diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index efffd8487..136955224 100644
--- a/src/yuzu/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
@@ -1,529 +1,554 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureInput</class>
- <widget class="QDialog" name="ConfigureInput">
+ <widget class="QWidget" name="ConfigureInput">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
- <width>384</width>
- <height>576</height>
+ <width>700</width>
+ <height>540</height>
</rect>
</property>
<property name="windowTitle">
- <string>Custom Input Settings</string>
+ <string>ConfigureInput</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
<item>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="gridGroupBox_1">
- <property name="title">
- <string>Players</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="1" column="2">
- <widget class="QComboBox" name="player1_combobox">
- <property name="minimumSize">
- <size>
- <width>110</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- </item>
- <item row="1" column="3">
- <widget class="QPushButton" name="player1_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Controller Type</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QComboBox" name="player2_combobox">
- <property name="minimumSize">
- <size>
- <width>110</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- </item>
- <item row="3" column="2">
- <widget class="QComboBox" name="player3_combobox">
- <property name="minimumSize">
- <size>
- <width>110</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- </item>
- <item row="4" column="2">
- <widget class="QComboBox" name="player4_combobox">
- <property name="minimumSize">
- <size>
- <width>110</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- </item>
- <item row="5" column="2">
- <widget class="QComboBox" name="player5_combobox">
- <property name="minimumSize">
- <size>
- <width>110</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- </item>
- <item row="6" column="2">
- <widget class="QComboBox" name="player6_combobox">
- <property name="minimumSize">
- <size>
- <width>110</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- </item>
- <item row="7" column="2">
- <widget class="QComboBox" name="player7_combobox">
- <property name="minimumSize">
- <size>
- <width>110</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- </item>
- <item row="8" column="2">
- <widget class="QComboBox" name="player8_combobox">
- <property name="minimumSize">
- <size>
- <width>110</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- </item>
- <item row="2" column="3">
- <widget class="QPushButton" name="player2_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="3" column="3">
- <widget class="QPushButton" name="player3_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="4" column="3">
- <widget class="QPushButton" name="player4_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="5" column="3">
- <widget class="QPushButton" name="player5_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="6" column="3">
- <widget class="QPushButton" name="player6_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="7" column="3">
- <widget class="QPushButton" name="player7_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="8" column="3">
- <widget class="QPushButton" name="player8_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="4">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="label_3">
- <property name="minimumSize">
- <size>
- <width>55</width>
- <height>0</height>
- </size>
- </property>
- <property name="text">
- <string>Player 1</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>Player 2</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>Player 3</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QLabel" name="label_6">
- <property name="text">
- <string>Player 4</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>Player 5</string>
- </property>
- </widget>
- </item>
- <item row="6" column="1">
- <widget class="QLabel" name="label_8">
- <property name="text">
- <string>Player 6</string>
- </property>
- </widget>
- </item>
- <item row="7" column="1">
- <widget class="QLabel" name="label_9">
- <property name="text">
- <string>Player 7</string>
- </property>
- </widget>
- </item>
- <item row="8" column="1">
- <widget class="QLabel" name="label_10">
- <property name="text">
- <string>Player 8</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="gridGroupBox_2">
- <property name="title">
- <string>Handheld</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="1" column="2">
- <spacer name="horizontalSpacer_5">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>72</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="4">
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="3">
- <widget class="QPushButton" name="handheld_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="1">
- <widget class="QCheckBox" name="handheld_connected">
- <property name="text">
- <string>Joycons Docked</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QCheckBox" name="use_docked_mode">
- <property name="text">
- <string>Use Docked Mode</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="gridGroupBox_3">
- <property name="title">
- <string>Other</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="1" column="1">
- <widget class="QCheckBox" name="keyboard_enabled">
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>23</height>
- </size>
- </property>
- <property name="text">
- <string>Keyboard</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QCheckBox" name="debug_enabled">
- <property name="text">
- <string>Debug Controller</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QCheckBox" name="touchscreen_enabled">
- <property name="text">
- <string>Touchscreen</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QCheckBox" name="mouse_enabled">
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>23</height>
- </size>
- </property>
- <property name="text">
- <string>Mouse</string>
- </property>
- </widget>
- </item>
- <item row="0" column="4">
- <spacer name="horizontalSpacer_7">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="2">
- <spacer name="horizontalSpacer_8">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>76</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="0">
- <spacer name="horizontalSpacer_6">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="3" column="3">
- <widget class="QPushButton" name="touchscreen_advanced">
- <property name="text">
- <string>Advanced</string>
- </property>
- </widget>
- </item>
- <item row="2" column="3">
- <widget class="QPushButton" name="debug_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QPushButton" name="mouse_advanced">
- <property name="text">
- <string>Advanced</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QPushButton" name="restore_defaults_button">
- <property name="text">
- <string>Restore Defaults</string>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tabPlayer1">
+ <property name="accessibleName">
+ <string>Player 1</string>
+ </property>
+ <attribute name="title">
+ <string>Player 1</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tabPlayer2">
+ <property name="accessibleName">
+ <string>Player 2</string>
+ </property>
+ <attribute name="title">
+ <string>Player 2</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tabPlayer3">
+ <property name="accessibleName">
+ <string>Player 3</string>
+ </property>
+ <attribute name="title">
+ <string>Player 3</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tabPlayer4">
+ <property name="accessibleName">
+ <string>Player 4</string>
+ </property>
+ <attribute name="title">
+ <string>Player 4</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tabPlayer5">
+ <property name="accessibleName">
+ <string>Player 5</string>
+ </property>
+ <attribute name="title">
+ <string>Player 5</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tabPlayer6">
+ <property name="accessibleName">
+ <string>Player 6</string>
+ </property>
+ <attribute name="title">
+ <string>Player 6</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tabPlayer7">
+ <property name="accessibleName">
+ <string>Player 7</string>
+ </property>
+ <attribute name="title">
+ <string>Player 7</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tabPlayer8">
+ <property name="accessibleName">
+ <string>Player 8</string>
+ </property>
+ <attribute name="title">
+ <string>Player 8</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tabAdvanced">
+ <property name="accessibleName">
+ <string>Advanced</string>
+ </property>
+ <attribute name="title">
+ <string>Advanced</string>
+ </attribute>
+ </widget>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignVCenter">
+ <widget class="QWidget" name="consoleInputSettings" native="true">
+ <layout class="QHBoxLayout" name="buttonsBottomRightHorizontalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignVCenter">
+ <widget class="QGroupBox" name="handheldGroup">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Console Mode</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="radioDocked">
+ <property name="text">
+ <string>Docked</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="radioUndocked">
+ <property name="text">
+ <string>Undocked</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="vibrationGroup">
+ <property name="title">
+ <string>Vibration</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QSpinBox" name="vibrationSpin">
+ <property name="minimumSize">
+ <size>
+ <width>65</width>
+ <height>21</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>65</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>200</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="motionGroup">
+ <property name="title">
+ <string>Motion</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="motionButton">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignVCenter">
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <property name="leftMargin">
+ <number>5</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_9">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <property name="rightMargin">
+ <number>0</number>
</property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
+ <property name="bottomMargin">
+ <number>0</number>
</property>
- </spacer>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ <property name="spacing">
+ <number>3</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
+ <item row="1" column="2">
+ <widget class="QCheckBox" name="checkboxPlayer2Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Controllers</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QCheckBox" name="checkboxPlayer4Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QCheckBox" name="checkboxPlayer3Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="5">
+ <widget class="QCheckBox" name="checkboxPlayer5Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="7">
+ <widget class="QCheckBox" name="checkboxPlayer7Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="6">
+ <widget class="QCheckBox" name="checkboxPlayer6Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="checkboxPlayer1Connected">
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="8">
+ <widget class="QCheckBox" name="checkboxPlayer8Connected">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>2</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>3</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>4</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="5">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>5</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="6">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>6</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="7">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>7</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="8">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>8</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>Connected</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item alignment="Qt::AlignBottom">
+ <widget class="QPushButton" name="buttonRestoreDefaults">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Defaults</string>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignBottom">
+ <widget class="QPushButton" name="buttonClearAll">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</item>
</layout>
</widget>
<resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>ConfigureInput</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>294</x>
- <y>553</y>
- </hint>
- <hint type="destinationlabel">
- <x>191</x>
- <y>287</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>ConfigureInput</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>294</x>
- <y>553</y>
- </hint>
- <hint type="destinationlabel">
- <x>191</x>
- <y>287</y>
- </hint>
- </hints>
- </connection>
- </connections>
+ <connections/>
</ui>
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
new file mode 100644
index 000000000..81f9dc16c
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -0,0 +1,171 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QColorDialog>
+#include "core/core.h"
+#include "core/settings.h"
+#include "ui_configure_input_advanced.h"
+#include "yuzu/configuration/configure_input_advanced.h"
+
+ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputAdvanced>()) {
+ ui->setupUi(this);
+
+ controllers_color_buttons = {{
+ {
+ ui->player1_left_body_button,
+ ui->player1_left_buttons_button,
+ ui->player1_right_body_button,
+ ui->player1_right_buttons_button,
+ },
+ {
+ ui->player2_left_body_button,
+ ui->player2_left_buttons_button,
+ ui->player2_right_body_button,
+ ui->player2_right_buttons_button,
+ },
+ {
+ ui->player3_left_body_button,
+ ui->player3_left_buttons_button,
+ ui->player3_right_body_button,
+ ui->player3_right_buttons_button,
+ },
+ {
+ ui->player4_left_body_button,
+ ui->player4_left_buttons_button,
+ ui->player4_right_body_button,
+ ui->player4_right_buttons_button,
+ },
+ {
+ ui->player5_left_body_button,
+ ui->player5_left_buttons_button,
+ ui->player5_right_body_button,
+ ui->player5_right_buttons_button,
+ },
+ {
+ ui->player6_left_body_button,
+ ui->player6_left_buttons_button,
+ ui->player6_right_body_button,
+ ui->player6_right_buttons_button,
+ },
+ {
+ ui->player7_left_body_button,
+ ui->player7_left_buttons_button,
+ ui->player7_right_body_button,
+ ui->player7_right_buttons_button,
+ },
+ {
+ ui->player8_left_body_button,
+ ui->player8_left_buttons_button,
+ ui->player8_right_body_button,
+ ui->player8_right_buttons_button,
+ },
+ }};
+
+ for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
+ auto& color_buttons = controllers_color_buttons[player_idx];
+ for (std::size_t button_idx = 0; button_idx < color_buttons.size(); ++button_idx) {
+ connect(color_buttons[button_idx], &QPushButton::clicked, this,
+ [this, player_idx, button_idx] {
+ OnControllerButtonClick(static_cast<int>(player_idx),
+ static_cast<int>(button_idx));
+ });
+ }
+ }
+
+ connect(ui->mouse_enabled, &QCheckBox::stateChanged, this,
+ &ConfigureInputAdvanced::UpdateUIEnabled);
+ connect(ui->debug_enabled, &QCheckBox::stateChanged, this,
+ &ConfigureInputAdvanced::UpdateUIEnabled);
+ connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this,
+ &ConfigureInputAdvanced::UpdateUIEnabled);
+
+ connect(ui->debug_configure, &QPushButton::clicked, this,
+ [this] { CallDebugControllerDialog(); });
+ connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); });
+ connect(ui->touchscreen_advanced, &QPushButton::clicked, this,
+ [this] { CallTouchscreenConfigDialog(); });
+ connect(ui->buttonMotionTouch, &QPushButton::clicked, this,
+ &ConfigureInputAdvanced::CallMotionTouchConfigDialog);
+
+ LoadConfiguration();
+}
+
+ConfigureInputAdvanced::~ConfigureInputAdvanced() = default;
+
+void ConfigureInputAdvanced::OnControllerButtonClick(int player_idx, int button_idx) {
+ const QColor new_bg_color = QColorDialog::getColor(controllers_colors[player_idx][button_idx]);
+ if (!new_bg_color.isValid()) {
+ return;
+ }
+ controllers_colors[player_idx][button_idx] = new_bg_color;
+ controllers_color_buttons[player_idx][button_idx]->setStyleSheet(
+ QStringLiteral("background-color: %1; min-width: 55px;")
+ .arg(controllers_colors[player_idx][button_idx].name()));
+}
+
+void ConfigureInputAdvanced::ApplyConfiguration() {
+ for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
+ auto& player = Settings::values.players[player_idx];
+ std::array<u32, 4> colors{};
+ std::transform(controllers_colors[player_idx].begin(), controllers_colors[player_idx].end(),
+ colors.begin(), [](QColor color) { return color.rgb(); });
+
+ player.body_color_left = colors[0];
+ player.button_color_left = colors[1];
+ player.body_color_right = colors[2];
+ player.button_color_right = colors[3];
+ }
+
+ Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
+ Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
+ Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
+ Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
+}
+
+void ConfigureInputAdvanced::LoadConfiguration() {
+ for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
+ auto& player = Settings::values.players[player_idx];
+ std::array<u32, 4> colors = {
+ player.body_color_left,
+ player.button_color_left,
+ player.body_color_right,
+ player.button_color_right,
+ };
+
+ std::transform(colors.begin(), colors.end(), controllers_colors[player_idx].begin(),
+ [](u32 rgb) { return QColor::fromRgb(rgb); });
+
+ for (std::size_t button_idx = 0; button_idx < colors.size(); ++button_idx) {
+ controllers_color_buttons[player_idx][button_idx]->setStyleSheet(
+ QStringLiteral("background-color: %1; min-width: 55px;")
+ .arg(controllers_colors[player_idx][button_idx].name()));
+ }
+ }
+
+ ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
+ ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
+ ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
+ ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
+
+ UpdateUIEnabled();
+}
+
+void ConfigureInputAdvanced::changeEvent(QEvent* event) {
+ if (event->type() == QEvent::LanguageChange) {
+ RetranslateUI();
+ }
+
+ QWidget::changeEvent(event);
+}
+
+void ConfigureInputAdvanced::RetranslateUI() {
+ ui->retranslateUi(this);
+}
+
+void ConfigureInputAdvanced::UpdateUIEnabled() {
+ ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
+ ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
+ ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
+}
diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h
new file mode 100644
index 000000000..50bb87768
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_advanced.h
@@ -0,0 +1,46 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <QWidget>
+
+class QColor;
+class QPushButton;
+
+namespace Ui {
+class ConfigureInputAdvanced;
+}
+
+class ConfigureInputAdvanced : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit ConfigureInputAdvanced(QWidget* parent = nullptr);
+ ~ConfigureInputAdvanced() override;
+
+ void ApplyConfiguration();
+
+signals:
+ void CallDebugControllerDialog();
+ void CallMouseConfigDialog();
+ void CallTouchscreenConfigDialog();
+ void CallMotionTouchConfigDialog();
+
+private:
+ void changeEvent(QEvent* event) override;
+ void RetranslateUI();
+ void UpdateUIEnabled();
+
+ void OnControllerButtonClick(int player_idx, int button_idx);
+
+ void LoadConfiguration();
+
+ std::unique_ptr<Ui::ConfigureInputAdvanced> ui;
+
+ std::array<std::array<QColor, 4>, 8> controllers_colors;
+ std::array<std::array<QPushButton*, 4>, 8> controllers_color_buttons;
+};
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui
new file mode 100644
index 000000000..5958435fc
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_advanced.ui
@@ -0,0 +1,2688 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureInputAdvanced</class>
+ <widget class="QWidget" name="ConfigureInputAdvanced">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>710</width>
+ <height>580</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Input</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="mainInputAdvanced" native="true">
+ <layout class="QHBoxLayout" name="main" stretch="1,1">
+ <property name="spacing">
+ <number>9</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="leftInputAdvanced" native="true">
+ <layout class="QVBoxLayout" name="leftLayout" stretch="0">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="joyconColorsGroup">
+ <property name="title">
+ <string>Joycon Colors</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3" stretch="1,1">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="topLeftInputAdvanced" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player12Widget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="player1Group">
+ <property name="title">
+ <string>Player 1</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player1LeftJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_14">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player1LeftBodyGroup">
+ <property name="title">
+ <string>L Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_66">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player1_left_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player1LeftButtonsGroup">
+ <property name="title">
+ <string>L Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_67">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player1_left_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player1RightJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_14">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player1RightBodyGroup">
+ <property name="title">
+ <string>R Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_64">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player1_right_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player1RightButtonsGroup">
+ <property name="title">
+ <string>R Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_65">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player1_right_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="player2Group">
+ <property name="title">
+ <string>Player 2</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_14">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player2LeftJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_15">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player2LeftBodyGroup">
+ <property name="title">
+ <string>L Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_70">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player2_left_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player2LeftButtonsGroup">
+ <property name="title">
+ <string>L Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_71">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player2_left_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player2RightJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_15">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player2RightBodyGroup">
+ <property name="title">
+ <string>R Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_68">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player2_right_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player2RightButtonsGroup">
+ <property name="title">
+ <string>R Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_69">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player2_right_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player34Widget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="player3Group">
+ <property name="title">
+ <string>Player 3</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_15">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player3LeftJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_16">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player3LeftBodyGroup">
+ <property name="title">
+ <string>L Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_74">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player3_left_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player3LeftButtonsGroup">
+ <property name="title">
+ <string>L Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_75">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player3_left_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player3RightJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_16">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player3RightBodyGroup">
+ <property name="title">
+ <string>R Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_72">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player3_right_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player3RightButtonsGroup">
+ <property name="title">
+ <string>R Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_73">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player3_right_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="player4Group">
+ <property name="title">
+ <string>Player 4</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_16">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player4LeftJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_17">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player4LeftBodyGroup">
+ <property name="title">
+ <string>L Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_78">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player4_left_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player4LeftButtonsGroup">
+ <property name="title">
+ <string>L Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_79">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player4_left_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player4RightJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_17">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player4RightBodyGroup">
+ <property name="title">
+ <string>R Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_76">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player4_right_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player4RightButtonsGroup">
+ <property name="title">
+ <string>R Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_77">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player4_right_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="bottomLeftInputAdvanced" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player56Widget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="player5Group">
+ <property name="title">
+ <string>Player 5</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_10">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player5LeftJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_10">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player5LeftBodyGroup">
+ <property name="title">
+ <string>L Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_50">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player5_left_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player5LeftButtonsGroup">
+ <property name="title">
+ <string>L Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_51">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player5_left_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player5RightJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_10">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player5RightBodyGroup">
+ <property name="title">
+ <string>R Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_48">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player5_right_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player5RightButtonsGroup">
+ <property name="title">
+ <string>R Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_49">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player5_right_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="player6Group">
+ <property name="title">
+ <string>Player 6</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_11">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player6LeftJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_11">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player6LeftBodyGroup">
+ <property name="title">
+ <string>L Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_54">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player6_left_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player6LeftButtonsGroup">
+ <property name="title">
+ <string>L Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_55">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player6_left_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player6RightJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_11">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player6RightBodyGroup">
+ <property name="title">
+ <string>R Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_52">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player6_right_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player6RightButtonsGroup">
+ <property name="title">
+ <string>R Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_53">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player6_right_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player78Widget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="player7Group">
+ <property name="title">
+ <string>Player 7</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_12">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player7LeftJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_12">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player7LeftBodyGroup">
+ <property name="title">
+ <string>L Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_58">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player7_left_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player7LeftButtonsGroup">
+ <property name="title">
+ <string>L Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_59">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player7_left_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player7RightJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_12">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player7RightBodyGroup">
+ <property name="title">
+ <string>R Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_56">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player7_right_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player7RightButtonsGroup">
+ <property name="title">
+ <string>R Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_57">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player7_right_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="player8Group">
+ <property name="title">
+ <string>Player 8</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_13">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="player8LeftJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_13">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player8LeftBodyGroup">
+ <property name="title">
+ <string>L Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_62">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player8_left_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player8LeftButtonsGroup">
+ <property name="title">
+ <string>L Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_63">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player8_left_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="player8RightJoycon" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_13">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player8RightBodyGroup">
+ <property name="title">
+ <string>R Body</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_60">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player8_right_body_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="player8RightButtonsGroup">
+ <property name="title">
+ <string>R Button</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_61">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="player8_right_buttons_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="rightInputAdvanced" native="true">
+ <layout class="QVBoxLayout" name="rightLayout" stretch="1,1">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="topRightInputAdvanced" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="gridGroupBox_3">
+ <property name="title">
+ <string>Other</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="keyboard_enabled">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Keyboard</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2">
+ <widget class="QPushButton" name="touchscreen_advanced">
+ <property name="text">
+ <string>Advanced</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <spacer name="horizontalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>76</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="mouse_advanced">
+ <property name="text">
+ <string>Advanced</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QCheckBox" name="touchscreen_enabled">
+ <property name="text">
+ <string>Touchscreen</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="mouse_enabled">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Mouse</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="motion_touch">
+ <property name="text">
+ <string>Motion / Touch</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="2">
+ <widget class="QPushButton" name="buttonMotionTouch">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QCheckBox" name="debug_enabled">
+ <property name="text">
+ <string>Debug Controller</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="2">
+ <widget class="QPushButton" name="debug_configure">
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="bottomRightInputAdvanced" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="mainVerticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/yuzu/configuration/configure_input_dialog.cpp b/src/yuzu/configuration/configure_input_dialog.cpp
new file mode 100644
index 000000000..1866003c2
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_dialog.cpp
@@ -0,0 +1,37 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "ui_configure_input_dialog.h"
+#include "yuzu/configuration/configure_input_dialog.h"
+
+ConfigureInputDialog::ConfigureInputDialog(QWidget* parent, std::size_t max_players,
+ InputCommon::InputSubsystem* input_subsystem)
+ : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputDialog>()),
+ input_widget(new ConfigureInput(this)) {
+ ui->setupUi(this);
+
+ input_widget->Initialize(input_subsystem, max_players);
+
+ ui->inputLayout->addWidget(input_widget);
+
+ RetranslateUI();
+}
+
+ConfigureInputDialog::~ConfigureInputDialog() = default;
+
+void ConfigureInputDialog::ApplyConfiguration() {
+ input_widget->ApplyConfiguration();
+}
+
+void ConfigureInputDialog::changeEvent(QEvent* event) {
+ if (event->type() == QEvent::LanguageChange) {
+ RetranslateUI();
+ }
+
+ QDialog::changeEvent(event);
+}
+
+void ConfigureInputDialog::RetranslateUI() {
+ ui->retranslateUi(this);
+}
diff --git a/src/yuzu/configuration/configure_input_dialog.h b/src/yuzu/configuration/configure_input_dialog.h
new file mode 100644
index 000000000..d1bd865f9
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_dialog.h
@@ -0,0 +1,38 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QDialog>
+#include "yuzu/configuration/configure_input.h"
+
+class QPushButton;
+
+namespace InputCommon {
+class InputSubsystem;
+}
+
+namespace Ui {
+class ConfigureInputDialog;
+}
+
+class ConfigureInputDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ConfigureInputDialog(QWidget* parent, std::size_t max_players,
+ InputCommon::InputSubsystem* input_subsystem);
+ ~ConfigureInputDialog() override;
+
+ void ApplyConfiguration();
+
+private:
+ void changeEvent(QEvent* event) override;
+ void RetranslateUI();
+
+ std::unique_ptr<Ui::ConfigureInputDialog> ui;
+
+ ConfigureInput* input_widget;
+};
diff --git a/src/yuzu/configuration/configure_input_dialog.ui b/src/yuzu/configuration/configure_input_dialog.ui
new file mode 100644
index 000000000..b92ddb200
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_dialog.ui
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureInputDialog</class>
+ <widget class="QDialog" name="ConfigureInputDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>70</width>
+ <height>540</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Input</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="inputLayout"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ConfigureInputDialog</receiver>
+ <slot>accept()</slot>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 597defe8c..698cb1940 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -5,39 +5,98 @@
#include <algorithm>
#include <memory>
#include <utility>
-#include <QColorDialog>
#include <QGridLayout>
+#include <QInputDialog>
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
#include <QTimer>
-#include "common/assert.h"
#include "common/param_package.h"
+#include "core/core.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/sm/sm.h"
+#include "input_common/gcadapter/gc_poller.h"
#include "input_common/main.h"
+#include "input_common/udp/udp.h"
#include "ui_configure_input_player.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_input_player.h"
+constexpr std::size_t HANDHELD_INDEX = 8;
+
const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM>
ConfigureInputPlayer::analog_sub_buttons{{
"up",
"down",
"left",
"right",
- "modifier",
}};
-static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) {
- const int index1 = grid->indexOf(item);
- const int index2 = grid->indexOf(onTopOf);
- int row, column, rowSpan, columnSpan;
- grid->getItemPosition(index2, &row, &column, &rowSpan, &columnSpan);
- grid->takeAt(index1);
- grid->addWidget(item, row, column, rowSpan, columnSpan);
+namespace {
+
+void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
+ bool connected) {
+ Core::System& system{Core::System::GetInstance()};
+ if (!system.IsPoweredOn()) {
+ return;
+ }
+ Service::SM::ServiceManager& sm = system.ServiceManager();
+
+ auto& npad =
+ sm.GetService<Service::HID::Hid>("hid")
+ ->GetAppletResource()
+ ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
+
+ npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
+}
+
+/// Maps the controller type combobox index to Controller Type enum
+constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) {
+ switch (index) {
+ case 0:
+ default:
+ return Settings::ControllerType::ProController;
+ case 1:
+ return Settings::ControllerType::DualJoyconDetached;
+ case 2:
+ return Settings::ControllerType::LeftJoycon;
+ case 3:
+ return Settings::ControllerType::RightJoycon;
+ case 4:
+ return Settings::ControllerType::Handheld;
+ }
}
-static QString GetKeyName(int key_code) {
+/// Maps the Controller Type enum to controller type combobox index
+constexpr int GetIndexFromControllerType(Settings::ControllerType type) {
+ switch (type) {
+ case Settings::ControllerType::ProController:
+ default:
+ return 0;
+ case Settings::ControllerType::DualJoyconDetached:
+ return 1;
+ case Settings::ControllerType::LeftJoycon:
+ return 2;
+ case Settings::ControllerType::RightJoycon:
+ return 3;
+ case Settings::ControllerType::Handheld:
+ return 4;
+ }
+}
+
+QString GetKeyName(int key_code) {
switch (key_code) {
+ case Qt::LeftButton:
+ return QObject::tr("Click 0");
+ case Qt::RightButton:
+ return QObject::tr("Click 1");
+ case Qt::MiddleButton:
+ return QObject::tr("Click 2");
+ case Qt::BackButton:
+ return QObject::tr("Click 3");
+ case Qt::ForwardButton:
+ return QObject::tr("Click 4");
case Qt::Key_Shift:
return QObject::tr("Shift");
case Qt::Key_Control:
@@ -51,9 +110,16 @@ static QString GetKeyName(int key_code) {
}
}
-static void SetAnalogButton(const Common::ParamPackage& input_param,
- Common::ParamPackage& analog_param, const std::string& button_name) {
- if (analog_param.Get("engine", "") != "analog_from_button") {
+void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackage& analog_param,
+ const std::string& button_name) {
+ // The poller returned a complete axis, so set all the buttons
+ if (input_param.Has("axis_x") && input_param.Has("axis_y")) {
+ analog_param = input_param;
+ return;
+ }
+ // Check if the current configuration has either no engine or an axis binding.
+ // Clears out the old binding and adds one with analog_from_button.
+ if (!analog_param.Has("engine") || analog_param.Has("axis_x") || analog_param.Has("axis_y")) {
analog_param = {
{"engine", "analog_from_button"},
};
@@ -61,7 +127,7 @@ static void SetAnalogButton(const Common::ParamPackage& input_param,
analog_param.Set(button_name, input_param.Serialize());
}
-static QString ButtonToText(const Common::ParamPackage& param) {
+QString ButtonToText(const Common::ParamPackage& param) {
if (!param.Has("engine")) {
return QObject::tr("[not set]");
}
@@ -84,6 +150,14 @@ static QString ButtonToText(const Common::ParamPackage& param) {
return GetKeyName(param.Get("code", 0));
}
+ if (param.Get("engine", "") == "cemuhookudp") {
+ if (param.Has("pad_index")) {
+ const QString motion_str = QString::fromStdString(param.Get("pad_index", ""));
+ return QObject::tr("Motion %1").arg(motion_str);
+ }
+ return GetKeyName(param.Get("code", 0));
+ }
+
if (param.Get("engine", "") == "sdl") {
if (param.Has("hat")) {
const QString hat_str = QString::fromStdString(param.Get("hat", ""));
@@ -111,7 +185,7 @@ static QString ButtonToText(const Common::ParamPackage& param) {
return QObject::tr("[unknown]");
}
-static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) {
+QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) {
if (!param.Has("engine")) {
return QObject::tr("[not set]");
}
@@ -161,22 +235,30 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string
}
return QObject::tr("[unknown]");
}
-
-ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug)
- : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
- debug(debug), timeout_timer(std::make_unique<QTimer>()),
- poll_timer(std::make_unique<QTimer>()) {
+} // namespace
+
+ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index,
+ QWidget* bottom_row,
+ InputCommon::InputSubsystem* input_subsystem_,
+ bool debug)
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
+ debug(debug), input_subsystem{input_subsystem_}, timeout_timer(std::make_unique<QTimer>()),
+ poll_timer(std::make_unique<QTimer>()), bottom_row(bottom_row) {
ui->setupUi(this);
+
setFocusPolicy(Qt::ClickFocus);
button_map = {
- ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
- ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
- ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
- ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
- ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown,
- ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown,
- ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
+ ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
+ ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
+ ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
+ ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
+ ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
+ };
+
+ mod_buttons = {
+ ui->buttonLStickMod,
+ ui->buttonRStickMod,
};
analog_map_buttons = {{
@@ -185,122 +267,66 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
ui->buttonLStickDown,
ui->buttonLStickLeft,
ui->buttonLStickRight,
- ui->buttonLStickMod,
},
{
ui->buttonRStickUp,
ui->buttonRStickDown,
ui->buttonRStickLeft,
ui->buttonRStickRight,
- ui->buttonRStickMod,
},
}};
- debug_hidden = {
- ui->buttonSL, ui->labelSL,
- ui->buttonSR, ui->labelSR,
- ui->buttonLStick, ui->labelLStickPressed,
- ui->buttonRStick, ui->labelRStickPressed,
- ui->buttonHome, ui->labelHome,
- ui->buttonScreenshot, ui->labelScreenshot,
+ motion_map = {
+ ui->buttonMotionLeft,
+ ui->buttonMotionRight,
};
- auto layout = Settings::values.players[player_index].type;
- if (debug)
- layout = Settings::ControllerType::DualJoycon;
-
- switch (layout) {
- case Settings::ControllerType::ProController:
- case Settings::ControllerType::DualJoycon:
- layout_hidden = {
- ui->buttonSL,
- ui->labelSL,
- ui->buttonSR,
- ui->labelSR,
- };
- break;
- case Settings::ControllerType::LeftJoycon:
- layout_hidden = {
- ui->right_body_button,
- ui->right_buttons_button,
- ui->right_body_label,
- ui->right_buttons_label,
- ui->buttonR,
- ui->labelR,
- ui->buttonZR,
- ui->labelZR,
- ui->labelHome,
- ui->buttonHome,
- ui->buttonPlus,
- ui->labelPlus,
- ui->RStick,
- ui->faceButtons,
- };
- break;
- case Settings::ControllerType::RightJoycon:
- layout_hidden = {
- ui->left_body_button, ui->left_buttons_button,
- ui->left_body_label, ui->left_buttons_label,
- ui->buttonL, ui->labelL,
- ui->buttonZL, ui->labelZL,
- ui->labelScreenshot, ui->buttonScreenshot,
- ui->buttonMinus, ui->labelMinus,
- ui->LStick, ui->Dpad,
- };
- break;
- }
-
- if (debug || layout == Settings::ControllerType::ProController) {
- ui->controller_color->hide();
- } else {
- if (layout == Settings::ControllerType::LeftJoycon ||
- layout == Settings::ControllerType::RightJoycon) {
- ui->horizontalSpacer_4->setGeometry({0, 0, 0, 0});
-
- LayerGridElements(ui->buttons, ui->shoulderButtons, ui->Dpad);
- LayerGridElements(ui->buttons, ui->misc, ui->RStick);
- LayerGridElements(ui->buttons, ui->Dpad, ui->faceButtons);
- LayerGridElements(ui->buttons, ui->RStick, ui->LStick);
- }
- }
-
- for (auto* widget : layout_hidden)
- widget->setVisible(false);
+ analog_map_deadzone_label = {ui->labelLStickDeadzone, ui->labelRStickDeadzone};
+ analog_map_deadzone_slider = {ui->sliderLStickDeadzone, ui->sliderRStickDeadzone};
+ analog_map_modifier_groupbox = {ui->buttonLStickModGroup, ui->buttonRStickModGroup};
+ analog_map_modifier_label = {ui->labelLStickModifierRange, ui->labelRStickModifierRange};
+ analog_map_modifier_slider = {ui->sliderLStickModifierRange, ui->sliderRStickModifierRange};
+ analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup};
+ analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange};
- analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
- analog_map_deadzone_and_modifier_slider = {ui->sliderLStickDeadzoneAndModifier,
- ui->sliderRStickDeadzoneAndModifier};
- analog_map_deadzone_and_modifier_slider_label = {ui->labelLStickDeadzoneAndModifier,
- ui->labelRStickDeadzoneAndModifier};
-
- for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
- auto* const button = button_map[button_id];
- if (button == nullptr) {
- continue;
- }
-
- button->setContextMenuPolicy(Qt::CustomContextMenu);
+ const auto ConfigureButtonClick = [&](QPushButton* button, Common::ParamPackage* param,
+ int default_val, InputCommon::Polling::DeviceType type) {
connect(button, &QPushButton::clicked, [=, this] {
HandleClick(
- button_map[button_id],
+ button,
[=, this](Common::ParamPackage params) {
- // Workaround for ZL & ZR for analog triggers like on XBOX controllors.
- // Analog triggers (from controllers like the XBOX controller) would not
- // work due to a different range of their signals (from 0 to 255 on
- // analog triggers instead of -32768 to 32768 on analog joysticks). The
- // SDL driver misinterprets analog triggers as analog joysticks.
+ // Workaround for ZL & ZR for analog triggers like on XBOX
+ // controllers. Analog triggers (from controllers like the XBOX
+ // controller) would not work due to a different range of their
+ // signals (from 0 to 255 on analog triggers instead of -32768 to
+ // 32768 on analog joysticks). The SDL driver misinterprets analog
+ // triggers as analog joysticks.
// TODO: reinterpret the signal range for analog triggers to map the
- // values correctly. This is required for the correct emulation of the
- // analog triggers of the GameCube controller.
- if (button_id == Settings::NativeButton::ZL ||
- button_id == Settings::NativeButton::ZR) {
+ // values correctly. This is required for the correct emulation of
+ // the analog triggers of the GameCube controller.
+ if (button == ui->buttonZL || button == ui->buttonZR) {
params.Set("direction", "+");
params.Set("threshold", "0.5");
}
- buttons_param[button_id] = std::move(params);
+ *param = std::move(params);
},
- InputCommon::Polling::DeviceType::Button);
+ type);
});
+ };
+
+ for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
+ auto* const button = button_map[button_id];
+
+ if (button == nullptr) {
+ continue;
+ }
+
+ ConfigureButtonClick(button_map[button_id], &buttons_param[button_id],
+ Config::default_buttons[button_id],
+ InputCommon::Polling::DeviceType::Button);
+
+ button->setContextMenuPolicy(Qt::CustomContextMenu);
+
connect(button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
@@ -308,100 +334,176 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
buttons_param[button_id].Clear();
button_map[button_id]->setText(tr("[not set]"));
});
- context_menu.addAction(tr("Restore Default"), [&] {
- buttons_param[button_id] = Common::ParamPackage{
- InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
- button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
- });
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
});
}
- for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
- for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
+ for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
+ auto* const button = motion_map[motion_id];
+ if (button == nullptr) {
+ continue;
+ }
+
+ ConfigureButtonClick(motion_map[motion_id], &motions_param[motion_id],
+ Config::default_motions[motion_id],
+ InputCommon::Polling::DeviceType::Motion);
+
+ button->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(button, &QPushButton::customContextMenuRequested,
+ [=, this](const QPoint& menu_location) {
+ QMenu context_menu;
+ context_menu.addAction(tr("Clear"), [&] {
+ motions_param[motion_id].Clear();
+ motion_map[motion_id]->setText(tr("[not set]"));
+ });
+ context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location));
+ });
+ }
+
+ for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
+ for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
+
if (analog_button == nullptr) {
continue;
}
- analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(analog_button, &QPushButton::clicked, [=, this] {
HandleClick(
analog_map_buttons[analog_id][sub_button_id],
[=, this](const Common::ParamPackage& params) {
- SetAnalogButton(params, analogs_param[analog_id],
- analog_sub_buttons[sub_button_id]);
+ SetAnalogParam(params, analogs_param[analog_id],
+ analog_sub_buttons[sub_button_id]);
},
- InputCommon::Polling::DeviceType::Button);
+ InputCommon::Polling::DeviceType::AnalogPreferred);
});
+
+ analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
+
connect(analog_button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
- analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
+ analogs_param[analog_id].Clear();
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
});
- context_menu.addAction(tr("Restore Default"), [&] {
- Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
- Config::default_analogs[analog_id][sub_button_id])};
- SetAnalogButton(params, analogs_param[analog_id],
- analog_sub_buttons[sub_button_id]);
- analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
- analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
- });
context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
menu_location));
});
}
- connect(analog_map_stick[analog_id], &QPushButton::clicked, [=, this] {
- if (QMessageBox::information(
- this, tr("Information"),
- tr("After pressing OK, first move your joystick horizontally, "
- "and then vertically."),
- QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
- HandleClick(
- analog_map_stick[analog_id],
- [=, this](const Common::ParamPackage& params) {
- analogs_param[analog_id] = params;
- },
- InputCommon::Polling::DeviceType::Analog);
- }
- });
- connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged,
+ // Handle clicks for the modifier buttons as well.
+ ConfigureButtonClick(mod_buttons[analog_id], &stick_mod_param[analog_id],
+ Config::default_stick_mod[analog_id],
+ InputCommon::Polling::DeviceType::Button);
+
+ mod_buttons[analog_id]->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(mod_buttons[analog_id], &QPushButton::customContextMenuRequested,
+ [=, this](const QPoint& menu_location) {
+ QMenu context_menu;
+ context_menu.addAction(tr("Clear"), [&] {
+ stick_mod_param[analog_id].Clear();
+ mod_buttons[analog_id]->setText(tr("[not set]"));
+ });
+ context_menu.exec(mod_buttons[analog_id]->mapToGlobal(menu_location));
+ });
+
+ connect(analog_map_range_spinbox[analog_id], qOverload<int>(&QSpinBox::valueChanged),
[=, this] {
- const float slider_value =
- analog_map_deadzone_and_modifier_slider[analog_id]->value();
- if (analogs_param[analog_id].Get("engine", "") == "sdl" ||
- analogs_param[analog_id].Get("engine", "") == "gcpad") {
- analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
- tr("Deadzone: %1%").arg(slider_value));
- analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
- } else {
- analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
- tr("Modifier Scale: %1%").arg(slider_value));
- analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
- }
+ const auto spinbox_value = analog_map_range_spinbox[analog_id]->value();
+ analogs_param[analog_id].Set("range", spinbox_value / 100.0f);
});
+
+ connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] {
+ const auto slider_value = analog_map_deadzone_slider[analog_id]->value();
+ analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value));
+ analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
+ });
+
+ connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] {
+ const auto slider_value = analog_map_modifier_slider[analog_id]->value();
+ analog_map_modifier_label[analog_id]->setText(
+ tr("Modifier Range: %1%").arg(slider_value));
+ analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
+ });
}
- connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
- connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); });
+ // Player Connected checkbox
+ connect(ui->groupConnectedController, &QGroupBox::toggled,
+ [this](bool checked) { emit Connected(checked); });
+
+ // Set up controller type. Only Player 1 can choose Handheld.
+ ui->comboControllerType->clear();
+
+ QStringList controller_types = {
+ tr("Pro Controller"),
+ tr("Dual Joycons"),
+ tr("Left Joycon"),
+ tr("Right Joycon"),
+ };
+
+ if (player_index == 0) {
+ controller_types.append(tr("Handheld"));
+ connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged),
+ [this](int index) {
+ emit HandheldStateChanged(GetControllerTypeFromIndex(index) ==
+ Settings::ControllerType::Handheld);
+ });
+ }
+
+ // The Debug Controller can only choose the Pro Controller.
+ if (debug) {
+ ui->buttonScreenshot->setEnabled(false);
+ ui->buttonHome->setEnabled(false);
+ ui->groupConnectedController->setCheckable(false);
+ QStringList debug_controller_types = {
+ tr("Pro Controller"),
+ };
+ ui->comboControllerType->addItems(debug_controller_types);
+ } else {
+ ui->comboControllerType->addItems(controller_types);
+ }
+
+ UpdateControllerIcon();
+ UpdateControllerAvailableButtons();
+ UpdateMotionButtons();
+ connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) {
+ UpdateControllerIcon();
+ UpdateControllerAvailableButtons();
+ UpdateMotionButtons();
+ });
+
+ connect(ui->comboDevices, qOverload<int>(&QComboBox::currentIndexChanged), this,
+ &ConfigureInputPlayer::UpdateMappingWithDefaults);
+
+ ui->buttonRefreshDevices->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
+ UpdateInputDevices();
+ connect(ui->buttonRefreshDevices, &QPushButton::clicked,
+ [this] { emit RefreshInputDevices(); });
timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this] {
Common::ParamPackage params;
- if (InputCommon::GetGCButtons()->IsPolling()) {
- params = InputCommon::GetGCButtons()->GetNextInput();
+ if (input_subsystem->GetGCButtons()->IsPolling()) {
+ params = input_subsystem->GetGCButtons()->GetNextInput();
+ if (params.Has("engine")) {
+ SetPollingResult(params, false);
+ return;
+ }
+ }
+ if (input_subsystem->GetGCAnalogs()->IsPolling()) {
+ params = input_subsystem->GetGCAnalogs()->GetNextInput();
if (params.Has("engine")) {
SetPollingResult(params, false);
return;
}
}
- if (InputCommon::GetGCAnalogs()->IsPolling()) {
- params = InputCommon::GetGCAnalogs()->GetNextInput();
+ if (input_subsystem->GetUDPMotions()->IsPolling()) {
+ params = input_subsystem->GetUDPMotions()->GetNextInput();
if (params.Has("engine")) {
SetPollingResult(params, false);
return;
@@ -416,20 +518,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
}
});
- controller_color_buttons = {
- ui->left_body_button,
- ui->left_buttons_button,
- ui->right_body_button,
- ui->right_buttons_button,
- };
-
- for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) {
- connect(controller_color_buttons[i], &QPushButton::clicked, this,
- [this, i] { OnControllerButtonClick(static_cast<int>(i)); });
- }
-
LoadConfiguration();
- resize(0, 0);
// TODO(wwylele): enable this when we actually emulate it
ui->buttonHome->setEnabled(false);
@@ -438,27 +527,47 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
ConfigureInputPlayer::~ConfigureInputPlayer() = default;
void ConfigureInputPlayer::ApplyConfiguration() {
- auto& buttons =
- debug ? Settings::values.debug_pad_buttons : Settings::values.players[player_index].buttons;
- auto& analogs =
- debug ? Settings::values.debug_pad_analogs : Settings::values.players[player_index].analogs;
+ auto& player = Settings::values.players[player_index];
+ auto& buttons = debug ? Settings::values.debug_pad_buttons : player.buttons;
+ auto& analogs = debug ? Settings::values.debug_pad_analogs : player.analogs;
std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(),
[](const Common::ParamPackage& param) { return param.Serialize(); });
std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(),
[](const Common::ParamPackage& param) { return param.Serialize(); });
- if (debug)
+ if (debug) {
+ return;
+ }
+
+ auto& motions = player.motions;
+ std::transform(motions_param.begin(), motions_param.end(), motions.begin(),
+ [](const Common::ParamPackage& param) { return param.Serialize(); });
+
+ player.controller_type =
+ static_cast<Settings::ControllerType>(ui->comboControllerType->currentIndex());
+ player.connected = ui->groupConnectedController->isChecked();
+
+ // Player 2-8
+ if (player_index != 0) {
+ UpdateController(player.controller_type, player_index, player.connected);
return;
+ }
- std::array<u32, 4> colors{};
- std::transform(controller_colors.begin(), controller_colors.end(), colors.begin(),
- [](QColor color) { return color.rgb(); });
+ // Player 1 and Handheld
+ auto& handheld = Settings::values.players[HANDHELD_INDEX];
+ // If Handheld is selected, copy all the settings from Player 1 to Handheld.
+ if (player.controller_type == Settings::ControllerType::Handheld) {
+ handheld = player;
+ handheld.connected = ui->groupConnectedController->isChecked();
+ player.connected = false; // Disconnect Player 1
+ } else {
+ player.connected = ui->groupConnectedController->isChecked();
+ handheld.connected = false; // Disconnect Handheld
+ }
- Settings::values.players[player_index].body_color_left = colors[0];
- Settings::values.players[player_index].button_color_left = colors[1];
- Settings::values.players[player_index].body_color_right = colors[2];
- Settings::values.players[player_index].button_color_right = colors[3];
+ UpdateController(player.controller_type, player_index, player.connected);
+ UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected);
}
void ConfigureInputPlayer::changeEvent(QEvent* event) {
@@ -466,24 +575,16 @@ void ConfigureInputPlayer::changeEvent(QEvent* event) {
RetranslateUI();
}
- QDialog::changeEvent(event);
+ QWidget::changeEvent(event);
}
void ConfigureInputPlayer::RetranslateUI() {
ui->retranslateUi(this);
- UpdateButtonLabels();
-}
-
-void ConfigureInputPlayer::OnControllerButtonClick(int i) {
- const QColor new_bg_color = QColorDialog::getColor(controller_colors[i]);
- if (!new_bg_color.isValid())
- return;
- controller_colors[i] = new_bg_color;
- controller_color_buttons[i]->setStyleSheet(
- QStringLiteral("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
+ UpdateUI();
}
void ConfigureInputPlayer::LoadConfiguration() {
+ auto& player = Settings::values.players[player_index];
if (debug) {
std::transform(Settings::values.debug_pad_buttons.begin(),
Settings::values.debug_pad_buttons.end(), buttons_param.begin(),
@@ -492,86 +593,110 @@ void ConfigureInputPlayer::LoadConfiguration() {
Settings::values.debug_pad_analogs.end(), analogs_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
} else {
- std::transform(Settings::values.players[player_index].buttons.begin(),
- Settings::values.players[player_index].buttons.end(), buttons_param.begin(),
+ std::transform(player.buttons.begin(), player.buttons.end(), buttons_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
- std::transform(Settings::values.players[player_index].analogs.begin(),
- Settings::values.players[player_index].analogs.end(), analogs_param.begin(),
+ std::transform(player.analogs.begin(), player.analogs.end(), analogs_param.begin(),
+ [](const std::string& str) { return Common::ParamPackage(str); });
+ std::transform(player.motions.begin(), player.motions.end(), motions_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
}
- UpdateButtonLabels();
+ UpdateUI();
- if (debug)
+ if (debug) {
return;
+ }
- std::array<u32, 4> colors = {
- Settings::values.players[player_index].body_color_left,
- Settings::values.players[player_index].button_color_left,
- Settings::values.players[player_index].body_color_right,
- Settings::values.players[player_index].button_color_right,
- };
-
- std::transform(colors.begin(), colors.end(), controller_colors.begin(),
- [](u32 rgb) { return QColor::fromRgb(rgb); });
+ ui->comboControllerType->setCurrentIndex(static_cast<int>(player.controller_type));
+ ui->groupConnectedController->setChecked(
+ player.connected ||
+ (player_index == 0 && Settings::values.players[HANDHELD_INDEX].connected));
+}
- for (std::size_t i = 0; i < colors.size(); ++i) {
- controller_color_buttons[i]->setStyleSheet(
- QStringLiteral("QPushButton { background-color: %1 }")
- .arg(controller_colors[i].name()));
+void ConfigureInputPlayer::UpdateInputDevices() {
+ input_devices = input_subsystem->GetInputDevices();
+ ui->comboDevices->clear();
+ for (auto device : input_devices) {
+ ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {});
}
}
void ConfigureInputPlayer::RestoreDefaults() {
- for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
+ // Reset Buttons
+ for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
buttons_param[button_id] = Common::ParamPackage{
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
}
- for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
- for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
+ // Reset Analogs and Modifier Buttons
+ for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
+ for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
Config::default_analogs[analog_id][sub_button_id])};
- SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
+ SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
}
+
+ stick_mod_param[analog_id] = Common::ParamPackage(
+ InputCommon::GenerateKeyboardParam(Config::default_stick_mod[analog_id]));
+ }
+
+ for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
+ motions_param[motion_id] = Common::ParamPackage{
+ InputCommon::GenerateKeyboardParam(Config::default_motions[motion_id])};
}
- UpdateButtonLabels();
- ApplyConfiguration();
+ UpdateUI();
+ UpdateInputDevices();
+ ui->comboControllerType->setCurrentIndex(0);
}
void ConfigureInputPlayer::ClearAll() {
- for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
+ for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
const auto* const button = button_map[button_id];
- if (button == nullptr || !button->isEnabled()) {
+ if (button == nullptr) {
continue;
}
buttons_param[button_id].Clear();
}
- for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
- for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
+ for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
+ for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
const auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
- if (analog_button == nullptr || !analog_button->isEnabled()) {
+ if (analog_button == nullptr) {
continue;
}
analogs_param[analog_id].Clear();
}
+
+ stick_mod_param[analog_id].Clear();
+ }
+
+ for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
+ const auto* const motion_button = motion_map[motion_id];
+ if (motion_button == nullptr) {
+ continue;
+ }
+
+ motions_param[motion_id].Clear();
}
- UpdateButtonLabels();
- ApplyConfiguration();
+ UpdateUI();
+ UpdateInputDevices();
}
-void ConfigureInputPlayer::UpdateButtonLabels() {
- for (int button = 0; button < Settings::NativeButton::NumButtons; button++) {
+void ConfigureInputPlayer::UpdateUI() {
+ for (int button = 0; button < Settings::NativeButton::NumButtons; ++button) {
button_map[button]->setText(ButtonToText(buttons_param[button]));
}
- for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
- for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
+ for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
+ motion_map[motion_id]->setText(ButtonToText(motions_param[motion_id]));
+ }
+
+ for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
+ for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
if (analog_button == nullptr) {
@@ -581,99 +706,153 @@ void ConfigureInputPlayer::UpdateButtonLabels() {
analog_button->setText(
AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
}
- analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
+ mod_buttons[analog_id]->setText(ButtonToText(stick_mod_param[analog_id]));
+
+ const auto deadzone_label = analog_map_deadzone_label[analog_id];
+ const auto deadzone_slider = analog_map_deadzone_slider[analog_id];
+ const auto modifier_groupbox = analog_map_modifier_groupbox[analog_id];
+ const auto modifier_label = analog_map_modifier_label[analog_id];
+ const auto modifier_slider = analog_map_modifier_slider[analog_id];
+ const auto range_groupbox = analog_map_range_groupbox[analog_id];
+ const auto range_spinbox = analog_map_range_spinbox[analog_id];
+
+ int slider_value;
auto& param = analogs_param[analog_id];
- auto* const analog_stick_slider = analog_map_deadzone_and_modifier_slider[analog_id];
- auto* const analog_stick_slider_label =
- analog_map_deadzone_and_modifier_slider_label[analog_id];
-
- if (param.Has("engine")) {
- if (param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad") {
- if (!param.Has("deadzone")) {
- param.Set("deadzone", 0.1f);
- }
-
- analog_stick_slider->setValue(static_cast<int>(param.Get("deadzone", 0.1f) * 100));
- if (analog_stick_slider->value() == 0) {
- analog_stick_slider_label->setText(tr("Deadzone: 0%"));
- }
- } else {
- if (!param.Has("modifier_scale")) {
- param.Set("modifier_scale", 0.5f);
- }
-
- analog_stick_slider->setValue(
- static_cast<int>(param.Get("modifier_scale", 0.5f) * 100));
- if (analog_stick_slider->value() == 0) {
- analog_stick_slider_label->setText(tr("Modifier Scale: 0%"));
- }
+ const bool is_controller =
+ param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad";
+
+ if (is_controller) {
+ if (!param.Has("deadzone")) {
+ param.Set("deadzone", 0.1f);
+ }
+ slider_value = static_cast<int>(param.Get("deadzone", 0.1f) * 100);
+ deadzone_label->setText(tr("Deadzone: %1%").arg(slider_value));
+ deadzone_slider->setValue(slider_value);
+ if (!param.Has("range")) {
+ param.Set("range", 1.0f);
+ }
+ range_spinbox->setValue(static_cast<int>(param.Get("range", 1.0f) * 100));
+ } else {
+ if (!param.Has("modifier_scale")) {
+ param.Set("modifier_scale", 0.5f);
}
+ slider_value = static_cast<int>(param.Get("modifier_scale", 0.5f) * 100);
+ modifier_label->setText(tr("Modifier Range: %1%").arg(slider_value));
+ modifier_slider->setValue(slider_value);
}
+
+ deadzone_label->setVisible(is_controller);
+ deadzone_slider->setVisible(is_controller);
+ modifier_groupbox->setVisible(!is_controller);
+ modifier_label->setVisible(!is_controller);
+ modifier_slider->setVisible(!is_controller);
+ range_groupbox->setVisible(is_controller);
}
}
+void ConfigureInputPlayer::UpdateMappingWithDefaults() {
+ if (ui->comboDevices->currentIndex() < 2) {
+ return;
+ }
+ const auto& device = input_devices[ui->comboDevices->currentIndex()];
+ auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
+ auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
+ for (std::size_t i = 0; i < buttons_param.size(); ++i) {
+ buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
+ }
+ for (std::size_t i = 0; i < analogs_param.size(); ++i) {
+ analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)];
+ }
+
+ UpdateUI();
+}
+
void ConfigureInputPlayer::HandleClick(
QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type) {
- button->setText(tr("[press key]"));
+ if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) {
+ button->setText(tr("Shake!"));
+ } else {
+ button->setText(tr("[waiting]"));
+ }
button->setFocus();
- // Keyboard keys can only be used as button devices
- want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
- if (want_keyboard_keys) {
- const auto iter = std::find(button_map.begin(), button_map.end(), button);
- ASSERT(iter != button_map.end());
- const auto index = std::distance(button_map.begin(), iter);
- ASSERT(index < Settings::NativeButton::NumButtons && index >= 0);
- }
+ // The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a
+ // controller, then they don't want keyboard/mouse input
+ want_keyboard_mouse = ui->comboDevices->currentIndex() < 2;
input_setter = new_input_setter;
- device_pollers = InputCommon::Polling::GetPollers(type);
+ device_pollers = input_subsystem->GetPollers(type);
for (auto& poller : device_pollers) {
poller->Start();
}
- grabKeyboard();
- grabMouse();
+ QWidget::grabMouse();
+ QWidget::grabKeyboard();
+
if (type == InputCommon::Polling::DeviceType::Button) {
- InputCommon::GetGCButtons()->BeginConfiguration();
+ input_subsystem->GetGCButtons()->BeginConfiguration();
} else {
- InputCommon::GetGCAnalogs()->BeginConfiguration();
+ input_subsystem->GetGCAnalogs()->BeginConfiguration();
}
- timeout_timer->start(5000); // Cancel after 5 seconds
- poll_timer->start(200); // Check for new inputs every 200ms
+
+ if (type == InputCommon::Polling::DeviceType::Motion) {
+ input_subsystem->GetUDPMotions()->BeginConfiguration();
+ }
+
+ timeout_timer->start(2500); // Cancel after 2.5 seconds
+ poll_timer->start(50); // Check for new inputs every 50ms
}
void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) {
- releaseKeyboard();
- releaseMouse();
timeout_timer->stop();
poll_timer->stop();
for (auto& poller : device_pollers) {
poller->Stop();
}
- InputCommon::GetGCButtons()->EndConfiguration();
- InputCommon::GetGCAnalogs()->EndConfiguration();
+ QWidget::releaseMouse();
+ QWidget::releaseKeyboard();
+
+ input_subsystem->GetGCButtons()->EndConfiguration();
+ input_subsystem->GetGCAnalogs()->EndConfiguration();
+
+ input_subsystem->GetUDPMotions()->EndConfiguration();
if (!abort) {
(*input_setter)(params);
}
- UpdateButtonLabels();
+ UpdateUI();
input_setter = std::nullopt;
}
+void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
+ if (!input_setter || !event) {
+ return;
+ }
+
+ if (want_keyboard_mouse) {
+ SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
+ false);
+ } else {
+ // We don't want any mouse buttons, so don't stop polling
+ return;
+ }
+
+ SetPollingResult({}, true);
+}
+
void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
if (!input_setter || !event) {
return;
}
if (event->key() != Qt::Key_Escape) {
- if (want_keyboard_keys) {
+ if (want_keyboard_mouse) {
SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
false);
} else {
@@ -681,5 +860,139 @@ void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
return;
}
}
+
SetPollingResult({}, true);
}
+
+void ConfigureInputPlayer::UpdateControllerIcon() {
+ // We aren't using Qt's built in theme support here since we aren't drawing an icon (and its
+ // "nonstandard" to use an image through the icon support)
+ const QString stylesheet = [this] {
+ switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) {
+ case Settings::ControllerType::ProController:
+ return QStringLiteral("image: url(:/controller/pro_controller%0)");
+ case Settings::ControllerType::DualJoyconDetached:
+ return QStringLiteral("image: url(:/controller/dual_joycon%0)");
+ case Settings::ControllerType::LeftJoycon:
+ return QStringLiteral("image: url(:/controller/single_joycon_left_vertical%0)");
+ case Settings::ControllerType::RightJoycon:
+ return QStringLiteral("image: url(:/controller/single_joycon_right_vertical%0)");
+ case Settings::ControllerType::Handheld:
+ return QStringLiteral("image: url(:/controller/handheld%0)");
+ default:
+ return QString{};
+ }
+ }();
+
+ const QString theme = [this] {
+ if (QIcon::themeName().contains(QStringLiteral("dark"))) {
+ return QStringLiteral("_dark");
+ } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
+ return QStringLiteral("_midnight");
+ } else {
+ return QString{};
+ }
+ }();
+
+ ui->controllerFrame->setStyleSheet(stylesheet.arg(theme));
+}
+
+void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
+ auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
+ if (debug) {
+ layout = Settings::ControllerType::ProController;
+ }
+
+ // List of all the widgets that will be hidden by any of the following layouts that need
+ // "unhidden" after the controller type changes
+ const std::array<QWidget*, 9> layout_show = {
+ ui->buttonShoulderButtonsSLSR,
+ ui->horizontalSpacerShoulderButtonsWidget,
+ ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->buttonShoulderButtonsLeft,
+ ui->buttonMiscButtonsMinusScreenshot,
+ ui->bottomLeft,
+ ui->buttonShoulderButtonsRight,
+ ui->buttonMiscButtonsPlusHome,
+ ui->bottomRight,
+ };
+
+ for (auto* widget : layout_show) {
+ widget->show();
+ }
+
+ std::vector<QWidget*> layout_hidden;
+ switch (layout) {
+ case Settings::ControllerType::ProController:
+ case Settings::ControllerType::DualJoyconDetached:
+ case Settings::ControllerType::Handheld:
+ layout_hidden = {
+ ui->buttonShoulderButtonsSLSR,
+ ui->horizontalSpacerShoulderButtonsWidget2,
+ };
+ break;
+ case Settings::ControllerType::LeftJoycon:
+ layout_hidden = {
+ ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->buttonShoulderButtonsRight,
+ ui->buttonMiscButtonsPlusHome,
+ ui->bottomRight,
+ };
+ break;
+ case Settings::ControllerType::RightJoycon:
+ layout_hidden = {
+ ui->horizontalSpacerShoulderButtonsWidget,
+ ui->buttonShoulderButtonsLeft,
+ ui->buttonMiscButtonsMinusScreenshot,
+ ui->bottomLeft,
+ };
+ break;
+ }
+
+ for (auto* widget : layout_hidden) {
+ widget->hide();
+ }
+}
+
+void ConfigureInputPlayer::UpdateMotionButtons() {
+ if (debug) {
+ // Motion isn't used with the debug controller, hide both groupboxes.
+ ui->buttonMotionLeftGroup->hide();
+ ui->buttonMotionRightGroup->hide();
+ return;
+ }
+
+ // Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller.
+ switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) {
+ case Settings::ControllerType::ProController:
+ case Settings::ControllerType::LeftJoycon:
+ case Settings::ControllerType::Handheld:
+ // Show "Motion 1" and hide "Motion 2".
+ ui->buttonMotionLeftGroup->show();
+ ui->buttonMotionRightGroup->hide();
+ break;
+ case Settings::ControllerType::RightJoycon:
+ // Show "Motion 2" and hide "Motion 1".
+ ui->buttonMotionLeftGroup->hide();
+ ui->buttonMotionRightGroup->show();
+ break;
+ case Settings::ControllerType::DualJoyconDetached:
+ default:
+ // Show both "Motion 1/2".
+ ui->buttonMotionLeftGroup->show();
+ ui->buttonMotionRightGroup->show();
+ break;
+ }
+}
+
+void ConfigureInputPlayer::showEvent(QShowEvent* event) {
+ if (bottom_row == nullptr) {
+ return;
+ }
+ QWidget::showEvent(event);
+ ui->main->addWidget(bottom_row);
+}
+
+void ConfigureInputPlayer::ConnectPlayer(bool connected) {
+ ui->groupConnectedController->setChecked(connected);
+}
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index 95afa5375..ce443dec5 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -10,16 +10,25 @@
#include <optional>
#include <string>
-#include <QDialog>
+#include <QWidget>
#include "common/param_package.h"
#include "core/settings.h"
#include "ui_configure_input.h"
+class QCheckBox;
class QKeyEvent;
+class QLabel;
class QPushButton;
+class QSlider;
+class QSpinBox;
class QString;
class QTimer;
+class QWidget;
+
+namespace InputCommon {
+class InputSubsystem;
+}
namespace InputCommon::Polling {
class DevicePoller;
@@ -30,77 +39,122 @@ namespace Ui {
class ConfigureInputPlayer;
}
-class ConfigureInputPlayer : public QDialog {
+class ConfigureInputPlayer : public QWidget {
Q_OBJECT
public:
- explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false);
+ explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row,
+ InputCommon::InputSubsystem* input_subsystem_,
+ bool debug = false);
~ConfigureInputPlayer() override;
- /// Save all button configurations to settings file
+ /// Save all button configurations to settings file.
void ApplyConfiguration();
+ /// Update the input devices combobox.
+ void UpdateInputDevices();
+
+ /// Restore all buttons to their default values.
+ void RestoreDefaults();
+
+ /// Clear all input configuration.
+ void ClearAll();
+
+ /// Set the connection state checkbox (used to sync state).
+ void ConnectPlayer(bool connected);
+
+signals:
+ /// Emitted when this controller is connected by the user.
+ void Connected(bool connected);
+ /// Emitted when the Handheld mode is selected (undocked with dual joycons attached).
+ void HandheldStateChanged(bool is_handheld);
+ /// Emitted when the input devices combobox is being refreshed.
+ void RefreshInputDevices();
+
+protected:
+ void showEvent(QShowEvent* event) override;
+
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
- void OnControllerButtonClick(int i);
-
/// Load configuration settings.
void LoadConfiguration();
- /// Restore all buttons to their default values.
- void RestoreDefaults();
- /// Clear all input configuration
- void ClearAll();
-
- /// Update UI to reflect current configuration.
- void UpdateButtonLabels();
/// Called when the button was pressed.
void HandleClick(QPushButton* button,
std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type);
- /// Finish polling and configure input using the input_setter
+ /// Finish polling and configure input using the input_setter.
void SetPollingResult(const Common::ParamPackage& params, bool abort);
+ /// Handle mouse button press events.
+ void mousePressEvent(QMouseEvent* event) override;
+
/// Handle key press events.
void keyPressEvent(QKeyEvent* event) override;
+ /// Update UI to reflect current configuration.
+ void UpdateUI();
+
+ /// Update the controller selection combobox
+ void UpdateControllerCombobox();
+
+ /// Update the current controller icon.
+ void UpdateControllerIcon();
+
+ /// Hides and disables controller settings based on the current controller type.
+ void UpdateControllerAvailableButtons();
+
+ /// Shows or hides motion groupboxes based on the current controller type.
+ void UpdateMotionButtons();
+
+ /// Gets the default controller mapping for this device and auto configures the input to match.
+ void UpdateMappingWithDefaults();
+
std::unique_ptr<Ui::ConfigureInputPlayer> ui;
std::size_t player_index;
bool debug;
+ InputCommon::InputSubsystem* input_subsystem;
+
std::unique_ptr<QTimer> timeout_timer;
std::unique_ptr<QTimer> poll_timer;
+ static constexpr int PLAYER_COUNT = 8;
+ std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox;
+
/// This will be the the setting function when an input is awaiting configuration.
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
+ std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> stick_mod_param;
+ std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions> motions_param;
- static constexpr int ANALOG_SUB_BUTTONS_NUM = 5;
+ static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
/// Each button input is represented by a QPushButton.
std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map;
+ /// Each motion input is represented by a QPushButton.
+ std::array<QPushButton*, Settings::NativeMotion::NumMotions> motion_map;
+ /// Extra buttons for the modifiers.
+ std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> mod_buttons;
- std::vector<QWidget*> debug_hidden;
- std::vector<QWidget*> layout_hidden;
-
- /// A group of five QPushButtons represent one analog input. The buttons each represent up,
- /// down, left, right, and modifier, respectively.
+ /// A group of four QPushButtons represent one analog input. The buttons each represent up,
+ /// down, left, right, respectively.
std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs>
analog_map_buttons;
- /// Analog inputs are also represented each with a single button, used to configure with an
- /// actual analog stick
- std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick;
- std::array<QSlider*, Settings::NativeAnalog::NumAnalogs>
- analog_map_deadzone_and_modifier_slider;
- std::array<QLabel*, Settings::NativeAnalog::NumAnalogs>
- analog_map_deadzone_and_modifier_slider_label;
+ std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_label;
+ std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_slider;
+ std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_groupbox;
+ std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_label;
+ std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_slider;
+ std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_groupbox;
+ std::array<QSpinBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_spinbox;
static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
@@ -108,8 +162,14 @@ private:
/// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
/// keyboard events are ignored.
- bool want_keyboard_keys = false;
+ bool want_keyboard_mouse = false;
+
+ /// List of physical devices users can map with. If a SDL backed device is selected, then you
+ /// can usue this device to get a default mapping.
+ std::vector<Common::ParamPackage> input_devices;
- std::array<QPushButton*, 4> controller_color_buttons;
- std::array<QColor, 4> controller_colors;
+ /// Bottom row is where console wide settings are held, and its "owned" by the parent
+ /// ConfigureInput widget. On show, add this widget to the main layout. This will change the
+ /// parent of the widget to this widget (but thats fine).
+ QWidget* bottom_row;
};
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
index f27a77180..e03461d9d 100644
--- a/src/yuzu/configuration/configure_input_player.ui
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -1,1243 +1,3075 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureInputPlayer</class>
- <widget class="QDialog" name="ConfigureInputPlayer">
+ <widget class="QWidget" name="ConfigureInputPlayer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
- <width>408</width>
- <height>731</height>
+ <width>780</width>
+ <height>487</height>
</rect>
</property>
<property name="windowTitle">
<string>Configure Input</string>
</property>
- <layout class="QVBoxLayout" name="verticalLayout_5">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
<item>
- <layout class="QGridLayout" name="buttons">
- <item row="1" column="1">
- <widget class="QGroupBox" name="RStick">
- <property name="title">
- <string>Right Stick</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
- </property>
- <property name="flat">
- <bool>false</bool>
+ <layout class="QVBoxLayout" name="main">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="top" stretch="0,1,2">
+ <property name="spacing">
+ <number>3</number>
</property>
- <property name="checkable">
- <bool>false</bool>
+ <property name="topMargin">
+ <number>0</number>
</property>
- <layout class="QGridLayout" name="gridLayout_5">
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonRStickDownVerticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupConnectedController">
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="title">
+ <string>Connect Controller</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="leftMargin">
+ <number>5</number>
+ </property>
+ <property name="topMargin">
+ <number>5</number>
+ </property>
+ <property name="rightMargin">
+ <number>5</number>
+ </property>
+ <property name="bottomMargin">
+ <number>5</number>
+ </property>
<item>
- <layout class="QHBoxLayout" name="buttonRStickDownHorizontalLayout">
+ <widget class="QComboBox" name="comboControllerType">
<item>
- <widget class="QLabel" name="labelRStickDown">
- <property name="text">
- <string>Down:</string>
- </property>
- </widget>
+ <property name="text">
+ <string>Pro Controller</string>
+ </property>
</item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickDown">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonRStickRightVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonRStickRightHorizontalLayout">
<item>
- <widget class="QLabel" name="labelRStickRight">
- <property name="text">
- <string>Right:</string>
- </property>
- </widget>
+ <property name="text">
+ <string>Dual Joycons</string>
+ </property>
</item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickRight">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="3" column="0" colspan="2">
- <widget class="QPushButton" name="buttonRStickAnalog">
- <property name="text">
- <string>Set Analog Stick</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonRStickLeftVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonRStickLeftHorizontalLayout">
<item>
- <widget class="QLabel" name="labelRStickLeft">
- <property name="text">
- <string>Left:</string>
- </property>
- </widget>
+ <property name="text">
+ <string>Left Joycon</string>
+ </property>
</item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickLeft">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonRStickUpVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonRStickUpHorizontalLayout">
<item>
- <widget class="QLabel" name="labelRStickUp">
- <property name="text">
- <string>Up:</string>
- </property>
- </widget>
+ <property name="text">
+ <string>Right Joycon</string>
+ </property>
</item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickUp">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="2" column="0">
- <layout class="QVBoxLayout" name="buttonRStickPressedVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonRStickPressedHorizontalLayout">
<item>
- <widget class="QLabel" name="labelRStickPressed">
- <property name="text">
- <string>Pressed:</string>
- </property>
- </widget>
+ <property name="text">
+ <string>Handheld</string>
+ </property>
</item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStick">
- <property name="text">
- <string/>
- </property>
</widget>
</item>
</layout>
- </item>
- <item row="2" column="1">
- <layout class="QVBoxLayout" name="buttonRStickModVerticalLayout">
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="devicesGroup">
+ <property name="title">
+ <string>Input Device</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>5</number>
+ </property>
+ <property name="topMargin">
+ <number>5</number>
+ </property>
+ <property name="rightMargin">
+ <number>5</number>
+ </property>
+ <property name="bottomMargin">
+ <number>5</number>
+ </property>
<item>
- <layout class="QHBoxLayout" name="buttonRStickModHorizontalLayout">
+ <widget class="QComboBox" name="comboDevices">
<item>
- <widget class="QLabel" name="labelRStickMod">
- <property name="text">
- <string>Modifier:</string>
- </property>
- </widget>
+ <property name="text">
+ <string>Any</string>
+ </property>
</item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRStickMod">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="4" column="0" colspan="2">
- <layout class="QVBoxLayout" name="sliderRStickDeadzoneAndModifierVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="sliderRStickDeadzoneAndModifierHorizontalLayout">
<item>
- <widget class="QLabel" name="labelRStickDeadzoneAndModifier">
- <property name="text">
- <string>Deadzone: 0</string>
- </property>
- <property name="alignment">
- <enum>Qt::AlignHCenter</enum>
- </property>
- </widget>
+ <property name="text">
+ <string>Keyboard/Mouse</string>
+ </property>
</item>
- </layout>
+ </widget>
</item>
<item>
- <widget class="QSlider" name="sliderRStickDeadzoneAndModifier">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <widget class="QPushButton" name="buttonRefreshDevices">
+ <property name="minimumSize">
+ <size>
+ <width>24</width>
+ <height>22</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>24</width>
+ <height>22</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
</property>
</widget>
</item>
</layout>
- </item>
- <item row="5" column="0">
- <spacer name="RStick_verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="profilesGroup">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Profile</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="2,0,0,0">
+ <property name="spacing">
+ <number>3</number>
</property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
+ <property name="leftMargin">
+ <number>5</number>
+ </property>
+ <property name="topMargin">
+ <number>5</number>
+ </property>
+ <property name="rightMargin">
+ <number>5</number>
+ </property>
+ <property name="bottomMargin">
+ <number>5</number>
</property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QGroupBox" name="Dpad">
- <property name="title">
- <string>Directional Pad</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonDpadUpVerticalLayout">
<item>
- <layout class="QHBoxLayout" name="buttonDpadUpHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelDpadUp">
- <property name="text">
- <string>Up:</string>
- </property>
- </widget>
- </item>
- </layout>
+ <widget class="QComboBox" name="comboProfiles"/>
</item>
<item>
- <widget class="QPushButton" name="buttonDpadUp">
- <property name="text">
- <string/>
+ <widget class="QPushButton" name="buttonProfilesSave">
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonDpadDownVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonDpadDownHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelDpadDown">
- <property name="text">
- <string>Down:</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonDpadDown">
<property name="text">
- <string/>
+ <string>Save</string>
</property>
</widget>
</item>
- </layout>
- </item>
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonDpadLeftHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelDpadLeft">
- <property name="minimumSize">
- <size>
- <width>80</width>
- <height>0</height>
- </size>
- </property>
- <property name="text">
- <string>Left:</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
<item>
- <widget class="QPushButton" name="buttonDpadLeft">
+ <widget class="QPushButton" name="buttonProfilesNew">
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
<property name="text">
- <string/>
+ <string>New</string>
</property>
</widget>
</item>
- </layout>
- </item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonDpadRightHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelDpadRight">
- <property name="minimumSize">
- <size>
- <width>80</width>
- <height>0</height>
- </size>
- </property>
- <property name="text">
- <string>Right:</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
<item>
- <widget class="QPushButton" name="buttonDpadRight">
+ <widget class="QPushButton" name="buttonProfilesDelete">
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
<property name="text">
- <string/>
+ <string>Delete</string>
</property>
</widget>
</item>
</layout>
- </item>
- </layout>
- </widget>
+ </widget>
+ </item>
+ </layout>
</item>
- <item row="0" column="0">
- <widget class="QGroupBox" name="faceButtons">
- <property name="title">
- <string>Face Buttons</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- <property name="checkable">
- <bool>false</bool>
+ <item>
+ <widget class="QFrame" name="bottom">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonFaceButtonsAVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonFaceButtonsAHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelA">
- <property name="minimumSize">
- <size>
- <width>80</width>
- <height>0</height>
- </size>
+ <layout class="QHBoxLayout" name="_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="bottomLeft" native="true">
+ <layout class="QVBoxLayout" name="bottomLeftLayout" stretch="0,0,0,0">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="LStick">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Left Stick</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>0</number>
</property>
- <property name="text">
- <string>A:</string>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonA">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonFaceButtonsBVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonFaceButtonsBHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelB">
- <property name="minimumSize">
- <size>
- <width>80</width>
- <height>0</height>
- </size>
+ <property name="leftMargin">
+ <number>3</number>
</property>
- <property name="text">
- <string>B:</string>
+ <property name="topMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonB">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonFaceButtonsXVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonFaceButtonsXHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelX">
- <property name="text">
- <string>X:</string>
+ <property name="rightMargin">
+ <number>3</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonX">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonFaceButtonsYVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonFaceButtonsYHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelY">
- <property name="text">
- <string>Y:</string>
+ <property name="bottomMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonY">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item row="5" column="0" colspan="2">
- <widget class="QGroupBox" name="controller_color">
- <property name="title">
- <string>Controller Color</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_10" columnstretch="0,0,0,0,0,0,0">
- <item row="0" column="0">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="left_body_label">
- <property name="text">
- <string>Left Body</string>
- </property>
- </widget>
- </item>
- <item row="0" column="6">
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="left_buttons_label">
- <property name="minimumSize">
- <size>
- <width>90</width>
- <height>0</height>
- </size>
- </property>
- <property name="text">
- <string>Left Buttons</string>
- </property>
- </widget>
- </item>
- <item row="1" column="5">
- <widget class="QPushButton" name="right_buttons_button">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>32</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>40</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="4">
- <widget class="QLabel" name="right_body_label">
- <property name="text">
- <string>Right Body</string>
- </property>
- </widget>
- </item>
- <item row="1" column="4">
- <widget class="QLabel" name="right_buttons_label">
- <property name="minimumSize">
- <size>
- <width>90</width>
- <height>0</height>
- </size>
- </property>
- <property name="text">
- <string>Right Buttons</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QPushButton" name="left_buttons_button">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>32</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>40</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QPushButton" name="left_body_button">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>32</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>40</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="5">
- <widget class="QPushButton" name="right_body_button">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>32</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>40</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QGroupBox" name="LStick">
- <property name="title">
- <string>Left Stick</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_4">
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonLStickUpVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonLStickUpHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelLStickUp">
- <property name="text">
- <string>Up:</string>
+ <item>
+ <widget class="QWidget" name="buttonLStickUpWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_20">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerLStickUpLeft">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonLStickUpGroup">
+ <property name="title">
+ <string>Up</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="buttonLStickUpVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonLStickUp">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Up</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacerLStickUpRight">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="buttonLStickLeftRightHorizontaLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonLStickLeftGroup">
+ <property name="title">
+ <string>Left</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonLStickLeftVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonLStickLeft">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Left</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonLStickRightGroup">
+ <property name="title">
+ <string>Right</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonLStickRightVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonLStickRight">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Right</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonLStickDownWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_22">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerLStickDownLeft">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonLStickDownGroup">
+ <property name="title">
+ <string>Down</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonLStickDownVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonLStickDown">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Down</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacerLStickDownRight">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="buttonLStickPressedModifierHorizontalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonLStickPressedGroup">
+ <property name="title">
+ <string>Pressed</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonLStickPressedVerticalLayout" stretch="0">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonLStick">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Pressed</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonLStickModGroup">
+ <property name="title">
+ <string>Modifier</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonLStickModVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonLStickMod">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Modifier</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="buttonLStickRangeGroup">
+ <property name="title">
+ <string>Range</string>
+ </property>
+ <layout class="QHBoxLayout" name="buttonLStickRangeGroupHorizontalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QSpinBox" name="spinboxLStickRange">
+ <property name="minimumSize">
+ <size>
+ <width>55</width>
+ <height>21</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>50</number>
+ </property>
+ <property name="maximum">
+ <number>150</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="sliderLStickDeadzoneModifierRangeVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="sliderLStickDeadzoneHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelLStickDeadzone">
+ <property name="text">
+ <string>Deadzone: 0%</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignHCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QSlider" name="sliderLStickDeadzone">
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="sliderLStickModifierRangeHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelLStickModifierRange">
+ <property name="text">
+ <string>Modifier Range: 0%</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignHCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QSlider" name="sliderLStickModifierRange">
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacerBottomLeft">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="Dpad">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>D-Pad</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <property name="spacing">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickUp">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="2">
- <layout class="QVBoxLayout" name="buttonLStickRightVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonLStickRightHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelLStickRight">
- <property name="text">
- <string>Right:</string>
+ <property name="leftMargin">
+ <number>3</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickRight">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="4" column="1" colspan="2">
- <widget class="QPushButton" name="buttonLStickAnalog">
- <property name="text">
- <string>Set Analog Stick</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonLStickLeftVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonLStickLeftHorizontalLayout_2">
- <item>
- <widget class="QLabel" name="labelLStickLeft">
- <property name="text">
- <string>Left:</string>
+ <property name="topMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickLeft">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="2">
- <layout class="QVBoxLayout" name="buttonLStickDownVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonLStickDownHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelLStickDown">
- <property name="text">
- <string>Down:</string>
+ <property name="rightMargin">
+ <number>3</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickDown">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="3" column="2">
- <layout class="QVBoxLayout" name="buttonLStickModVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonLStickModHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelLStickMod">
- <property name="text">
- <string>Modifier:</string>
+ <property name="bottomMargin">
+ <number>3</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStickMod">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item>
+ <widget class="QWidget" name="buttonDpadUpWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_23">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerDpadUpLeft">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonDpadUpGroup">
+ <property name="title">
+ <string>Up</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonDpadUpVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonDpadUp">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Up</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacerDpadUpRight">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="buttonDpadLeftRightHorizontalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonDpadLeftGroup">
+ <property name="title">
+ <string>Left</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonDpadLeft">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Left</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonDpadRightGroup">
+ <property name="title">
+ <string>Right</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonDpadRight">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Right</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonDpadDownWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_24">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerDpadDownLeft">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonDpadDownGroup">
+ <property name="title">
+ <string>Down</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonDpadDownVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonDpadDown">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Down</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacerDpadDownRight">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacerBottomLeft_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
</item>
- <item row="3" column="1">
- <layout class="QVBoxLayout" name="buttonLStickPressedVerticalLayout" stretch="0,0">
- <item>
- <layout class="QHBoxLayout" name="buttonLStickPressedHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelLStickPressed">
- <property name="text">
- <string>Pressed:</string>
+ <item>
+ <widget class="QWidget" name="bottomMiddle" native="true">
+ <layout class="QVBoxLayout" stretch="0,0,0">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="shoulderButtons">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="buttonShoulderButtonsLeft" native="true">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsLeftVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="buttonShoulderButtonsButtonLGroup">
+ <property name="title">
+ <string>L</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsLVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonL">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>L</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="buttonShoulderButtonsButtonZLGroup">
+ <property name="title">
+ <string>ZL</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsZLVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonZL">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>ZL</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidgetLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerShoulderButtons1">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonMiscButtonsMinusScreenshot" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsMinusScreenshotVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonMiscButtonsMinusGroup">
+ <property name="title">
+ <string>Minus</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonMiscMinusVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonMinus">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Minus</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonMiscButtonsScreenshotGroup">
+ <property name="title">
+ <string>Capture</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonMiscScrCapVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonScreenshot">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Capture</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonMiscButtonsPlusHome" native="true">
+ <layout class="QVBoxLayout" name="buttonMiscButtonsPlusHomeVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonMiscButtonsPlusGroup">
+ <property name="title">
+ <string>Plus</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonMiscPlusVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonPlus">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Plus</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonMiscButtonsHomeGroup">
+ <property name="title">
+ <string>Home</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonMiscHomeVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonHome">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Home</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget3" native="true">
+ <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidget3Layout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerShoulderButtons2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonShoulderButtonsRight" native="true">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsRightVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="buttonShoulderButtonsRGroup">
+ <property name="title">
+ <string>R</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsRVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonR">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>R</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="buttonShoulderButtonsZRGroup">
+ <property name="title">
+ <string>ZR</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsZRVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonZR">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>ZR</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget2" native="true">
+ <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidget2Layout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerShoulderButtons3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonShoulderButtonsSLSR" native="true">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSLGroup">
+ <property name="title">
+ <string>SL</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSL">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>SL</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSRGroup">
+ <property name="title">
+ <string>SR</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSR">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>SR</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QFrame" name="controllerFrame">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">image: url(:/controller/pro);</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="leftMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonLStick">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="5" column="1" colspan="2">
- <layout class="QVBoxLayout" name="sliderLStickDeadzoneAndModifierVerticalLayout">
- <property name="sizeConstraint">
- <enum>QLayout::SetDefaultConstraint</enum>
- </property>
- <item>
- <layout class="QHBoxLayout" name="sliderLStickDeadzoneAndModifierHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelLStickDeadzoneAndModifier">
- <property name="text">
- <string>Deadzone: 0</string>
+ <property name="topMargin">
+ <number>0</number>
</property>
- <property name="alignment">
- <enum>Qt::AlignHCenter</enum>
+ <property name="rightMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QSlider" name="sliderLStickDeadzoneAndModifier">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="6" column="1">
- <spacer name="LStick_verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QGroupBox" name="shoulderButtons">
- <property name="title">
- <string>Shoulder Buttons</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsLVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonShoulderButtonsLHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelL">
- <property name="text">
- <string>L:</string>
+ <property name="bottomMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonL">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="miscButtons">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerMiscButtons1">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="buttonMotionLeftGroup">
+ <property name="title">
+ <string>Motion 1</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout_2">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonMotionLeft">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Left</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="buttonMotionRightGroup">
+ <property name="title">
+ <string>Motion 2</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout_2">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonMotionRight">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Right</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacerMiscButtons4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
</item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsRVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonShoulderButtonsRHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelR">
- <property name="text">
- <string>R:</string>
+ <item>
+ <widget class="QWidget" name="bottomRight" native="true">
+ <layout class="QVBoxLayout" name="bottomRightLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="faceButtons">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Face Buttons</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonR">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsZLVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonShoulderButtonsZLHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelZL">
- <property name="text">
- <string>ZL:</string>
+ <property name="leftMargin">
+ <number>3</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonZL">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsZRVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonShoulderButtonsZRHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelZR">
- <property name="text">
- <string>ZR:</string>
+ <property name="topMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonZR">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="2">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonShoulderButtonsSLHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelSL">
- <property name="text">
- <string>SL:</string>
+ <property name="rightMargin">
+ <number>3</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonSL">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="2">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonShoulderButtonsSRHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelSR">
- <property name="text">
- <string>SR:</string>
+ <property name="bottomMargin">
+ <number>3</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonSR">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QGroupBox" name="misc">
- <property name="title">
- <string>Misc.</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_6">
- <item row="1" column="0">
- <layout class="QVBoxLayout" name="buttonMiscMinusVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonMiscMinusHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelMinus">
- <property name="text">
- <string>Minus:</string>
+ <item>
+ <widget class="QWidget" name="buttonFaceButtonsBWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerBLeft">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonFaceButtonsXGroup">
+ <property name="title">
+ <string>X</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonFaceButtonsXVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonX">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>X</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacerBRight">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="buttonFaceButtonsYAHorizontalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonFaceButtonsYGroup">
+ <property name="title">
+ <string>Y</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonFaceButtonsYVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonY">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Y</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonFaceButtonsAGroup">
+ <property name="title">
+ <string>A</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonFaceButtonsAVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonA">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>A</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonFaceButtonsXWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_10">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerXLeft">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonFaceButtonsBWidget_2">
+ <property name="title">
+ <string>B</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonFaceButtonsBVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonB">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>B</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacerXRight">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacerBottomRight">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="RStick">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Right Stick</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonMinus">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="3" column="1">
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="buttonMiscPlusVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonMiscPlusHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelPlus">
- <property name="text">
- <string>Plus:</string>
+ <property name="leftMargin">
+ <number>3</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonPlus">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="buttonMiscHomeVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonMiscHomeHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelHome">
- <property name="text">
- <string>Home:</string>
+ <property name="topMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonHome">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="1">
- <layout class="QVBoxLayout" name="buttonMiscScrCapVerticalLayout">
- <item>
- <layout class="QHBoxLayout" name="buttonMiscScrCapHorizontalLayout">
- <item>
- <widget class="QLabel" name="labelScreenshot">
- <property name="text">
- <string>Screen Capture:</string>
+ <property name="rightMargin">
+ <number>3</number>
</property>
- <property name="wordWrap">
- <bool>false</bool>
+ <property name="bottomMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="buttonScreenshot">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="maximumSize">
- <size>
- <width>80</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
+ <item>
+ <widget class="QWidget" name="buttonRStickUpWidget" native="true">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_9">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerRStickUpLeft">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonRStickUpGroup">
+ <property name="title">
+ <string>Up</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonRStickUpVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonRStickUp">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Up</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacerRStickUpRight">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="buttonRStickLeftRightHorizontalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonRStickLeftGroup">
+ <property name="title">
+ <string>Left</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonRStickLeftVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonRStickLeft">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Left</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonRStickRightGroup">
+ <property name="title">
+ <string>Right</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonRStickRightVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonRStickRight">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Right</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonRStickDownWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_11">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerRStickDownLeft">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="buttonRStickDownGroup">
+ <property name="title">
+ <string>Down</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonRStickDownVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonRStickDown">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Down</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacerRStickDownRight">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="buttonRStickPressedModifierHorizontalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="groupRStickPressed">
+ <property name="title">
+ <string>Pressed</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonRStickPressedVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonRStick">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Pressed</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonRStickModGroup">
+ <property name="title">
+ <string>Modifier</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonRStickModVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonRStickMod">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 55px;</string>
+ </property>
+ <property name="text">
+ <string>Modifier</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="buttonRStickRangeGroup">
+ <property name="title">
+ <string>Range</string>
+ </property>
+ <layout class="QHBoxLayout" name="buttonRStickRangeGroupHorizontalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QSpinBox" name="spinboxRStickRange">
+ <property name="minimumSize">
+ <size>
+ <width>55</width>
+ <height>21</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>50</number>
+ </property>
+ <property name="maximum">
+ <number>150</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="sliderRStickDeadzoneModifierRangeVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="sliderRStickDeadzoneHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelRStickDeadzone">
+ <property name="text">
+ <string>Deadzone: 0%</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignHCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QSlider" name="sliderRStickDeadzone">
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="sliderRStickModifierRangeHorizontalLayout">
+ <item>
+ <widget class="QLabel" name="labelRStickModifierRange">
+ <property name="text">
+ <string>Modifier Range: 0%</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignHCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QSlider" name="sliderRStickModifierRange">
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacerBottomRight_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout"/>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QPushButton" name="buttonClearAll">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="sizeIncrement">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="baseSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="layoutDirection">
- <enum>Qt::LeftToRight</enum>
- </property>
- <property name="text">
- <string>Clear All</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonRestoreDefaults">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="sizeIncrement">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="baseSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="layoutDirection">
- <enum>Qt::LeftToRight</enum>
- </property>
- <property name="text">
- <string>Restore Defaults</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </item>
</layout>
</widget>
- <resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>ConfigureInputPlayer</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>371</x>
- <y>730</y>
- </hint>
- <hint type="destinationlabel">
- <x>229</x>
- <y>375</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>ConfigureInputPlayer</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>371</x>
- <y>730</y>
- </hint>
- <hint type="destinationlabel">
- <x>229</x>
- <y>375</y>
- </hint>
- </hints>
- </connection>
- </connections>
+ <resources>
+ <include location="../../../dist/icons/controller/controller.qrc"/>
+ </resources>
+ <connections/>
</ui>
diff --git a/src/yuzu/configuration/configure_input_simple.cpp b/src/yuzu/configuration/configure_input_simple.cpp
deleted file mode 100644
index 0e0e8f113..000000000
--- a/src/yuzu/configuration/configure_input_simple.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <array>
-#include <tuple>
-
-#include "ui_configure_input_simple.h"
-#include "yuzu/configuration/configure_input.h"
-#include "yuzu/configuration/configure_input_player.h"
-#include "yuzu/configuration/configure_input_simple.h"
-#include "yuzu/uisettings.h"
-
-namespace {
-
-template <typename Dialog, typename... Args>
-void CallConfigureDialog(ConfigureInputSimple* caller, Args&&... args) {
- caller->ApplyConfiguration();
- Dialog dialog(caller, std::forward<Args>(args)...);
-
- const auto res = dialog.exec();
- if (res == QDialog::Accepted) {
- dialog.ApplyConfiguration();
- }
-}
-
-// OnProfileSelect functions should (when applicable):
-// - Set controller types
-// - Set controller enabled
-// - Set docked mode
-// - Set advanced controller config/enabled (i.e. debug, kbd, mouse, touch)
-//
-// OnProfileSelect function should NOT however:
-// - Reset any button mappings
-// - Open any dialogs
-// - Block in any way
-
-constexpr std::size_t PLAYER_0_INDEX = 0;
-constexpr std::size_t HANDHELD_INDEX = 8;
-
-void HandheldOnProfileSelect() {
- Settings::values.players[HANDHELD_INDEX].connected = true;
- Settings::values.players[HANDHELD_INDEX].type = Settings::ControllerType::DualJoycon;
-
- for (std::size_t player = 0; player < HANDHELD_INDEX; ++player) {
- Settings::values.players[player].connected = false;
- }
-
- Settings::values.use_docked_mode = false;
- Settings::values.keyboard_enabled = false;
- Settings::values.mouse_enabled = false;
- Settings::values.debug_pad_enabled = false;
- Settings::values.touchscreen.enabled = true;
-}
-
-void DualJoyconsDockedOnProfileSelect() {
- Settings::values.players[PLAYER_0_INDEX].connected = true;
- Settings::values.players[PLAYER_0_INDEX].type = Settings::ControllerType::DualJoycon;
-
- for (std::size_t player = 1; player <= HANDHELD_INDEX; ++player) {
- Settings::values.players[player].connected = false;
- }
-
- Settings::values.use_docked_mode = true;
- Settings::values.keyboard_enabled = false;
- Settings::values.mouse_enabled = false;
- Settings::values.debug_pad_enabled = false;
- Settings::values.touchscreen.enabled = true;
-}
-
-// Name, OnProfileSelect (called when selected in drop down), OnConfigure (called when configure
-// is clicked)
-using InputProfile = std::tuple<const char*, void (*)(), void (*)(ConfigureInputSimple*)>;
-
-constexpr std::array<InputProfile, 3> INPUT_PROFILES{{
- {QT_TR_NOOP("Single Player - Handheld - Undocked"), HandheldOnProfileSelect,
- [](ConfigureInputSimple* caller) {
- CallConfigureDialog<ConfigureInputPlayer>(caller, HANDHELD_INDEX, false);
- }},
- {QT_TR_NOOP("Single Player - Dual Joycons - Docked"), DualJoyconsDockedOnProfileSelect,
- [](ConfigureInputSimple* caller) {
- CallConfigureDialog<ConfigureInputPlayer>(caller, PLAYER_0_INDEX, false);
- }},
- {QT_TR_NOOP("Custom"), [] {}, CallConfigureDialog<ConfigureInput>},
-}};
-
-} // namespace
-
-void ApplyInputProfileConfiguration(int profile_index) {
- std::get<1>(
- INPUT_PROFILES.at(std::min(profile_index, static_cast<int>(INPUT_PROFILES.size() - 1))))();
-}
-
-ConfigureInputSimple::ConfigureInputSimple(QWidget* parent)
- : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputSimple>()) {
- ui->setupUi(this);
-
- for (const auto& profile : INPUT_PROFILES) {
- const QString label = tr(std::get<0>(profile));
- ui->profile_combobox->addItem(label, label);
- }
-
- connect(ui->profile_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
- &ConfigureInputSimple::OnSelectProfile);
- connect(ui->profile_configure, &QPushButton::clicked, this, &ConfigureInputSimple::OnConfigure);
-
- LoadConfiguration();
-}
-
-ConfigureInputSimple::~ConfigureInputSimple() = default;
-
-void ConfigureInputSimple::ApplyConfiguration() {
- auto index = ui->profile_combobox->currentIndex();
- // Make the stored index for "Custom" very large so that if new profiles are added it
- // doesn't change.
- if (index >= static_cast<int>(INPUT_PROFILES.size() - 1)) {
- index = std::numeric_limits<int>::max();
- }
-
- UISettings::values.profile_index = index;
-}
-
-void ConfigureInputSimple::changeEvent(QEvent* event) {
- if (event->type() == QEvent::LanguageChange) {
- RetranslateUI();
- }
-
- QWidget::changeEvent(event);
-}
-
-void ConfigureInputSimple::RetranslateUI() {
- ui->retranslateUi(this);
-}
-
-void ConfigureInputSimple::LoadConfiguration() {
- const auto index = UISettings::values.profile_index;
- if (index >= static_cast<int>(INPUT_PROFILES.size()) || index < 0) {
- ui->profile_combobox->setCurrentIndex(static_cast<int>(INPUT_PROFILES.size() - 1));
- } else {
- ui->profile_combobox->setCurrentIndex(index);
- }
-}
-
-void ConfigureInputSimple::OnSelectProfile(int index) {
- const auto old_docked = Settings::values.use_docked_mode;
- ApplyInputProfileConfiguration(index);
- OnDockedModeChanged(old_docked, Settings::values.use_docked_mode);
-}
-
-void ConfigureInputSimple::OnConfigure() {
- std::get<2>(INPUT_PROFILES.at(ui->profile_combobox->currentIndex()))(this);
-}
diff --git a/src/yuzu/configuration/configure_input_simple.h b/src/yuzu/configuration/configure_input_simple.h
deleted file mode 100644
index bb5050224..000000000
--- a/src/yuzu/configuration/configure_input_simple.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-
-#include <QWidget>
-
-class QPushButton;
-class QString;
-class QTimer;
-
-namespace Ui {
-class ConfigureInputSimple;
-}
-
-// Used by configuration loader to apply a profile if the input is invalid.
-void ApplyInputProfileConfiguration(int profile_index);
-
-class ConfigureInputSimple : public QWidget {
- Q_OBJECT
-
-public:
- explicit ConfigureInputSimple(QWidget* parent = nullptr);
- ~ConfigureInputSimple() override;
-
- /// Save all button configurations to settings file
- void ApplyConfiguration();
-
-private:
- void changeEvent(QEvent* event) override;
- void RetranslateUI();
-
- /// Load configuration settings.
- void LoadConfiguration();
-
- void OnSelectProfile(int index);
- void OnConfigure();
-
- std::unique_ptr<Ui::ConfigureInputSimple> ui;
-};
diff --git a/src/yuzu/configuration/configure_input_simple.ui b/src/yuzu/configuration/configure_input_simple.ui
deleted file mode 100644
index c4889caa9..000000000
--- a/src/yuzu/configuration/configure_input_simple.ui
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ConfigureInputSimple</class>
- <widget class="QWidget" name="ConfigureInputSimple">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>473</width>
- <height>685</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>ConfigureInputSimple</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_5">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="gridGroupBox">
- <property name="title">
- <string>Profile</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="1" column="2">
- <widget class="QPushButton" name="profile_configure">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="3">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="1">
- <widget class="QComboBox" name="profile_combobox">
- <property name="minimumSize">
- <size>
- <width>250</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- </item>
- <item row="0" column="1" colspan="2">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Choose a controller configuration:</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
new file mode 100644
index 000000000..170574d9b
--- /dev/null
+++ b/src/yuzu/configuration/configure_motion_touch.cpp
@@ -0,0 +1,314 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <array>
+#include <QCloseEvent>
+#include <QLabel>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include "common/logging/log.h"
+#include "core/settings.h"
+#include "input_common/main.h"
+#include "input_common/udp/client.h"
+#include "input_common/udp/udp.h"
+#include "ui_configure_motion_touch.h"
+#include "yuzu/configuration/configure_motion_touch.h"
+#include "yuzu/configuration/configure_touch_from_button.h"
+
+CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
+ const std::string& host, u16 port,
+ u8 pad_index, u16 client_id)
+ : QDialog(parent) {
+ layout = new QVBoxLayout;
+ status_label = new QLabel(tr("Communicating with the server..."));
+ cancel_button = new QPushButton(tr("Cancel"));
+ connect(cancel_button, &QPushButton::clicked, this, [this] {
+ if (!completed) {
+ job->Stop();
+ }
+ accept();
+ });
+ layout->addWidget(status_label);
+ layout->addWidget(cancel_button);
+ setLayout(layout);
+
+ using namespace InputCommon::CemuhookUDP;
+ job = std::make_unique<CalibrationConfigurationJob>(
+ host, port, pad_index, client_id,
+ [this](CalibrationConfigurationJob::Status status) {
+ QString text;
+ switch (status) {
+ case CalibrationConfigurationJob::Status::Ready:
+ text = tr("Touch the top left corner <br>of your touchpad.");
+ break;
+ case CalibrationConfigurationJob::Status::Stage1Completed:
+ text = tr("Now touch the bottom right corner <br>of your touchpad.");
+ break;
+ case CalibrationConfigurationJob::Status::Completed:
+ text = tr("Configuration completed!");
+ break;
+ }
+ QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text));
+ if (status == CalibrationConfigurationJob::Status::Completed) {
+ QMetaObject::invokeMethod(this, "UpdateButtonText", Q_ARG(QString, tr("OK")));
+ }
+ },
+ [this](u16 min_x_, u16 min_y_, u16 max_x_, u16 max_y_) {
+ completed = true;
+ min_x = min_x_;
+ min_y = min_y_;
+ max_x = max_x_;
+ max_y = max_y_;
+ });
+}
+
+CalibrationConfigurationDialog::~CalibrationConfigurationDialog() = default;
+
+void CalibrationConfigurationDialog::UpdateLabelText(const QString& text) {
+ status_label->setText(text);
+}
+
+void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) {
+ cancel_button->setText(text);
+}
+
+constexpr std::array<std::pair<const char*, const char*>, 2> MotionProviders = {{
+ {"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")},
+ {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
+}};
+
+constexpr std::array<std::pair<const char*, const char*>, 2> TouchProviders = {{
+ {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")},
+ {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
+}};
+
+ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
+ InputCommon::InputSubsystem* input_subsystem_)
+ : QDialog(parent), input_subsystem{input_subsystem_},
+ ui(std::make_unique<Ui::ConfigureMotionTouch>()) {
+ ui->setupUi(this);
+ for (const auto& [provider, name] : MotionProviders) {
+ ui->motion_provider->addItem(tr(name), QString::fromUtf8(provider));
+ }
+ for (const auto& [provider, name] : TouchProviders) {
+ ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider));
+ }
+
+ ui->udp_learn_more->setOpenExternalLinks(true);
+ ui->udp_learn_more->setText(
+ tr("<a "
+ "href='https://yuzu-emu.org/wiki/"
+ "using-a-controller-or-android-phone-for-motion-or-touch-input'><span "
+ "style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>"));
+
+ SetConfiguration();
+ UpdateUiDisplay();
+ ConnectEvents();
+}
+
+ConfigureMotionTouch::~ConfigureMotionTouch() = default;
+
+void ConfigureMotionTouch::SetConfiguration() {
+ const Common::ParamPackage motion_param(Settings::values.motion_device);
+ const Common::ParamPackage touch_param(Settings::values.touch_device);
+ const std::string motion_engine = motion_param.Get("engine", "motion_emu");
+ const std::string touch_engine = touch_param.Get("engine", "emu_window");
+
+ ui->motion_provider->setCurrentIndex(
+ ui->motion_provider->findData(QString::fromStdString(motion_engine)));
+ ui->touch_provider->setCurrentIndex(
+ ui->touch_provider->findData(QString::fromStdString(touch_engine)));
+ ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button);
+ touch_from_button_maps = Settings::values.touch_from_button_maps;
+ for (const auto& touch_map : touch_from_button_maps) {
+ ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
+ }
+ ui->touch_from_button_map->setCurrentIndex(Settings::values.touch_from_button_map_index);
+ ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f));
+
+ min_x = touch_param.Get("min_x", 100);
+ min_y = touch_param.Get("min_y", 50);
+ max_x = touch_param.Get("max_x", 1800);
+ max_y = touch_param.Get("max_y", 850);
+
+ ui->udp_server->setText(QString::fromStdString(Settings::values.udp_input_address));
+ ui->udp_port->setText(QString::number(Settings::values.udp_input_port));
+ ui->udp_pad_index->setCurrentIndex(Settings::values.udp_pad_index);
+}
+
+void ConfigureMotionTouch::UpdateUiDisplay() {
+ const QString motion_engine = ui->motion_provider->currentData().toString();
+ const QString touch_engine = ui->touch_provider->currentData().toString();
+ const QString cemuhook_udp = QStringLiteral("cemuhookudp");
+
+ if (motion_engine == QStringLiteral("motion_emu")) {
+ ui->motion_sensitivity_label->setVisible(true);
+ ui->motion_sensitivity->setVisible(true);
+ } else {
+ ui->motion_sensitivity_label->setVisible(false);
+ ui->motion_sensitivity->setVisible(false);
+ }
+
+ if (touch_engine == cemuhook_udp) {
+ ui->touch_calibration->setVisible(true);
+ ui->touch_calibration_config->setVisible(true);
+ ui->touch_calibration_label->setVisible(true);
+ ui->touch_calibration->setText(
+ QStringLiteral("(%1, %2) - (%3, %4)").arg(min_x).arg(min_y).arg(max_x).arg(max_y));
+ } else {
+ ui->touch_calibration->setVisible(false);
+ ui->touch_calibration_config->setVisible(false);
+ ui->touch_calibration_label->setVisible(false);
+ }
+
+ if (motion_engine == cemuhook_udp || touch_engine == cemuhook_udp) {
+ ui->udp_config_group_box->setVisible(true);
+ } else {
+ ui->udp_config_group_box->setVisible(false);
+ }
+}
+
+void ConfigureMotionTouch::ConnectEvents() {
+ connect(ui->motion_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
+ [this](int index) { UpdateUiDisplay(); });
+ connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
+ [this](int index) { UpdateUiDisplay(); });
+ connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest);
+ connect(ui->touch_calibration_config, &QPushButton::clicked, this,
+ &ConfigureMotionTouch::OnConfigureTouchCalibration);
+ connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this,
+ &ConfigureMotionTouch::OnConfigureTouchFromButton);
+ connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] {
+ if (CanCloseDialog()) {
+ reject();
+ }
+ });
+}
+
+void ConfigureMotionTouch::OnCemuhookUDPTest() {
+ ui->udp_test->setEnabled(false);
+ ui->udp_test->setText(tr("Testing"));
+ udp_test_in_progress = true;
+ InputCommon::CemuhookUDP::TestCommunication(
+ ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()),
+ static_cast<u32>(ui->udp_pad_index->currentIndex()), 24872,
+ [this] {
+ LOG_INFO(Frontend, "UDP input test success");
+ QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));
+ },
+ [this] {
+ LOG_ERROR(Frontend, "UDP input test failed");
+ QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, false));
+ });
+}
+
+void ConfigureMotionTouch::OnConfigureTouchCalibration() {
+ ui->touch_calibration_config->setEnabled(false);
+ ui->touch_calibration_config->setText(tr("Configuring"));
+ CalibrationConfigurationDialog dialog(
+ this, ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toUInt()),
+ static_cast<u8>(ui->udp_pad_index->currentIndex()), 24872);
+ dialog.exec();
+ if (dialog.completed) {
+ min_x = dialog.min_x;
+ min_y = dialog.min_y;
+ max_x = dialog.max_x;
+ max_y = dialog.max_y;
+ LOG_INFO(Frontend,
+ "UDP touchpad calibration config success: min_x={}, min_y={}, max_x={}, max_y={}",
+ min_x, min_y, max_x, max_y);
+ UpdateUiDisplay();
+ } else {
+ LOG_ERROR(Frontend, "UDP touchpad calibration config failed");
+ }
+ ui->touch_calibration_config->setEnabled(true);
+ ui->touch_calibration_config->setText(tr("Configure"));
+}
+
+void ConfigureMotionTouch::closeEvent(QCloseEvent* event) {
+ if (CanCloseDialog()) {
+ event->accept();
+ } else {
+ event->ignore();
+ }
+}
+
+void ConfigureMotionTouch::ShowUDPTestResult(bool result) {
+ udp_test_in_progress = false;
+ if (result) {
+ QMessageBox::information(this, tr("Test Successful"),
+ tr("Successfully received data from the server."));
+ } else {
+ QMessageBox::warning(this, tr("Test Failed"),
+ tr("Could not receive valid data from the server.<br>Please verify "
+ "that the server is set up correctly and "
+ "the address and port are correct."));
+ }
+ ui->udp_test->setEnabled(true);
+ ui->udp_test->setText(tr("Test"));
+}
+
+void ConfigureMotionTouch::OnConfigureTouchFromButton() {
+ ConfigureTouchFromButton dialog{this, touch_from_button_maps, input_subsystem,
+ ui->touch_from_button_map->currentIndex()};
+ if (dialog.exec() != QDialog::Accepted) {
+ return;
+ }
+ touch_from_button_maps = dialog.GetMaps();
+
+ while (ui->touch_from_button_map->count() > 0) {
+ ui->touch_from_button_map->removeItem(0);
+ }
+ for (const auto& touch_map : touch_from_button_maps) {
+ ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
+ }
+ ui->touch_from_button_map->setCurrentIndex(dialog.GetSelectedIndex());
+}
+
+bool ConfigureMotionTouch::CanCloseDialog() {
+ if (udp_test_in_progress) {
+ QMessageBox::warning(this, tr("Citra"),
+ tr("UDP Test or calibration configuration is in progress.<br>Please "
+ "wait for them to finish."));
+ return false;
+ }
+ return true;
+}
+
+void ConfigureMotionTouch::ApplyConfiguration() {
+ if (!CanCloseDialog()) {
+ return;
+ }
+
+ std::string motion_engine = ui->motion_provider->currentData().toString().toStdString();
+ std::string touch_engine = ui->touch_provider->currentData().toString().toStdString();
+
+ Common::ParamPackage motion_param{}, touch_param{};
+ motion_param.Set("engine", std::move(motion_engine));
+ touch_param.Set("engine", std::move(touch_engine));
+
+ if (motion_engine == "motion_emu") {
+ motion_param.Set("sensitivity", static_cast<float>(ui->motion_sensitivity->value()));
+ }
+
+ if (touch_engine == "cemuhookudp") {
+ touch_param.Set("min_x", min_x);
+ touch_param.Set("min_y", min_y);
+ touch_param.Set("max_x", max_x);
+ touch_param.Set("max_y", max_y);
+ }
+
+ Settings::values.motion_device = motion_param.Serialize();
+ Settings::values.touch_device = touch_param.Serialize();
+ Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked();
+ Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex();
+ Settings::values.touch_from_button_maps = touch_from_button_maps;
+ Settings::values.udp_input_address = ui->udp_server->text().toStdString();
+ Settings::values.udp_input_port = static_cast<u16>(ui->udp_port->text().toInt());
+ Settings::values.udp_pad_index = static_cast<u8>(ui->udp_pad_index->currentIndex());
+ input_subsystem->ReloadInputDevices();
+
+ accept();
+}
diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h
new file mode 100644
index 000000000..3d4b5d659
--- /dev/null
+++ b/src/yuzu/configuration/configure_motion_touch.h
@@ -0,0 +1,90 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QDialog>
+#include "common/param_package.h"
+
+class QLabel;
+class QPushButton;
+class QVBoxLayout;
+
+namespace InputCommon {
+class InputSubsystem;
+}
+
+namespace InputCommon::CemuhookUDP {
+class CalibrationConfigurationJob;
+}
+
+namespace Ui {
+class ConfigureMotionTouch;
+}
+
+/// A dialog for touchpad calibration configuration.
+class CalibrationConfigurationDialog : public QDialog {
+ Q_OBJECT
+public:
+ explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port,
+ u8 pad_index, u16 client_id);
+ ~CalibrationConfigurationDialog() override;
+
+private:
+ Q_INVOKABLE void UpdateLabelText(const QString& text);
+ Q_INVOKABLE void UpdateButtonText(const QString& text);
+
+ QVBoxLayout* layout;
+ QLabel* status_label;
+ QPushButton* cancel_button;
+ std::unique_ptr<InputCommon::CemuhookUDP::CalibrationConfigurationJob> job;
+
+ // Configuration results
+ bool completed{};
+ u16 min_x{};
+ u16 min_y{};
+ u16 max_x{};
+ u16 max_y{};
+
+ friend class ConfigureMotionTouch;
+};
+
+class ConfigureMotionTouch : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ConfigureMotionTouch(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_);
+ ~ConfigureMotionTouch() override;
+
+public slots:
+ void ApplyConfiguration();
+
+private slots:
+ void OnCemuhookUDPTest();
+ void OnConfigureTouchCalibration();
+ void OnConfigureTouchFromButton();
+
+private:
+ void closeEvent(QCloseEvent* event) override;
+ Q_INVOKABLE void ShowUDPTestResult(bool result);
+ void SetConfiguration();
+ void UpdateUiDisplay();
+ void ConnectEvents();
+ bool CanCloseDialog();
+
+ InputCommon::InputSubsystem* input_subsystem;
+
+ std::unique_ptr<Ui::ConfigureMotionTouch> ui;
+
+ // Coordinate system of the CemuhookUDP touch provider
+ int min_x{};
+ int min_y{};
+ int max_x{};
+ int max_y{};
+
+ bool udp_test_in_progress{};
+
+ std::vector<Settings::TouchFromButtonMap> touch_from_button_maps;
+};
diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui
new file mode 100644
index 000000000..602cf8cd8
--- /dev/null
+++ b/src/yuzu/configuration/configure_motion_touch.ui
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureMotionTouch</class>
+ <widget class="QDialog" name="ConfigureMotionTouch">
+ <property name="windowTitle">
+ <string>Configure Motion / Touch</string>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>500</width>
+ <height>450</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QGroupBox" name="motion_group_box">
+ <property name="title">
+ <string>Motion</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="motion_provider_label">
+ <property name="text">
+ <string>Motion Provider:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="motion_provider"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="motion_sensitivity_label">
+ <property name="text">
+ <string>Sensitivity:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="motion_sensitivity">
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="decimals">
+ <number>4</number>
+ </property>
+ <property name="minimum">
+ <double>0.010000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>10.000000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>0.001000000000000</double>
+ </property>
+ <property name="value">
+ <double>0.010000000000000</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="touch_group_box">
+ <property name="title">
+ <string>Touch</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="touch_provider_label">
+ <property name="text">
+ <string>Touch Provider:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="touch_provider"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="touch_calibration_label">
+ <property name="text">
+ <string>Calibration:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="touch_calibration">
+ <property name="text">
+ <string>(100, 50) - (1800, 850)</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="touch_calibration_config">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QCheckBox" name="touch_from_button_checkbox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Use button mapping:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="touch_from_button_map"/>
+ </item>
+ <item>
+ <widget class="QPushButton" name="touch_from_button_config_btn">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Configure</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="udp_config_group_box">
+ <property name="title">
+ <string>CemuhookUDP Config</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QLabel" name="udp_help">
+ <property name="text">
+ <string>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="udp_server_label">
+ <property name="text">
+ <string>Server:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="udp_server">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="udp_port_label">
+ <property name="text">
+ <string>Port:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="udp_port">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="udp_pad_index_label">
+ <property name="text">
+ <string>Pad:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="udp_pad_index">
+ <item>
+ <property name="text">
+ <string>Pad 1</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Pad 2</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Pad 3</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Pad 4</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="udp_learn_more">
+ <property name="text">
+ <string>Learn More</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="udp_test">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Test</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>167</width>
+ <height>55</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ConfigureMotionTouch</receiver>
+ <slot>ApplyConfiguration()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>220</x>
+ <y>380</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>220</x>
+ <y>200</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
index 5bcf5ffa8..2af3afda8 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.cpp
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -18,6 +18,16 @@
static QString GetKeyName(int key_code) {
switch (key_code) {
+ case Qt::LeftButton:
+ return QObject::tr("Click 0");
+ case Qt::RightButton:
+ return QObject::tr("Click 1");
+ case Qt::MiddleButton:
+ return QObject::tr("Click 2");
+ case Qt::BackButton:
+ return QObject::tr("Click 3");
+ case Qt::ForwardButton:
+ return QObject::tr("Click 4");
case Qt::Key_Shift:
return QObject::tr("Shift");
case Qt::Key_Control:
@@ -66,8 +76,10 @@ static QString ButtonToText(const Common::ParamPackage& param) {
return QObject::tr("[unknown]");
}
-ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
- : QDialog(parent), ui(std::make_unique<Ui::ConfigureMouseAdvanced>()),
+ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent,
+ InputCommon::InputSubsystem* input_subsystem_)
+ : QDialog(parent),
+ ui(std::make_unique<Ui::ConfigureMouseAdvanced>()), input_subsystem{input_subsystem_},
timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
ui->setupUi(this);
setFocusPolicy(Qt::ClickFocus);
@@ -188,9 +200,9 @@ void ConfigureMouseAdvanced::HandleClick(
button->setText(tr("[press key]"));
button->setFocus();
- // Keyboard keys can only be used as button devices
- want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
- if (want_keyboard_keys) {
+ // Keyboard keys or mouse buttons can only be used as button devices
+ want_keyboard_mouse = type == InputCommon::Polling::DeviceType::Button;
+ if (want_keyboard_mouse) {
const auto iter = std::find(button_map.begin(), button_map.end(), button);
ASSERT(iter != button_map.end());
const auto index = std::distance(button_map.begin(), iter);
@@ -199,27 +211,29 @@ void ConfigureMouseAdvanced::HandleClick(
input_setter = new_input_setter;
- device_pollers = InputCommon::Polling::GetPollers(type);
+ device_pollers = input_subsystem->GetPollers(type);
for (auto& poller : device_pollers) {
poller->Start();
}
- grabKeyboard();
- grabMouse();
- timeout_timer->start(5000); // Cancel after 5 seconds
- poll_timer->start(200); // Check for new inputs every 200ms
+ QWidget::grabMouse();
+ QWidget::grabKeyboard();
+
+ timeout_timer->start(2500); // Cancel after 2.5 seconds
+ poll_timer->start(50); // Check for new inputs every 50ms
}
void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) {
- releaseKeyboard();
- releaseMouse();
timeout_timer->stop();
poll_timer->stop();
for (auto& poller : device_pollers) {
poller->Stop();
}
+ QWidget::releaseMouse();
+ QWidget::releaseKeyboard();
+
if (!abort) {
(*input_setter)(params);
}
@@ -228,13 +242,29 @@ void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params
input_setter = std::nullopt;
}
+void ConfigureMouseAdvanced::mousePressEvent(QMouseEvent* event) {
+ if (!input_setter || !event) {
+ return;
+ }
+
+ if (want_keyboard_mouse) {
+ SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
+ false);
+ } else {
+ // We don't want any mouse buttons, so don't stop polling
+ return;
+ }
+
+ SetPollingResult({}, true);
+}
+
void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) {
if (!input_setter || !event) {
return;
}
if (event->key() != Qt::Key_Escape) {
- if (want_keyboard_keys) {
+ if (want_keyboard_mouse) {
SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
false);
} else {
diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h
index 342b82412..65b6fca9a 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.h
+++ b/src/yuzu/configuration/configure_mouse_advanced.h
@@ -8,12 +8,14 @@
#include <optional>
#include <QDialog>
-#include "core/settings.h"
-
class QCheckBox;
class QPushButton;
class QTimer;
+namespace InputCommon {
+class InputSubsystem;
+}
+
namespace Ui {
class ConfigureMouseAdvanced;
}
@@ -22,7 +24,7 @@ class ConfigureMouseAdvanced : public QDialog {
Q_OBJECT
public:
- explicit ConfigureMouseAdvanced(QWidget* parent);
+ explicit ConfigureMouseAdvanced(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_);
~ConfigureMouseAdvanced() override;
void ApplyConfiguration();
@@ -49,11 +51,16 @@ private:
/// Finish polling and configure input using the input_setter
void SetPollingResult(const Common::ParamPackage& params, bool abort);
+ /// Handle mouse button press events.
+ void mousePressEvent(QMouseEvent* event) override;
+
/// Handle key press events.
void keyPressEvent(QKeyEvent* event) override;
std::unique_ptr<Ui::ConfigureMouseAdvanced> ui;
+ InputCommon::InputSubsystem* input_subsystem;
+
/// This will be the the setting function when an input is awaiting configuration.
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
@@ -67,5 +74,5 @@ private:
/// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
/// keyboard events are ignored.
- bool want_keyboard_keys = false;
+ bool want_keyboard_mouse = false;
};
diff --git a/src/yuzu/configuration/configure_mouse_advanced.ui b/src/yuzu/configuration/configure_mouse_advanced.ui
index 08245ecf0..74552fdbd 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.ui
+++ b/src/yuzu/configuration/configure_mouse_advanced.ui
@@ -6,13 +6,18 @@
<rect>
<x>0</x>
<y>0</y>
- <width>250</width>
- <height>261</height>
+ <width>310</width>
+ <height>193</height>
</rect>
</property>
<property name="windowTitle">
<string>Configure Mouse</string>
</property>
+ <property name="styleSheet">
+ <string notr="true">QPushButton {
+ min-width: 55px;
+}</string>
+ </property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="gridGroupBox">
@@ -20,81 +25,33 @@
<string>Mouse Buttons</string>
</property>
<layout class="QGridLayout" name="gridLayout">
- <item row="0" column="4">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="3">
- <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item row="3" column="5">
+ <layout class="QVBoxLayout" name="verticalLayout_6">
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
- <widget class="QLabel" name="label_3">
+ <widget class="QLabel" name="label_5">
<property name="text">
- <string>Right:</string>
+ <string>Forward:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
- <widget class="QPushButton" name="right_button">
+ <widget class="QPushButton" name="forward_button">
<property name="minimumSize">
<size>
- <width>75</width>
+ <width>57</width>
<height>0</height>
</size>
</property>
- <property name="text">
- <string/>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
</property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="0">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="1">
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Middle:</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QPushButton" name="middle_button">
<property name="text">
<string/>
</property>
@@ -123,6 +80,12 @@
</item>
<item>
<widget class="QPushButton" name="back_button">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
<property name="text">
<string/>
</property>
@@ -147,7 +110,7 @@
<widget class="QPushButton" name="left_button">
<property name="minimumSize">
<size>
- <width>75</width>
+ <width>57</width>
<height>0</height>
</size>
</property>
@@ -158,21 +121,99 @@
</item>
</layout>
</item>
- <item row="3" column="3">
- <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item row="0" column="3">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
- <widget class="QLabel" name="label_5">
+ <widget class="QLabel" name="label_2">
<property name="text">
- <string>Forward:</string>
+ <string>Middle:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
- <widget class="QPushButton" name="forward_button">
+ <widget class="QPushButton" name="middle_button">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="6">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="5">
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Right:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="right_button">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
<property name="text">
<string/>
</property>
@@ -180,6 +221,32 @@
</item>
</layout>
</item>
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="4">
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
</item>
@@ -187,15 +254,39 @@
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QPushButton" name="buttonClearAll">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
<property name="text">
- <string>Clear All</string>
+ <string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonRestoreDefaults">
+ <property name="minimumSize">
+ <size>
+ <width>57</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
<property name="text">
- <string>Restore Defaults</string>
+ <string>Defaults</string>
</property>
</widget>
</item>
@@ -206,21 +297,24 @@
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>40</width>
+ <width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
</layout>
</widget>
<resources/>
diff --git a/src/yuzu/configuration/configure_touch_from_button.cpp b/src/yuzu/configuration/configure_touch_from_button.cpp
new file mode 100644
index 000000000..15557e4b8
--- /dev/null
+++ b/src/yuzu/configuration/configure_touch_from_button.cpp
@@ -0,0 +1,623 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QInputDialog>
+#include <QKeyEvent>
+#include <QMessageBox>
+#include <QMouseEvent>
+#include <QResizeEvent>
+#include <QStandardItemModel>
+#include <QTimer>
+#include "common/param_package.h"
+#include "core/frontend/framebuffer_layout.h"
+#include "core/settings.h"
+#include "input_common/main.h"
+#include "ui_configure_touch_from_button.h"
+#include "yuzu/configuration/configure_touch_from_button.h"
+#include "yuzu/configuration/configure_touch_widget.h"
+
+static QString GetKeyName(int key_code) {
+ switch (key_code) {
+ case Qt::Key_Shift:
+ return QObject::tr("Shift");
+ case Qt::Key_Control:
+ return QObject::tr("Ctrl");
+ case Qt::Key_Alt:
+ return QObject::tr("Alt");
+ case Qt::Key_Meta:
+ return QString{};
+ default:
+ return QKeySequence(key_code).toString();
+ }
+}
+
+static QString ButtonToText(const Common::ParamPackage& param) {
+ if (!param.Has("engine")) {
+ return QObject::tr("[not set]");
+ }
+
+ if (param.Get("engine", "") == "keyboard") {
+ return GetKeyName(param.Get("code", 0));
+ }
+
+ if (param.Get("engine", "") == "sdl") {
+ if (param.Has("hat")) {
+ const QString hat_str = QString::fromStdString(param.Get("hat", ""));
+ const QString direction_str = QString::fromStdString(param.Get("direction", ""));
+
+ return QObject::tr("Hat %1 %2").arg(hat_str, direction_str);
+ }
+
+ if (param.Has("axis")) {
+ const QString axis_str = QString::fromStdString(param.Get("axis", ""));
+ const QString direction_str = QString::fromStdString(param.Get("direction", ""));
+
+ return QObject::tr("Axis %1%2").arg(axis_str, direction_str);
+ }
+
+ if (param.Has("button")) {
+ const QString button_str = QString::fromStdString(param.Get("button", ""));
+
+ return QObject::tr("Button %1").arg(button_str);
+ }
+
+ return {};
+ }
+
+ return QObject::tr("[unknown]");
+}
+
+ConfigureTouchFromButton::ConfigureTouchFromButton(
+ QWidget* parent, const std::vector<Settings::TouchFromButtonMap>& touch_maps,
+ InputCommon::InputSubsystem* input_subsystem_, const int default_index)
+ : QDialog(parent), ui(std::make_unique<Ui::ConfigureTouchFromButton>()),
+ touch_maps(touch_maps), input_subsystem{input_subsystem_}, selected_index(default_index),
+ timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
+ ui->setupUi(this);
+ binding_list_model = new QStandardItemModel(0, 3, this);
+ binding_list_model->setHorizontalHeaderLabels(
+ {tr("Button"), tr("X", "X axis"), tr("Y", "Y axis")});
+ ui->binding_list->setModel(binding_list_model);
+ ui->bottom_screen->SetCoordLabel(ui->coord_label);
+
+ SetConfiguration();
+ UpdateUiDisplay();
+ ConnectEvents();
+}
+
+ConfigureTouchFromButton::~ConfigureTouchFromButton() = default;
+
+void ConfigureTouchFromButton::showEvent(QShowEvent* ev) {
+ QWidget::showEvent(ev);
+
+ // width values are not valid in the constructor
+ const int w =
+ ui->binding_list->viewport()->contentsRect().width() / binding_list_model->columnCount();
+ if (w <= 0) {
+ return;
+ }
+ ui->binding_list->setColumnWidth(0, w);
+ ui->binding_list->setColumnWidth(1, w);
+ ui->binding_list->setColumnWidth(2, w);
+}
+
+void ConfigureTouchFromButton::SetConfiguration() {
+ for (const auto& touch_map : touch_maps) {
+ ui->mapping->addItem(QString::fromStdString(touch_map.name));
+ }
+
+ ui->mapping->setCurrentIndex(selected_index);
+}
+
+void ConfigureTouchFromButton::UpdateUiDisplay() {
+ ui->button_delete->setEnabled(touch_maps.size() > 1);
+ ui->button_delete_bind->setEnabled(false);
+
+ binding_list_model->removeRows(0, binding_list_model->rowCount());
+
+ for (const auto& button_str : touch_maps[selected_index].buttons) {
+ Common::ParamPackage package{button_str};
+ QStandardItem* button = new QStandardItem(ButtonToText(package));
+ button->setData(QString::fromStdString(button_str));
+ button->setEditable(false);
+ QStandardItem* xcoord = new QStandardItem(QString::number(package.Get("x", 0)));
+ QStandardItem* ycoord = new QStandardItem(QString::number(package.Get("y", 0)));
+ binding_list_model->appendRow({button, xcoord, ycoord});
+
+ const int dot = ui->bottom_screen->AddDot(package.Get("x", 0), package.Get("y", 0));
+ button->setData(dot, DataRoleDot);
+ }
+}
+
+void ConfigureTouchFromButton::ConnectEvents() {
+ connect(ui->mapping, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int index) {
+ SaveCurrentMapping();
+ selected_index = index;
+ UpdateUiDisplay();
+ });
+ connect(ui->button_new, &QPushButton::clicked, this, &ConfigureTouchFromButton::NewMapping);
+ connect(ui->button_delete, &QPushButton::clicked, this,
+ &ConfigureTouchFromButton::DeleteMapping);
+ connect(ui->button_rename, &QPushButton::clicked, this,
+ &ConfigureTouchFromButton::RenameMapping);
+ connect(ui->button_delete_bind, &QPushButton::clicked, this,
+ &ConfigureTouchFromButton::DeleteBinding);
+ connect(ui->binding_list, &QTreeView::doubleClicked, this,
+ &ConfigureTouchFromButton::EditBinding);
+ connect(ui->binding_list->selectionModel(), &QItemSelectionModel::selectionChanged, this,
+ &ConfigureTouchFromButton::OnBindingSelection);
+ connect(binding_list_model, &QStandardItemModel::itemChanged, this,
+ &ConfigureTouchFromButton::OnBindingChanged);
+ connect(ui->binding_list->model(), &QStandardItemModel::rowsAboutToBeRemoved, this,
+ &ConfigureTouchFromButton::OnBindingDeleted);
+ connect(ui->bottom_screen, &TouchScreenPreview::DotAdded, this,
+ &ConfigureTouchFromButton::NewBinding);
+ connect(ui->bottom_screen, &TouchScreenPreview::DotSelected, this,
+ &ConfigureTouchFromButton::SetActiveBinding);
+ connect(ui->bottom_screen, &TouchScreenPreview::DotMoved, this,
+ &ConfigureTouchFromButton::SetCoordinates);
+ connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
+ &ConfigureTouchFromButton::ApplyConfiguration);
+
+ connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); });
+
+ connect(poll_timer.get(), &QTimer::timeout, [this]() {
+ Common::ParamPackage params;
+ for (auto& poller : device_pollers) {
+ params = poller->GetNextInput();
+ if (params.Has("engine")) {
+ SetPollingResult(params, false);
+ return;
+ }
+ }
+ });
+}
+
+void ConfigureTouchFromButton::SaveCurrentMapping() {
+ auto& map = touch_maps[selected_index];
+ map.buttons.clear();
+ for (int i = 0, rc = binding_list_model->rowCount(); i < rc; ++i) {
+ const auto bind_str = binding_list_model->index(i, 0)
+ .data(Qt::ItemDataRole::UserRole + 1)
+ .toString()
+ .toStdString();
+ if (bind_str.empty()) {
+ continue;
+ }
+ Common::ParamPackage params{bind_str};
+ if (!params.Has("engine")) {
+ continue;
+ }
+ params.Set("x", binding_list_model->index(i, 1).data().toInt());
+ params.Set("y", binding_list_model->index(i, 2).data().toInt());
+ map.buttons.emplace_back(params.Serialize());
+ }
+}
+
+void ConfigureTouchFromButton::NewMapping() {
+ const QString name =
+ QInputDialog::getText(this, tr("New Profile"), tr("Enter the name for the new profile."));
+ if (name.isEmpty()) {
+ return;
+ }
+ touch_maps.emplace_back(Settings::TouchFromButtonMap{name.toStdString(), {}});
+ ui->mapping->addItem(name);
+ ui->mapping->setCurrentIndex(ui->mapping->count() - 1);
+}
+
+void ConfigureTouchFromButton::DeleteMapping() {
+ const auto answer = QMessageBox::question(
+ this, tr("Delete Profile"), tr("Delete profile %1?").arg(ui->mapping->currentText()));
+ if (answer != QMessageBox::Yes) {
+ return;
+ }
+ const bool blocked = ui->mapping->blockSignals(true);
+ ui->mapping->removeItem(selected_index);
+ ui->mapping->blockSignals(blocked);
+ touch_maps.erase(touch_maps.begin() + selected_index);
+ selected_index = ui->mapping->currentIndex();
+ UpdateUiDisplay();
+}
+
+void ConfigureTouchFromButton::RenameMapping() {
+ const QString new_name = QInputDialog::getText(this, tr("Rename Profile"), tr("New name:"));
+ if (new_name.isEmpty()) {
+ return;
+ }
+ ui->mapping->setItemText(selected_index, new_name);
+ touch_maps[selected_index].name = new_name.toStdString();
+}
+
+void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is_new) {
+ binding_list_model->item(row_index, 0)->setText(tr("[press key]"));
+
+ input_setter = [this, row_index, is_new](const Common::ParamPackage& params,
+ const bool cancel) {
+ auto* cell = binding_list_model->item(row_index, 0);
+ if (cancel) {
+ if (is_new) {
+ binding_list_model->removeRow(row_index);
+ } else {
+ cell->setText(
+ ButtonToText(Common::ParamPackage{cell->data().toString().toStdString()}));
+ }
+ } else {
+ cell->setText(ButtonToText(params));
+ cell->setData(QString::fromStdString(params.Serialize()));
+ }
+ };
+
+ device_pollers = input_subsystem->GetPollers(InputCommon::Polling::DeviceType::Button);
+
+ for (auto& poller : device_pollers) {
+ poller->Start();
+ }
+
+ grabKeyboard();
+ grabMouse();
+ qApp->setOverrideCursor(QCursor(Qt::CursorShape::ArrowCursor));
+ timeout_timer->start(5000); // Cancel after 5 seconds
+ poll_timer->start(200); // Check for new inputs every 200ms
+}
+
+void ConfigureTouchFromButton::NewBinding(const QPoint& pos) {
+ auto* button = new QStandardItem();
+ button->setEditable(false);
+ auto* x_coord = new QStandardItem(QString::number(pos.x()));
+ auto* y_coord = new QStandardItem(QString::number(pos.y()));
+
+ const int dot_id = ui->bottom_screen->AddDot(pos.x(), pos.y());
+ button->setData(dot_id, DataRoleDot);
+
+ binding_list_model->appendRow({button, x_coord, y_coord});
+ ui->binding_list->setFocus();
+ ui->binding_list->setCurrentIndex(button->index());
+
+ GetButtonInput(binding_list_model->rowCount() - 1, true);
+}
+
+void ConfigureTouchFromButton::EditBinding(const QModelIndex& qi) {
+ if (qi.row() >= 0 && qi.column() == 0) {
+ GetButtonInput(qi.row(), false);
+ }
+}
+
+void ConfigureTouchFromButton::DeleteBinding() {
+ const int row_index = ui->binding_list->currentIndex().row();
+ if (row_index < 0) {
+ return;
+ }
+ ui->bottom_screen->RemoveDot(binding_list_model->index(row_index, 0).data(DataRoleDot).toInt());
+ binding_list_model->removeRow(row_index);
+}
+
+void ConfigureTouchFromButton::OnBindingSelection(const QItemSelection& selected,
+ const QItemSelection& deselected) {
+ ui->button_delete_bind->setEnabled(!selected.isEmpty());
+ if (!selected.isEmpty()) {
+ const auto dot_data = selected.indexes().first().data(DataRoleDot);
+ if (dot_data.isValid()) {
+ ui->bottom_screen->HighlightDot(dot_data.toInt());
+ }
+ }
+ if (!deselected.isEmpty()) {
+ const auto dot_data = deselected.indexes().first().data(DataRoleDot);
+ if (dot_data.isValid()) {
+ ui->bottom_screen->HighlightDot(dot_data.toInt(), false);
+ }
+ }
+}
+
+void ConfigureTouchFromButton::OnBindingChanged(QStandardItem* item) {
+ if (item->column() == 0) {
+ return;
+ }
+
+ const bool blocked = binding_list_model->blockSignals(true);
+ item->setText(QString::number(
+ std::clamp(item->text().toInt(), 0,
+ static_cast<int>((item->column() == 1 ? Layout::ScreenUndocked::Width
+ : Layout::ScreenUndocked::Height) -
+ 1))));
+ binding_list_model->blockSignals(blocked);
+
+ const auto dot_data = binding_list_model->index(item->row(), 0).data(DataRoleDot);
+ if (dot_data.isValid()) {
+ ui->bottom_screen->MoveDot(dot_data.toInt(),
+ binding_list_model->item(item->row(), 1)->text().toInt(),
+ binding_list_model->item(item->row(), 2)->text().toInt());
+ }
+}
+
+void ConfigureTouchFromButton::OnBindingDeleted(const QModelIndex& parent, int first, int last) {
+ for (int i = first; i <= last; ++i) {
+ const auto ix = binding_list_model->index(i, 0);
+ if (!ix.isValid()) {
+ return;
+ }
+ const auto dot_data = ix.data(DataRoleDot);
+ if (dot_data.isValid()) {
+ ui->bottom_screen->RemoveDot(dot_data.toInt());
+ }
+ }
+}
+
+void ConfigureTouchFromButton::SetActiveBinding(const int dot_id) {
+ for (int i = 0; i < binding_list_model->rowCount(); ++i) {
+ if (binding_list_model->index(i, 0).data(DataRoleDot) == dot_id) {
+ ui->binding_list->setCurrentIndex(binding_list_model->index(i, 0));
+ ui->binding_list->setFocus();
+ return;
+ }
+ }
+}
+
+void ConfigureTouchFromButton::SetCoordinates(const int dot_id, const QPoint& pos) {
+ for (int i = 0; i < binding_list_model->rowCount(); ++i) {
+ if (binding_list_model->item(i, 0)->data(DataRoleDot) == dot_id) {
+ binding_list_model->item(i, 1)->setText(QString::number(pos.x()));
+ binding_list_model->item(i, 2)->setText(QString::number(pos.y()));
+ return;
+ }
+ }
+}
+
+void ConfigureTouchFromButton::SetPollingResult(const Common::ParamPackage& params,
+ const bool cancel) {
+ releaseKeyboard();
+ releaseMouse();
+ qApp->restoreOverrideCursor();
+ timeout_timer->stop();
+ poll_timer->stop();
+ for (auto& poller : device_pollers) {
+ poller->Stop();
+ }
+ if (input_setter) {
+ (*input_setter)(params, cancel);
+ input_setter.reset();
+ }
+}
+
+void ConfigureTouchFromButton::keyPressEvent(QKeyEvent* event) {
+ if (!input_setter && event->key() == Qt::Key_Delete) {
+ DeleteBinding();
+ return;
+ }
+
+ if (!input_setter) {
+ return QDialog::keyPressEvent(event);
+ }
+
+ if (event->key() != Qt::Key_Escape) {
+ SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
+ false);
+ } else {
+ SetPollingResult({}, true);
+ }
+}
+
+void ConfigureTouchFromButton::ApplyConfiguration() {
+ SaveCurrentMapping();
+ accept();
+}
+
+int ConfigureTouchFromButton::GetSelectedIndex() const {
+ return selected_index;
+}
+
+std::vector<Settings::TouchFromButtonMap> ConfigureTouchFromButton::GetMaps() const {
+ return touch_maps;
+}
+
+TouchScreenPreview::TouchScreenPreview(QWidget* parent) : QFrame(parent) {
+ setBackgroundRole(QPalette::ColorRole::Base);
+}
+
+TouchScreenPreview::~TouchScreenPreview() = default;
+
+void TouchScreenPreview::SetCoordLabel(QLabel* const label) {
+ coord_label = label;
+}
+
+int TouchScreenPreview::AddDot(const int device_x, const int device_y) {
+ QFont dot_font{QStringLiteral("monospace")};
+ dot_font.setStyleHint(QFont::Monospace);
+ dot_font.setPointSize(20);
+
+ auto* dot = new QLabel(this);
+ dot->setAttribute(Qt::WA_TranslucentBackground);
+ dot->setFont(dot_font);
+ dot->setText(QChar(0xD7)); // U+00D7 Multiplication Sign
+ dot->setAlignment(Qt::AlignmentFlag::AlignCenter);
+ dot->setProperty(PropId, ++max_dot_id);
+ dot->setProperty(PropX, device_x);
+ dot->setProperty(PropY, device_y);
+ dot->setCursor(Qt::CursorShape::PointingHandCursor);
+ dot->setMouseTracking(true);
+ dot->installEventFilter(this);
+ dot->show();
+ PositionDot(dot, device_x, device_y);
+ dots.emplace_back(max_dot_id, dot);
+ return max_dot_id;
+}
+
+void TouchScreenPreview::RemoveDot(const int id) {
+ const auto iter = std::find_if(dots.begin(), dots.end(),
+ [id](const auto& entry) { return entry.first == id; });
+ if (iter == dots.cend()) {
+ return;
+ }
+
+ iter->second->deleteLater();
+ dots.erase(iter);
+}
+
+void TouchScreenPreview::HighlightDot(const int id, const bool active) const {
+ for (const auto& dot : dots) {
+ if (dot.first == id) {
+ // use color property from the stylesheet, or fall back to the default palette
+ if (dot_highlight_color.isValid()) {
+ dot.second->setStyleSheet(
+ active ? QStringLiteral("color: %1").arg(dot_highlight_color.name())
+ : QString{});
+ } else {
+ dot.second->setForegroundRole(active ? QPalette::ColorRole::LinkVisited
+ : QPalette::ColorRole::NoRole);
+ }
+ if (active) {
+ dot.second->raise();
+ }
+ return;
+ }
+ }
+}
+
+void TouchScreenPreview::MoveDot(const int id, const int device_x, const int device_y) const {
+ const auto iter = std::find_if(dots.begin(), dots.end(),
+ [id](const auto& entry) { return entry.first == id; });
+ if (iter == dots.cend()) {
+ return;
+ }
+
+ iter->second->setProperty(PropX, device_x);
+ iter->second->setProperty(PropY, device_y);
+ PositionDot(iter->second, device_x, device_y);
+}
+
+void TouchScreenPreview::resizeEvent(QResizeEvent* event) {
+ if (ignore_resize) {
+ return;
+ }
+
+ const int target_width = std::min(width(), height() * 4 / 3);
+ const int target_height = std::min(height(), width() * 3 / 4);
+ if (target_width == width() && target_height == height()) {
+ return;
+ }
+ ignore_resize = true;
+ setGeometry((parentWidget()->contentsRect().width() - target_width) / 2, y(), target_width,
+ target_height);
+ ignore_resize = false;
+
+ if (event->oldSize().width() != target_width || event->oldSize().height() != target_height) {
+ for (const auto& dot : dots) {
+ PositionDot(dot.second);
+ }
+ }
+}
+
+void TouchScreenPreview::mouseMoveEvent(QMouseEvent* event) {
+ if (!coord_label) {
+ return;
+ }
+ const auto pos = MapToDeviceCoords(event->x(), event->y());
+ if (pos) {
+ coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x()).arg(pos->y()));
+ } else {
+ coord_label->clear();
+ }
+}
+
+void TouchScreenPreview::leaveEvent(QEvent* event) {
+ if (coord_label) {
+ coord_label->clear();
+ }
+}
+
+void TouchScreenPreview::mousePressEvent(QMouseEvent* event) {
+ if (event->button() != Qt::MouseButton::LeftButton) {
+ return;
+ }
+ const auto pos = MapToDeviceCoords(event->x(), event->y());
+ if (pos) {
+ emit DotAdded(*pos);
+ }
+}
+
+bool TouchScreenPreview::eventFilter(QObject* obj, QEvent* event) {
+ switch (event->type()) {
+ case QEvent::Type::MouseButtonPress: {
+ const auto mouse_event = static_cast<QMouseEvent*>(event);
+ if (mouse_event->button() != Qt::MouseButton::LeftButton) {
+ break;
+ }
+ emit DotSelected(obj->property(PropId).toInt());
+
+ drag_state.dot = qobject_cast<QLabel*>(obj);
+ drag_state.start_pos = mouse_event->globalPos();
+ return true;
+ }
+ case QEvent::Type::MouseMove: {
+ if (!drag_state.dot) {
+ break;
+ }
+ const auto mouse_event = static_cast<QMouseEvent*>(event);
+ if (!drag_state.active) {
+ drag_state.active =
+ (mouse_event->globalPos() - drag_state.start_pos).manhattanLength() >=
+ QApplication::startDragDistance();
+ if (!drag_state.active) {
+ break;
+ }
+ }
+ auto current_pos = mapFromGlobal(mouse_event->globalPos());
+ current_pos.setX(std::clamp(current_pos.x(), contentsMargins().left(),
+ contentsMargins().left() + contentsRect().width() - 1));
+ current_pos.setY(std::clamp(current_pos.y(), contentsMargins().top(),
+ contentsMargins().top() + contentsRect().height() - 1));
+ const auto device_coord = MapToDeviceCoords(current_pos.x(), current_pos.y());
+ if (device_coord) {
+ drag_state.dot->setProperty(PropX, device_coord->x());
+ drag_state.dot->setProperty(PropY, device_coord->y());
+ PositionDot(drag_state.dot, device_coord->x(), device_coord->y());
+ emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord);
+ if (coord_label) {
+ coord_label->setText(
+ QStringLiteral("X: %1, Y: %2").arg(device_coord->x()).arg(device_coord->y()));
+ }
+ }
+ return true;
+ }
+ case QEvent::Type::MouseButtonRelease: {
+ drag_state.dot.clear();
+ drag_state.active = false;
+ return true;
+ }
+ default:
+ break;
+ }
+ return obj->eventFilter(obj, event);
+}
+
+std::optional<QPoint> TouchScreenPreview::MapToDeviceCoords(const int screen_x,
+ const int screen_y) const {
+ const float t_x = 0.5f + static_cast<float>(screen_x - contentsMargins().left()) *
+ (Layout::ScreenUndocked::Width - 1) / (contentsRect().width() - 1);
+ const float t_y = 0.5f + static_cast<float>(screen_y - contentsMargins().top()) *
+ (Layout::ScreenUndocked::Height - 1) /
+ (contentsRect().height() - 1);
+ if (t_x >= 0.5f && t_x < Layout::ScreenUndocked::Width && t_y >= 0.5f &&
+ t_y < Layout::ScreenUndocked::Height) {
+
+ return QPoint{static_cast<int>(t_x), static_cast<int>(t_y)};
+ }
+ return std::nullopt;
+}
+
+void TouchScreenPreview::PositionDot(QLabel* const dot, const int device_x,
+ const int device_y) const {
+ const float device_coord_x =
+ static_cast<float>(device_x >= 0 ? device_x : dot->property(PropX).toInt());
+ int x_coord = static_cast<int>(
+ device_coord_x * (contentsRect().width() - 1) / (Layout::ScreenUndocked::Width - 1) +
+ contentsMargins().left() - static_cast<float>(dot->width()) / 2 + 0.5f);
+
+ const float device_coord_y =
+ static_cast<float>(device_y >= 0 ? device_y : dot->property(PropY).toInt());
+ const int y_coord = static_cast<int>(
+ device_coord_y * (contentsRect().height() - 1) / (Layout::ScreenUndocked::Height - 1) +
+ contentsMargins().top() - static_cast<float>(dot->height()) / 2 + 0.5f);
+
+ dot->move(x_coord, y_coord);
+}
diff --git a/src/yuzu/configuration/configure_touch_from_button.h b/src/yuzu/configuration/configure_touch_from_button.h
new file mode 100644
index 000000000..d9513e3bc
--- /dev/null
+++ b/src/yuzu/configuration/configure_touch_from_button.h
@@ -0,0 +1,92 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <vector>
+#include <QDialog>
+
+class QItemSelection;
+class QModelIndex;
+class QStandardItemModel;
+class QStandardItem;
+class QTimer;
+
+namespace Common {
+class ParamPackage;
+}
+
+namespace InputCommon {
+class InputSubsystem;
+}
+
+namespace InputCommon::Polling {
+class DevicePoller;
+}
+
+namespace Settings {
+struct TouchFromButtonMap;
+}
+
+namespace Ui {
+class ConfigureTouchFromButton;
+}
+
+class ConfigureTouchFromButton : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ConfigureTouchFromButton(QWidget* parent,
+ const std::vector<Settings::TouchFromButtonMap>& touch_maps,
+ InputCommon::InputSubsystem* input_subsystem_,
+ int default_index = 0);
+ ~ConfigureTouchFromButton() override;
+
+ int GetSelectedIndex() const;
+ std::vector<Settings::TouchFromButtonMap> GetMaps() const;
+
+public slots:
+ void ApplyConfiguration();
+ void NewBinding(const QPoint& pos);
+ void SetActiveBinding(int dot_id);
+ void SetCoordinates(int dot_id, const QPoint& pos);
+
+protected:
+ void showEvent(QShowEvent* ev) override;
+ void keyPressEvent(QKeyEvent* event) override;
+
+private slots:
+ void NewMapping();
+ void DeleteMapping();
+ void RenameMapping();
+ void EditBinding(const QModelIndex& qi);
+ void DeleteBinding();
+ void OnBindingSelection(const QItemSelection& selected, const QItemSelection& deselected);
+ void OnBindingChanged(QStandardItem* item);
+ void OnBindingDeleted(const QModelIndex& parent, int first, int last);
+
+private:
+ void SetConfiguration();
+ void UpdateUiDisplay();
+ void ConnectEvents();
+ void GetButtonInput(int row_index, bool is_new);
+ void SetPollingResult(const Common::ParamPackage& params, bool cancel);
+ void SaveCurrentMapping();
+
+ std::unique_ptr<Ui::ConfigureTouchFromButton> ui;
+ std::vector<Settings::TouchFromButtonMap> touch_maps;
+ QStandardItemModel* binding_list_model;
+ InputCommon::InputSubsystem* input_subsystem;
+ int selected_index;
+
+ std::unique_ptr<QTimer> timeout_timer;
+ std::unique_ptr<QTimer> poll_timer;
+ std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
+ std::optional<std::function<void(const Common::ParamPackage&, bool)>> input_setter;
+
+ static constexpr int DataRoleDot = Qt::ItemDataRole::UserRole + 2;
+};
diff --git a/src/yuzu/configuration/configure_touch_from_button.ui b/src/yuzu/configuration/configure_touch_from_button.ui
new file mode 100644
index 000000000..f581e27e0
--- /dev/null
+++ b/src/yuzu/configuration/configure_touch_from_button.ui
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureTouchFromButton</class>
+ <widget class="QDialog" name="ConfigureTouchFromButton">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>500</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Touchscreen Mappings</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Mapping:</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="mapping">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="button_new">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>New</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="button_delete">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="button_rename">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Rename</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Click the bottom area to add a point, then press a button to bind.
+Drag points to change position, or double-click table cells to edit values.</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="button_delete_bind">
+ <property name="text">
+ <string>Delete Point</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="binding_list">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="TouchScreenPreview" name="bottom_screen">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>160</width>
+ <height>120</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>320</width>
+ <height>240</height>
+ </size>
+ </property>
+ <property name="cursor">
+ <cursorShape>CrossCursor</cursorShape>
+ </property>
+ <property name="mouseTracking">
+ <bool>true</bool>
+ </property>
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Sunken</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="coord_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>TouchScreenPreview</class>
+ <extends>QFrame</extends>
+ <header>yuzu/configuration/configure_touch_widget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ConfigureTouchFromButton</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>249</x>
+ <y>428</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>249</x>
+ <y>224</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/configuration/configure_touch_widget.h b/src/yuzu/configuration/configure_touch_widget.h
new file mode 100644
index 000000000..347b46583
--- /dev/null
+++ b/src/yuzu/configuration/configure_touch_widget.h
@@ -0,0 +1,62 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <optional>
+#include <utility>
+#include <vector>
+#include <QFrame>
+#include <QPointer>
+
+class QLabel;
+
+// Widget for representing touchscreen coordinates
+class TouchScreenPreview : public QFrame {
+ Q_OBJECT
+ Q_PROPERTY(QColor dotHighlightColor MEMBER dot_highlight_color)
+
+public:
+ explicit TouchScreenPreview(QWidget* parent);
+ ~TouchScreenPreview() override;
+
+ void SetCoordLabel(QLabel*);
+ int AddDot(int device_x, int device_y);
+ void RemoveDot(int id);
+ void HighlightDot(int id, bool active = true) const;
+ void MoveDot(int id, int device_x, int device_y) const;
+
+signals:
+ void DotAdded(const QPoint& pos);
+ void DotSelected(int dot_id);
+ void DotMoved(int dot_id, const QPoint& pos);
+
+protected:
+ void resizeEvent(QResizeEvent*) override;
+ void mouseMoveEvent(QMouseEvent*) override;
+ void leaveEvent(QEvent*) override;
+ void mousePressEvent(QMouseEvent*) override;
+ bool eventFilter(QObject*, QEvent*) override;
+
+private:
+ std::optional<QPoint> MapToDeviceCoords(int screen_x, int screen_y) const;
+ void PositionDot(QLabel* dot, int device_x = -1, int device_y = -1) const;
+
+ bool ignore_resize = false;
+ QPointer<QLabel> coord_label;
+
+ std::vector<std::pair<int, QLabel*>> dots;
+ int max_dot_id = 0;
+ QColor dot_highlight_color;
+ static constexpr char PropId[] = "dot_id";
+ static constexpr char PropX[] = "device_x";
+ static constexpr char PropY[] = "device_y";
+
+ struct DragState {
+ bool active = false;
+ QPointer<QLabel> dot;
+ QPoint start_pos;
+ };
+ DragState drag_state;
+};
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 6a71d9644..70d865112 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -25,7 +25,8 @@
#include "yuzu/main.h"
#include "yuzu/uisettings.h"
-GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {}
+GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist, QObject* parent)
+ : QObject(parent), gamelist{gamelist} {}
// EventFilter in order to process systemkeys while editing the searchfield
bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) {
@@ -56,7 +57,7 @@ bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* eve
case Qt::Key_Return:
case Qt::Key_Enter: {
if (gamelist->search_field->visible == 1) {
- QString file_path = gamelist->getLastFilterResultItem();
+ const QString file_path = gamelist->GetLastFilterResultItem();
// To avoid loading error dialog loops while confirming them using enter
// Also users usually want to run a different game after closing one
@@ -83,22 +84,25 @@ void GameListSearchField::setFilterResult(int visible, int total) {
label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible));
}
-QString GameList::getLastFilterResultItem() const {
- QStandardItem* folder;
- QStandardItem* child;
+QString GameList::GetLastFilterResultItem() const {
QString file_path;
const int folder_count = item_model->rowCount();
+
for (int i = 0; i < folder_count; ++i) {
- folder = item_model->item(i, 0);
+ const QStandardItem* folder = item_model->item(i, 0);
const QModelIndex folder_index = folder->index();
const int children_count = folder->rowCount();
+
for (int j = 0; j < children_count; ++j) {
- if (!tree_view->isRowHidden(j, folder_index)) {
- child = folder->child(j, 0);
- file_path = child->data(GameListItemPath::FullPathRole).toString();
+ if (tree_view->isRowHidden(j, folder_index)) {
+ continue;
}
+
+ const QStandardItem* child = folder->child(j, 0);
+ file_path = child->data(GameListItemPath::FullPathRole).toString();
}
}
+
return file_path;
}
@@ -113,7 +117,7 @@ void GameListSearchField::setFocus() {
}
GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
- auto* const key_release_eater = new KeyReleaseEater(parent);
+ auto* const key_release_eater = new KeyReleaseEater(parent, this);
layout_filter = new QHBoxLayout;
layout_filter->setMargin(8);
label_filter = new QLabel;
@@ -123,7 +127,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
edit_filter->setPlaceholderText(tr("Enter pattern to filter"));
edit_filter->installEventFilter(key_release_eater);
edit_filter->setClearButtonEnabled(true);
- connect(edit_filter, &QLineEdit::textChanged, parent, &GameList::onTextChanged);
+ connect(edit_filter, &QLineEdit::textChanged, parent, &GameList::OnTextChanged);
label_filter_result = new QLabel;
button_filter_close = new QToolButton(this);
button_filter_close->setText(QStringLiteral("X"));
@@ -133,7 +137,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
"#000000; font-weight: bold; background: #F0F0F0; }"
"QToolButton:hover{ border: none; padding: 0px; color: "
"#EEEEEE; font-weight: bold; background: #E81123}"));
- connect(button_filter_close, &QToolButton::clicked, parent, &GameList::onFilterCloseClicked);
+ connect(button_filter_close, &QToolButton::clicked, parent, &GameList::OnFilterCloseClicked);
layout_filter->setSpacing(10);
layout_filter->addWidget(label_filter);
layout_filter->addWidget(edit_filter);
@@ -159,16 +163,22 @@ static bool ContainsAllWords(const QString& haystack, const QString& userinput)
}
// Syncs the expanded state of Game Directories with settings to persist across sessions
-void GameList::onItemExpanded(const QModelIndex& item) {
+void GameList::OnItemExpanded(const QModelIndex& item) {
const auto type = item.data(GameListItem::TypeRole).value<GameListItemType>();
- if (type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir ||
- type == GameListItemType::UserNandDir || type == GameListItemType::SysNandDir)
- item.data(GameListDir::GameDirRole).value<UISettings::GameDir*>()->expanded =
- tree_view->isExpanded(item);
+ const bool is_dir = type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir ||
+ type == GameListItemType::UserNandDir ||
+ type == GameListItemType::SysNandDir;
+
+ if (!is_dir) {
+ return;
+ }
+
+ auto* game_dir = item.data(GameListDir::GameDirRole).value<UISettings::GameDir*>();
+ game_dir->expanded = tree_view->isExpanded(item);
}
// Event in order to filter the gamelist after editing the searchfield
-void GameList::onTextChanged(const QString& new_text) {
+void GameList::OnTextChanged(const QString& new_text) {
const int folder_count = tree_view->model()->rowCount();
QString edit_filter_text = new_text.toLower();
QStandardItem* folder;
@@ -224,7 +234,7 @@ void GameList::onTextChanged(const QString& new_text) {
}
}
-void GameList::onUpdateThemedIcons() {
+void GameList::OnUpdateThemedIcons() {
for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) {
QStandardItem* child = item_model->invisibleRootItem()->child(i);
@@ -276,7 +286,7 @@ void GameList::onUpdateThemedIcons() {
}
}
-void GameList::onFilterCloseClicked() {
+void GameList::OnFilterCloseClicked() {
main_window->filterBarSetChecked(false);
}
@@ -317,11 +327,11 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
}
item_model->setSortRole(GameListItemPath::SortRole);
- connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::onUpdateThemedIcons);
+ connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry);
connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
- connect(tree_view, &QTreeView::expanded, this, &GameList::onItemExpanded);
- connect(tree_view, &QTreeView::collapsed, this, &GameList::onItemExpanded);
+ connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
+ connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded);
// We must register all custom types with the Qt Automoc system so that we are able to use
// it with signals/slots. In this case, QList falls under the umbrells of custom types.
@@ -338,17 +348,17 @@ GameList::~GameList() {
emit ShouldCancelWorker();
}
-void GameList::setFilterFocus() {
+void GameList::SetFilterFocus() {
if (tree_view->model()->rowCount() > 0) {
search_field->setFocus();
}
}
-void GameList::setFilterVisible(bool visibility) {
+void GameList::SetFilterVisible(bool visibility) {
search_field->setVisible(visibility);
}
-void GameList::clearFilter() {
+void GameList::ClearFilter() {
search_field->clear();
}
@@ -397,10 +407,11 @@ void GameList::ValidateEntry(const QModelIndex& item) {
}
}
-bool GameList::isEmpty() const {
+bool GameList::IsEmpty() const {
for (int i = 0; i < item_model->rowCount(); i++) {
const QStandardItem* child = item_model->invisibleRootItem()->child(i);
const auto type = static_cast<GameListItemType>(child->type());
+
if (!child->hasChildren() &&
(type == GameListItemType::SdmcDir || type == GameListItemType::UserNandDir ||
type == GameListItemType::SysNandDir)) {
@@ -408,11 +419,12 @@ bool GameList::isEmpty() const {
i--;
}
}
+
return !item_model->invisibleRootItem()->hasChildren();
}
-void GameList::DonePopulating(QStringList watch_list) {
- emit ShowList(!isEmpty());
+void GameList::DonePopulating(const QStringList& watch_list) {
+ emit ShowList(!IsEmpty());
item_model->invisibleRootItem()->appendRow(new GameListAddDir());
@@ -472,7 +484,7 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location));
}
-void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string path) {
+void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) {
QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location"));
QAction* open_transferable_shader_cache =
@@ -690,12 +702,15 @@ void GameList::SaveInterfaceLayout() {
}
void GameList::LoadInterfaceLayout() {
- auto header = tree_view->header();
- if (!header->restoreState(UISettings::values.gamelist_header_state)) {
- // We are using the name column to display icons and titles
- // so make it as large as possible as default.
- header->resizeSection(COLUMN_NAME, header->width());
+ auto* header = tree_view->header();
+
+ if (header->restoreState(UISettings::values.gamelist_header_state)) {
+ return;
}
+
+ // We are using the name column to display icons and titles
+ // so make it as large as possible as default.
+ header->resizeSection(COLUMN_NAME, header->width());
}
const QStringList GameList::supported_file_extensions = {
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 78e2ba169..58059a3c4 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -67,11 +67,11 @@ public:
FileSys::ManualContentProvider* provider, GMainWindow* parent = nullptr);
~GameList() override;
- QString getLastFilterResultItem() const;
- void clearFilter();
- void setFilterFocus();
- void setFilterVisible(bool visibility);
- bool isEmpty() const;
+ QString GetLastFilterResultItem() const;
+ void ClearFilter();
+ void SetFilterFocus();
+ void SetFilterVisible(bool visibility);
+ bool IsEmpty() const;
void LoadCompatibilityList();
void PopulateAsync(QVector<UISettings::GameDir>& game_dirs);
@@ -82,7 +82,7 @@ public:
static const QStringList supported_file_extensions;
signals:
- void GameChosen(QString game_path);
+ void GameChosen(const QString& game_path);
void ShouldCancelWorker();
void OpenFolderRequested(u64 program_id, GameListOpenTarget target,
const std::string& game_path);
@@ -99,21 +99,21 @@ signals:
void ShowList(bool show);
private slots:
- void onItemExpanded(const QModelIndex& item);
- void onTextChanged(const QString& new_text);
- void onFilterCloseClicked();
- void onUpdateThemedIcons();
+ void OnItemExpanded(const QModelIndex& item);
+ void OnTextChanged(const QString& new_text);
+ void OnFilterCloseClicked();
+ void OnUpdateThemedIcons();
private:
void AddDirEntry(GameListDir* entry_items);
void AddEntry(const QList<QStandardItem*>& entry_items, GameListDir* parent);
void ValidateEntry(const QModelIndex& item);
- void DonePopulating(QStringList watch_list);
+ void DonePopulating(const QStringList& watch_list);
void RefreshGameDirectory();
void PopupContextMenu(const QPoint& menu_location);
- void AddGamePopup(QMenu& context_menu, u64 program_id, std::string path);
+ void AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path);
void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected);
void AddPermDirPopup(QMenu& context_menu, QModelIndex selected);
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index 0cd0054c8..248855aff 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -49,10 +49,10 @@ class GameListItem : public QStandardItem {
public:
// used to access type from item index
- static const int TypeRole = Qt::UserRole + 1;
- static const int SortRole = Qt::UserRole + 2;
+ static constexpr int TypeRole = Qt::UserRole + 1;
+ static constexpr int SortRole = Qt::UserRole + 2;
GameListItem() = default;
- GameListItem(const QString& string) : QStandardItem(string) {
+ explicit GameListItem(const QString& string) : QStandardItem(string) {
setData(string, SortRole);
}
};
@@ -65,10 +65,10 @@ public:
*/
class GameListItemPath : public GameListItem {
public:
- static const int TitleRole = SortRole + 1;
- static const int FullPathRole = SortRole + 2;
- static const int ProgramIdRole = SortRole + 3;
- static const int FileTypeRole = SortRole + 4;
+ static constexpr int TitleRole = SortRole + 1;
+ static constexpr int FullPathRole = SortRole + 2;
+ static constexpr int ProgramIdRole = SortRole + 3;
+ static constexpr int FileTypeRole = SortRole + 4;
GameListItemPath() = default;
GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data,
@@ -110,18 +110,22 @@ public:
const auto& row1 = row_data.at(UISettings::values.row_1_text_id);
const int row2_id = UISettings::values.row_2_text_id;
- if (role == SortRole)
+ if (role == SortRole) {
return row1.toLower();
+ }
- if (row2_id == 4) // None
+ // None
+ if (row2_id == 4) {
return row1;
+ }
const auto& row2 = row_data.at(row2_id);
- if (row1 == row2)
+ if (row1 == row2) {
return row1;
+ }
- return QString(row1 + QStringLiteral("\n ") + row2);
+ return QStringLiteral("%1\n %2").arg(row1, row2);
}
return GameListItem::data(role);
@@ -131,7 +135,7 @@ public:
class GameListItemCompat : public GameListItem {
Q_DECLARE_TR_FUNCTIONS(GameListItemCompat)
public:
- static const int CompatNumberRole = SortRole;
+ static constexpr int CompatNumberRole = SortRole;
GameListItemCompat() = default;
explicit GameListItemCompat(const QString& compatibility) {
setData(type(), TypeRole);
@@ -181,7 +185,7 @@ public:
*/
class GameListItemSize : public GameListItem {
public:
- static const int SizeRole = SortRole;
+ static constexpr int SizeRole = SortRole;
GameListItemSize() = default;
explicit GameListItemSize(const qulonglong size_bytes) {
@@ -217,7 +221,7 @@ public:
class GameListDir : public GameListItem {
public:
- static const int GameDirRole = Qt::UserRole + 2;
+ static constexpr int GameDirRole = Qt::UserRole + 2;
explicit GameListDir(UISettings::GameDir& directory,
GameListItemType dir_type = GameListItemType::CustomDir)
@@ -326,7 +330,7 @@ public:
private:
class KeyReleaseEater : public QObject {
public:
- explicit KeyReleaseEater(GameList* gamelist);
+ explicit KeyReleaseEater(GameList* gamelist, QObject* parent = nullptr);
private:
GameList* gamelist = nullptr;
diff --git a/src/yuzu/install_dialog.h b/src/yuzu/install_dialog.h
index e4aba1b06..68e03fe4e 100644
--- a/src/yuzu/install_dialog.h
+++ b/src/yuzu/install_dialog.h
@@ -20,9 +20,8 @@ public:
explicit InstallDialog(QWidget* parent, const QStringList& files);
~InstallDialog() override;
- QStringList GetFiles() const;
- bool ShouldOverwriteFiles() const;
- int GetMinimumWidth() const;
+ [[nodiscard]] QStringList GetFiles() const;
+ [[nodiscard]] int GetMinimumWidth() const;
private:
QListWidget* file_list;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index cd7e78eb4..e3de0f0e1 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -11,6 +11,7 @@
#endif
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
+#include "applets/controller.h"
#include "applets/error.h"
#include "applets/profile_select.h"
#include "applets/software_keyboard.h"
@@ -19,7 +20,9 @@
#include "configuration/configure_per_game.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h"
+#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/general_frontend.h"
+#include "core/frontend/applets/software_keyboard.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
@@ -84,7 +87,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "core/file_sys/romfs.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/submission_package.h"
-#include "core/frontend/applets/software_keyboard.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/filesystem/filesystem.h"
@@ -94,6 +96,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "core/perf_stats.h"
#include "core/settings.h"
#include "core/telemetry_session.h"
+#include "input_common/main.h"
#include "video_core/gpu.h"
#include "video_core/shader_notify.h"
#include "yuzu/about_dialog.h"
@@ -186,9 +189,9 @@ static void InitializeLogging() {
}
GMainWindow::GMainWindow()
- : config(new Config()), emu_thread(nullptr),
- vfs(std::make_shared<FileSys::RealVfsFilesystem>()),
- provider(std::make_unique<FileSys::ManualContentProvider>()) {
+ : input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
+ config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
+ provider{std::make_unique<FileSys::ManualContentProvider>()} {
InitializeLogging();
LoadTranslation();
@@ -282,18 +285,38 @@ GMainWindow::~GMainWindow() {
delete render_window;
}
+void GMainWindow::ControllerSelectorReconfigureControllers(
+ const Core::Frontend::ControllerParameters& parameters) {
+ QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
+ dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
+ Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
+ dialog.setWindowModality(Qt::WindowModal);
+ dialog.exec();
+
+ emit ControllerSelectorReconfigureFinished();
+
+ // Don't forget to apply settings.
+ Settings::Apply();
+ config->Save();
+
+ UpdateStatusButtons();
+}
+
void GMainWindow::ProfileSelectorSelectProfile() {
const Service::Account::ProfileManager manager;
int index = 0;
if (manager.GetUserCount() != 1) {
QtProfileSelectionDialog dialog(this);
- dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
- Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
+ dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
+ Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
+ Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
+
if (dialog.exec() == QDialog::Rejected) {
emit ProfileSelectorFinishedSelection(std::nullopt);
return;
}
+
index = dialog.GetIndex();
}
@@ -309,8 +332,9 @@ void GMainWindow::ProfileSelectorSelectProfile() {
void GMainWindow::SoftwareKeyboardGetText(
const Core::Frontend::SoftwareKeyboardParameters& parameters) {
QtSoftwareKeyboardDialog dialog(this, parameters);
- dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
- Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
+ dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
+ Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
+ Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
if (dialog.exec() == QDialog::Rejected) {
@@ -473,7 +497,7 @@ void GMainWindow::InitializeWidgets() {
#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
ui.action_Report_Compatibility->setVisible(true);
#endif
- render_window = new GRenderWindow(this, emu_thread.get());
+ render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem);
render_window->hide();
game_list = new GameList(vfs, provider.get(), this);
@@ -816,7 +840,7 @@ void GMainWindow::RestoreUIState() {
OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar);
- game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked());
+ game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked());
ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar);
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
@@ -965,13 +989,14 @@ bool GMainWindow::LoadROM(const QString& filename) {
system.SetFilesystem(vfs);
system.SetAppletFrontendSet({
- nullptr, // Parental Controls
- std::make_unique<QtErrorDisplay>(*this), //
- nullptr, // Photo Viewer
- std::make_unique<QtProfileSelector>(*this), //
- std::make_unique<QtSoftwareKeyboard>(*this), //
- std::make_unique<QtWebBrowser>(*this), //
- nullptr, // E-Commerce
+ std::make_unique<QtControllerSelector>(*this), // Controller Selector
+ nullptr, // E-Commerce
+ std::make_unique<QtErrorDisplay>(*this), // Error Display
+ nullptr, // Parental Controls
+ nullptr, // Photo Viewer
+ std::make_unique<QtProfileSelector>(*this), // Profile Selector
+ std::make_unique<QtSoftwareKeyboard>(*this), // Software Keyboard
+ std::make_unique<QtWebBrowser>(*this), // Web Browser
});
system.RegisterHostThread();
@@ -1176,11 +1201,12 @@ void GMainWindow::ShutdownGame() {
render_window->hide();
loading_screen->hide();
loading_screen->Clear();
- if (game_list->isEmpty())
+ if (game_list->IsEmpty()) {
game_list_placeholder->show();
- else
+ } else {
game_list->show();
- game_list->setFilterFocus();
+ }
+ game_list->SetFilterFocus();
setMouseTracking(false);
ui.centralwidget->setMouseTracking(false);
@@ -2046,6 +2072,7 @@ void GMainWindow::OnStartGame() {
emu_thread->SetRunning(true);
+ qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
"Core::Frontend::SoftwareKeyboardParameters");
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
@@ -2213,7 +2240,7 @@ void GMainWindow::OnConfigure() {
const auto old_theme = UISettings::values.theme;
const bool old_discord_presence = UISettings::values.enable_discord_presence;
- ConfigureDialog configure_dialog(this, hotkey_registry);
+ ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get());
connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
&GMainWindow::OnLanguageChanged);
@@ -2337,11 +2364,11 @@ void GMainWindow::OnAbout() {
}
void GMainWindow::OnToggleFilterBar() {
- game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked());
+ game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked());
if (ui.action_Show_Filter_Bar->isChecked()) {
- game_list->setFilterFocus();
+ game_list->SetFilterFocus();
} else {
- game_list->clearFilter();
+ game_list->ClearFilter();
}
}
@@ -2568,8 +2595,10 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
const auto function = [this, &keys, &pdm] {
keys.PopulateFromPartitionData(pdm);
- Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs);
- keys.DeriveETicket(pdm);
+
+ auto& system = Core::System::GetInstance();
+ system.GetFileSystemController().CreateFactories(*vfs);
+ keys.DeriveETicket(pdm, system.GetContentProvider());
};
QString errors;
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 01f9131e5..afcfa68a9 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -37,15 +37,24 @@ enum class InstalledEntryType;
class GameListPlaceholder;
namespace Core::Frontend {
+struct ControllerParameters;
struct SoftwareKeyboardParameters;
} // namespace Core::Frontend
+namespace DiscordRPC {
+class DiscordInterface;
+}
+
namespace FileSys {
class ContentProvider;
class ManualContentProvider;
class VfsFilesystem;
} // namespace FileSys
+namespace InputCommon {
+class InputSubsystem;
+}
+
enum class EmulatedDirectoryTarget {
NAND,
SDMC,
@@ -62,10 +71,6 @@ enum class ReinitializeKeyBehavior {
Warning,
};
-namespace DiscordRPC {
-class DiscordInterface;
-}
-
class GMainWindow : public QMainWindow {
Q_OBJECT
@@ -86,8 +91,6 @@ public:
GMainWindow();
~GMainWindow() override;
- std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
-
bool DropAction(QDropEvent* event);
void AcceptDropEvent(QDropEvent* event);
@@ -114,9 +117,12 @@ signals:
void UpdateInstallProgress();
+ void ControllerSelectorReconfigureFinished();
+
void ErrorDisplayFinished();
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
+
void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
void SoftwareKeyboardFinishedCheckDialog();
@@ -125,6 +131,8 @@ signals:
public slots:
void OnLoadComplete();
+ void ControllerSelectorReconfigureControllers(
+ const Core::Frontend::ControllerParameters& parameters);
void ErrorDisplayDisplayError(QString body);
void ProfileSelectorSelectProfile();
void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
@@ -255,6 +263,9 @@ private:
Ui::MainWindow ui;
+ std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
+ std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
+
GRenderWindow* render_window;
GameList* game_list;
LoadingScreen* loading_screen;
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 87ea985d8..2f3792247 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -293,7 +293,7 @@
<bool>false</bool>
</property>
<property name="text">
- <string>Configure Current Game..</string>
+ <string>Configure Current Game...</string>
</property>
</action>
</widget>
diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp
index a51175f36..37499fc85 100644
--- a/src/yuzu/uisettings.cpp
+++ b/src/yuzu/uisettings.cpp
@@ -16,4 +16,5 @@ const Themes themes{{
}};
Values values = {};
+
} // namespace UISettings
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 2d2e82f15..ce3945485 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -87,9 +87,6 @@ struct Values {
// logging
bool show_console;
- // Controllers
- int profile_index;
-
// Game List
bool show_add_ons;
uint32_t icon_size;
@@ -100,6 +97,7 @@ struct Values {
};
extern Values values;
+
} // namespace UISettings
Q_DECLARE_METATYPE(UISettings::GameDir*);
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 8a63fd191..23448e747 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -288,6 +288,10 @@ void Config::ReadValues() {
Settings::values.debug_pad_analogs[i] = default_param;
}
+ Settings::values.vibration_enabled =
+ sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true);
+ Settings::values.motion_enabled =
+ sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true);
Settings::values.touchscreen.enabled =
sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
Settings::values.touchscreen.device =
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index e5e684206..521209622 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -13,23 +13,24 @@
#include "input_common/sdl/sdl.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
-EmuWindow_SDL2::EmuWindow_SDL2(Core::System& system, bool fullscreen) : system{system} {
+EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_)
+ : input_subsystem{input_subsystem_} {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting...");
exit(1);
}
- InputCommon::Init();
+ input_subsystem->Initialize();
SDL_SetMainReady();
}
EmuWindow_SDL2::~EmuWindow_SDL2() {
- InputCommon::Shutdown();
+ input_subsystem->Shutdown();
SDL_Quit();
}
void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
- InputCommon::GetMotionEmu()->Tilt(x, y);
+ input_subsystem->GetMotionEmu()->Tilt(x, y);
}
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
@@ -41,9 +42,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
}
} else if (button == SDL_BUTTON_RIGHT) {
if (state == SDL_PRESSED) {
- InputCommon::GetMotionEmu()->BeginTilt(x, y);
+ input_subsystem->GetMotionEmu()->BeginTilt(x, y);
} else {
- InputCommon::GetMotionEmu()->EndTilt();
+ input_subsystem->GetMotionEmu()->EndTilt();
}
}
}
@@ -79,9 +80,9 @@ void EmuWindow_SDL2::OnFingerUp() {
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
if (state == SDL_PRESSED) {
- InputCommon::GetKeyboard()->PressKey(key);
+ input_subsystem->GetKeyboard()->PressKey(key);
} else if (state == SDL_RELEASED) {
- InputCommon::GetKeyboard()->ReleaseKey(key);
+ input_subsystem->GetKeyboard()->ReleaseKey(key);
}
}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index fffac4252..53d756c3c 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -14,9 +14,13 @@ namespace Core {
class System;
}
+namespace InputCommon {
+class InputSubsystem;
+}
+
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
public:
- explicit EmuWindow_SDL2(Core::System& system, bool fullscreen);
+ explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem);
~EmuWindow_SDL2();
/// Polls window events
@@ -28,9 +32,6 @@ public:
/// Returns if window is shown (not minimized)
bool IsShown() const override;
- /// Presents the next frame
- virtual void Present() = 0;
-
protected:
/// Called by PollEvents when a key is pressed or released.
void OnKeyEvent(int key, u8 state);
@@ -62,9 +63,6 @@ protected:
/// Called when a configuration change affects the minimal size of the window
void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) override;
- /// Instance of the system, used to access renderer for the presentation thread
- Core::System& system;
-
/// Is the window still open?
bool is_open = true;
@@ -76,4 +74,7 @@ protected:
/// Keeps track of how often to update the title bar during gameplay
u32 last_time = 0;
+
+ /// Input subsystem to use with this window.
+ InputCommon::InputSubsystem* input_subsystem;
};
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index e78025737..5f35233b5 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -87,8 +87,8 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
return unsupported_ext.empty();
}
-EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system, bool fullscreen)
- : EmuWindow_SDL2{system, fullscreen} {
+EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen)
+ : EmuWindow_SDL2{input_subsystem} {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
@@ -162,13 +162,3 @@ EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() {
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const {
return std::make_unique<SDLGLContext>();
}
-
-void EmuWindow_SDL2_GL::Present() {
- SDL_GL_MakeCurrent(render_window, window_context);
- SDL_GL_SetSwapInterval(Settings::values.use_vsync.GetValue() ? 1 : 0);
- while (IsOpen()) {
- system.Renderer().TryPresent(100);
- SDL_GL_SwapWindow(render_window);
- }
- SDL_GL_MakeCurrent(render_window, nullptr);
-}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
index 48bb41683..dba5c293c 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
@@ -8,13 +8,15 @@
#include "core/frontend/emu_window.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
+namespace InputCommon {
+class InputSubsystem;
+}
+
class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 {
public:
- explicit EmuWindow_SDL2_GL(Core::System& system, bool fullscreen);
+ explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen);
~EmuWindow_SDL2_GL();
- void Present() override;
-
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
private:
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
index cb8e68a39..3ba657c00 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
@@ -19,8 +19,8 @@
#include <SDL.h>
#include <SDL_syswm.h>
-EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen)
- : EmuWindow_SDL2{system, fullscreen} {
+EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem)
+ : EmuWindow_SDL2{input_subsystem} {
const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name,
Common::g_scm_branch, Common::g_scm_desc);
render_window =
@@ -73,7 +73,3 @@ EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() = default;
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const {
return std::make_unique<DummyContext>();
}
-
-void EmuWindow_SDL2_VK::Present() {
- // TODO (bunnei): ImplementMe
-}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
index 77a6ca72b..bdfdc3c6f 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
@@ -13,12 +13,14 @@ namespace Core {
class System;
}
+namespace InputCommon {
+class InputSubsystem;
+}
+
class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
public:
- explicit EmuWindow_SDL2_VK(Core::System& system, bool fullscreen);
- ~EmuWindow_SDL2_VK();
-
- void Present() override;
+ explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem);
+ ~EmuWindow_SDL2_VK() override;
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
};
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 8efe49390..3a76c785f 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -23,12 +23,15 @@
#include "common/telemetry.h"
#include "core/core.h"
#include "core/crypto/key_manager.h"
+#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_real.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "core/settings.h"
#include "core/telemetry_session.h"
+#include "input_common/main.h"
#include "video_core/renderer_base.h"
#include "yuzu_cmd/config.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
@@ -37,8 +40,6 @@
#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
#endif
-#include "core/file_sys/registered_cache.h"
-
#ifdef _WIN32
// windows.h needs to be included before shellapi.h
#include <windows.h>
@@ -179,15 +180,16 @@ int main(int argc, char** argv) {
Settings::Apply();
Core::System& system{Core::System::GetInstance()};
+ InputCommon::InputSubsystem input_subsystem;
std::unique_ptr<EmuWindow_SDL2> emu_window;
switch (Settings::values.renderer_backend.GetValue()) {
case Settings::RendererBackend::OpenGL:
- emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen);
+ emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, fullscreen);
break;
case Settings::RendererBackend::Vulkan:
#ifdef HAS_VULKAN
- emu_window = std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen);
+ emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem);
break;
#else
LOG_CRITICAL(Frontend, "Vulkan backend has not been compiled!");
@@ -234,16 +236,15 @@ int main(int argc, char** argv) {
// Core is loaded, start the GPU (makes the GPU contexts current to this thread)
system.GPU().Start();
- system.Renderer().Rasterizer().LoadDiskResources();
+ system.Renderer().Rasterizer().LoadDiskResources(
+ system.CurrentProcess()->GetTitleID(), false,
+ [](VideoCore::LoadCallbackStage, size_t value, size_t total) {});
- std::thread render_thread([&emu_window] { emu_window->Present(); });
system.Run();
while (emu_window->IsOpen()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
system.Pause();
- render_thread.join();
-
system.Shutdown();
detached_tasks.WaitForAllTasks();
diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp
index 74022af23..bc273fb51 100644
--- a/src/yuzu_tester/config.cpp
+++ b/src/yuzu_tester/config.cpp
@@ -75,6 +75,8 @@ void Config::ReadValues() {
Settings::values.debug_pad_analogs[i] = "";
}
+ Settings::values.vibration_enabled = true;
+ Settings::values.motion_enabled = true;
Settings::values.touchscreen.enabled = "";
Settings::values.touchscreen.device = "";
Settings::values.touchscreen.finger = 0;
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp
index 8584f6671..78f75fb38 100644
--- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp
+++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp
@@ -13,7 +13,6 @@
#include <glad/glad.h>
-#include "common/assert.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
#include "core/settings.h"
@@ -53,7 +52,7 @@ EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() {
exit(1);
}
- InputCommon::Init();
+ input_subsystem->Initialize();
SDL_SetMainReady();
@@ -105,7 +104,7 @@ EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() {
}
EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() {
- InputCommon::Shutdown();
+ input_subsystem->Shutdown();
SDL_GL_DeleteContext(gl_context);
SDL_Quit();
}
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h
index c13a82df2..a553b4b95 100644
--- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h
+++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h
@@ -8,6 +8,10 @@
struct SDL_Window;
+namespace InputCommon {
+class InputSubsystem;
+}
+
class EmuWindow_SDL2_Hide : public Core::Frontend::EmuWindow {
public:
explicit EmuWindow_SDL2_Hide();
@@ -25,6 +29,8 @@ private:
/// Whether the GPU and driver supports the OpenGL extension required
bool SupportsRequiredGLExtensions();
+ std::unique_ptr<InputCommon::InputSubsystem> input_subsystem;
+
/// Internal SDL2 render window
SDL_Window* render_window;
diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp
index 7acf0caad..5798ce43a 100644
--- a/src/yuzu_tester/yuzu.cpp
+++ b/src/yuzu_tester/yuzu.cpp
@@ -255,7 +255,6 @@ int main(int argc, char** argv) {
"SDLHideTester");
system.GPU().Start();
- system.Renderer().Rasterizer().LoadDiskResources();
system.Run();
while (!finished) {