Compare commits

...
Author SHA1 Message Date
The412Banner dd511b27e3 test: opt in to the experimental Compose test APIs the drawer key test uses 2026-10-22 00:17:15 +00:00
The412Banner 49cc703662 fix: newest nightly wins a pairing; the page switch exposes its state
nightlyPairs keeps the newest nightly when two match one stable build
(CodeRabbit). The components page switch uses toggleable, so
accessibility services see it as on or off (CodeRabbit).
2026-10-22 00:03:58 +00:00
The412Banner cd7c607e1b fix: Stable/Nightly tabs beside the row in the in-session drawer
The switch sat inside the menu row, whose own A handler and bounds kept a
controller from reaching or flipping it. The drawer now shows the app's
tab strip (TabStrip, without LB/RB, compact) beside the row: D-pad right
from the row reaches Stable, then Nightly; A on a tab picks it and the
row switches to that build; A on the row downloads what it shows. The
components page keeps its switch next to Get.
2026-10-22 00:03:02 +00:00
The412Banner df5e4843ca feat: DroidDeck's linux-nightly components, with a Stable/Nightly switch
The component catalog also reads the linux-nightly release of
Droid-Deck/DroidDeck-Components (hourly builds of DXVK, VKD3D-Proton and
FEX for glibc Protons). That release holds all three components, so each
file goes to its list by name: DD-dxvk-, DD-vkd3d-proton-, DD-FEXCore-.

A nightly that matches a stable build (same flavor and version, e.g.
DD-dxvk-3.1.1+153-nightly and dxvk-3.1.1-linux) has no row of its own:
the stable row gets a Stable | Nightly switch before Get, on the
components page and in the in-session drawer's download menus. Get
downloads whichever the row shows. The switch is styled like the Get
button, is one focus stop and flips with A or a tap. A nightly without a
stable counterpart keeps its own row, listed below the stable ones.

Downloads are allowed from that repository's releases too. A failed
nightly download says the file may have been replaced and asks for a
refresh. Strings in all locales.
2026-10-21 23:39:38 +00:00
MaxsTechReview 8b40bb5c88 fix: Chromium browsers start on the desktop (#1280)
A process's status read for another process is served read-only, so
Chromium's ReadOnlyFile check no longer kills the browser. Chromium-based
AppImages without chrome-sandbox get --no-sandbox, and Flathub Chromium and
Electron apps skip zypak's spawn portal, which cannot work here.
2026-10-21 18:17:07 -04:00
kingokksa a0dbdd6b9a fix: some games never loaded their own Steam touch layout, and the sticks could not be placed (#1058) 2026-10-21 17:39:05 -04:00
Resul Övür aaaa18a7dc fix: manual cloud-save upload/download no longer reports a skipped sync as success (#1068) 2026-10-21 17:32:28 -04:00
Kurt Himebauch da26822714 feat: SteamVR controller types, phone controls on glasses, flat games as VR panels (#1268) 2026-10-21 21:22:21 +00:00
MaxsTechReview c178355d92 perf: performance overlay updates ride the next game frame instead of an extra composite (#1274)
* perf: performance overlay updates ride the next game frame instead of an extra composite

* gamescope: a held overlay repaint is only cleared once an output was painted

* gamescope: release.env points at p12
2026-10-21 17:20:12 -04:00
MaxsTechReview 1be8495ee5 perf: network tables Android refuses are served from the synthesized copy without retrying the open (#1275) 2026-10-21 17:18:11 -04:00
MaxsTechReview 81500fe184 perf: SysV message queues stay mapped instead of reopening per call (#1272) 2026-10-21 17:14:03 -04:00
MaxsTechReview cdc0866cfe perf: games skip Steam's install-script evaluator once it has finished (#1273) 2026-10-21 16:59:52 -04:00
greg 6a3583d744 Add support for Java 17 via mise (#1231) 2026-10-21 18:30:34 +00:00
kingokksa 23bca1b974 fix: give the touch gesture dialog room to scroll on phones (#1214) 2026-10-21 14:14:03 -04:00
Kurt Himebauch d51f8ed4ff feat: Rokid Max and Air glasses with 3DoF, SBS modes, 120 Hz and brightness (#1266) 2026-10-21 14:11:01 -04:00
Kurt Himebauch fba6a5d0f2 feat: Remote Play host: PipeWire capture, hardware encoding, touch and game audio (#1139)
* feat: run SteamOS PipeWire and WirePlumber for gamescope screen capture

* feat: hardware Remote Play encoding through MediaCodec behind Steam's V4L2 stage

* feat: deliver Remote Play touches to gamescope as touches

* feat: route game audio through PulseAudio while a Remote Play client is connected

* fix: keep the Remote Play marker when a forked child closes the encoder

* fix: allow standalone preload tests without V4L2 encoder hook
2026-10-21 17:57:24 +00:00
Kurt Himebauch 4992cf76dd feat: local builds reuse the add-on packs a CI build installed (#1265) 2026-10-21 17:23:16 +00:00
FX1922 c2c80c3540 fix: keep controller focus after installing a boot movie; Xbox and itch artwork covered (#1229) 2026-10-21 13:13:31 -04:00
kingokksa 7d691282fa fix: store dots stay dim when signed out and stores open on the first arranged tab (#1236) 2026-10-21 13:12:49 -04:00
0x1Nawaf dcb269d5ea feat: the performance HUD adds a colored frame-time graph, battery temperature, and opacity controls (#1256) 2026-10-21 13:12:23 -04:00
Kurt Himebauch f67398e6bc feat: Decky Loader update channel selector (#1264) 2026-10-21 17:08:46 +00:00
Kurt Himebauch 003064769d feat: warn before installing a Decky plugin ZIP (#1263) 2026-10-21 12:47:10 -04:00
Kurt Himebauch 9fe8bf6955 fix: keep Steam downloads running across suspend with Manual policy (#1262) 2026-10-21 15:45:39 +00:00
162 changed files with 5122 additions and 781 deletions

No files matched your search

+13
View File
@@ -321,6 +321,17 @@ jobs:
install -Dm644 tools/mangoapp/mangoapp "$D/usr/local/bin/mangoapp"
rm -rf mango-pkgs
ls -l "$M"
mkdir -p pw-pkgs
grep -v '^#' tools/pipewire/packages.txt | while read -r sum url; do
[ -n "$url" ] || continue
curl -fsSL --retry 3 -o pw-pkgs/pkg.tar.zst "$url"
echo "$sum pw-pkgs/pkg.tar.zst" | sha256sum -c -
tar --use-compress-program=unzstd -xf pw-pkgs/pkg.tar.zst -C pw-pkgs
rm pw-pkgs/pkg.tar.zst
done
tools/pipewire/assemble.sh pw-pkgs "$D/usr/local/lib/droiddeck-pipewire.tzst"
rm -rf pw-pkgs
ls -l "$D/usr/local/lib/droiddeck-pipewire.tzst"
T="$D/usr/local/lib/droiddeck-msitools"
mkdir -p "$T" msi-pkgs
grep -v '^#' tools/msitools/packages.txt | while read -r sum url; do
@@ -478,6 +489,8 @@ jobs:
/tmp/test-xr-tracking
g++ -std=c++17 -Wall -Wextra -Werror tools/vr/tests/test_xr_touch.cpp -o /tmp/test-xr-touch
/tmp/test-xr-touch
g++ -std=c++17 -Wall -Wextra -Werror tools/vr/tests/test_pad_controller_config.cpp -o /tmp/test-pad-controller-config
/tmp/test-pad-controller-config
g++ -std=c++17 -Wall -Wextra -Werror -pthread tools/vr/tests/test_xr_vsync.cpp -o /tmp/test-xr-vsync
/tmp/test-xr-vsync
g++ -std=c++17 -Wall -Wextra -Werror -pthread tools/vr/tests/test_xr_frames.cpp -o /tmp/test-xr-frames
+3 -3
View File
@@ -21,7 +21,7 @@ On Android 14 and newer, before Steam launches, you must turn on **Disable child
## Smart glasses
Use **Setup → Smart glasses** for app-wide virtual-screen settings across DroidDeck menus, launchers, desktop sessions, and games. Supported VITURE, RayNeo, and XREAL connections provide 3DoF; Luma Ultra adds optional experimental 6DoF and stereo-assisted hand/Joy-Con tracking. Model support and SDK requirements differ: see the [smart-glasses support matrix](docs/smart-glasses-support.md) for supported devices, controls, setup, and limitations.
Use **Setup → Smart glasses** for app-wide virtual-screen settings across DroidDeck menus, launchers, desktop sessions, and games. Supported VITURE, RayNeo, XREAL, and Rokid connections provide 3DoF; Luma Ultra adds optional experimental 6DoF and stereo-assisted hand/Joy-Con tracking. Model support and SDK requirements differ: see the [smart-glasses support matrix](docs/smart-glasses-support.md) for supported devices, controls, setup, and limitations.
## Community
@@ -49,10 +49,10 @@ Compatibility and performance vary by device; hardware validation is limited. De
GPL-3.0. Runtime, shim, input, and controller work build on WinNative and Bannerlator (maxjivi05). Epic Games and GOG support build on [Phobos’s](https://github.com/phobos665) adaptation of [Legendary](https://github.com/legendary-gl/legendary) and [gogdl](https://github.com/Heroic-Games-Launcher/heroic-gogdl), respectively. The registry entries a GOG game's install script (`goggame-<id>.script`) sets are read the way [Heroic Games Launcher](https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher)'s GOG setup (GPL-3.0) reads them. LSFG frame generation is from the work of Camille LaVey and the [Eden](https://eden-emu.dev) emulator project, following [lsfg-vk](https://github.com/PancakeTAS/lsfg-vk), ported to WinNative and DroidDeck by [@maxjivi05](https://github.com/maxjivi05); it needs your own copy of [Lossless Scaling](https://store.steampowered.com/app/993090/) and ships none of its shaders. x86 AppImages, and any whose own runtime cannot unpack them, are unpacked with [uruntime](https://github.com/VHSgunzo/uruntime) by VHSgunzo (MIT), shipped unmodified with its licence, which also starts the arm64 emulator AppImages whose own runtime cannot run its extractor on Android. The Steam client's audio goes through [@The412Banner](https://github.com/The412Banner)'s [DirectAudio](https://github.com/The412Banner/directaudio) PulseAudio sink (LGPL-2.1-or-later), built from `tools/directaudio/sink` with its request size kept to its ring so clients are not asked to queue 100 ms ahead. mmap ring-buffer controller input was developed by ribbit384 ([WinNative #345](https://github.com/WinNative-Emu/WinNative/pull/345)). Why the x86-64 Steam client refused the arm64 client's sign-in was checked by reading Steam's saved token with the `ConnectCache` format from [deadlock-api-ingest](https://github.com/deadlock-api/deadlock-api-ingest). x86 programs that link OpenSSL 3 under FEX use the copy in the [Steam Linux Runtime 4.0](https://gitlab.steamos.cloud/steamrt/steamrt) platform. Hooks written with `WriteProcessMemory` into code [FEX](https://github.com/FEX-Emu/FEX) has translated go through `/proc/<pid>/mem` again when the kernel refuses `process_vm_writev`, as [Wine](https://gitlab.winehq.org/wine/wine)'s `server/ptrace.c` wrote them before Wine 11. x86 Linux games under FEX get the same `/etc/asound.conf` that [pressure-vessel](https://gitlab.steamos.cloud/steamrt/steam-runtime-tools) writes into the Steam Linux Runtime, so ALSA plays through PulseAudio. Games render with [Mesa](https://gitlab.freedesktop.org/mesa/mesa) Turnip's own per-render-pass choice between tile memory and system memory, while the Steam client keeps `TU_DEBUG=sysmem`; [FEX](https://github.com/FEX-Emu/FEX)'s code disk cache was checked in its source and is already on through Proton. See [LICENSE](LICENSE). Steam and Proton belong to Valve Corporation; this project is not affiliated with Valve.
XR glasses support builds on WinNative's VITURE glasses work. VITURE protocol details were checked against [XRLinuxDriver](https://github.com/wheaney/XRLinuxDriver) by [@wheaney](https://github.com/wheaney), including the VITURE protocol header it ships, [ar-drivers-rs](https://github.com/badicsalex/ar-drivers-rs) by [@badicsalex](https://github.com/badicsalex) and the [go-macos/iokit VITURE package](https://pkg.go.dev/github.com/go-macos/iokit/viture); the optional VITURE SDK belongs to VITURE and is not included. RayNeo support adapts [@informalTechCode](https://github.com/informalTechCode)'s [RayNeo-Air-Series-3DoF-Scaffold](https://github.com/informalTechCode/RayNeo-Air-Series-3DoF-Scaffold) (Apache-2.0) and references [@verncat](https://github.com/verncat)'s [RayNeo-Air-3S-Pro-OpenVR](https://github.com/verncat/RayNeo-Air-3S-Pro-OpenVR) (MIT) and [Monado](https://gitlab.freedesktop.org/monado/monado) (BSL-1.0); see [docs/third-party/rayneo](docs/third-party/rayneo/README.md). XREAL 1S support references [XRLinuxDriver](https://github.com/wheaney/XRLinuxDriver) and [xrealOneDeviceKit](https://github.com/wheaney/xrealOneDeviceKit) by @wheaney, [xreal_one_driver](https://github.com/rohitsangwan01/xreal_one_driver) by [@rohitsangwan01](https://github.com/rohitsangwan01) (MIT) and [xr-tools](https://github.com/0xcaff/xr-tools) by [@0xcaff](https://github.com/0xcaff). The REDMAGIC glasses-display findings draw on [@mekhontsev](https://github.com/mekhontsev)'s [MagicDesk investigation](https://github.com/mekhontsev/magicdesk/blob/main/docs/xr-resolution-fix.md) and [@Coding-BR](https://github.com/Coding-BR)'s [decompiled Nubia kernel](https://github.com/Coding-BR/android_kernel_nubia_sm8850_qwjujube). VITURE, RayNeo, XREAL and REDMAGIC are trademarks of their owners; this project is not affiliated with them.
XR glasses support builds on WinNative's VITURE glasses work. VITURE protocol details were checked against [XRLinuxDriver](https://github.com/wheaney/XRLinuxDriver) by [@wheaney](https://github.com/wheaney), including the VITURE protocol header it ships, [ar-drivers-rs](https://github.com/badicsalex/ar-drivers-rs) by [@badicsalex](https://github.com/badicsalex) and the [go-macos/iokit VITURE package](https://pkg.go.dev/github.com/go-macos/iokit/viture); the optional VITURE SDK belongs to VITURE and is not included. RayNeo support adapts [@informalTechCode](https://github.com/informalTechCode)'s [RayNeo-Air-Series-3DoF-Scaffold](https://github.com/informalTechCode/RayNeo-Air-Series-3DoF-Scaffold) (Apache-2.0) and references [@verncat](https://github.com/verncat)'s [RayNeo-Air-3S-Pro-OpenVR](https://github.com/verncat/RayNeo-Air-3S-Pro-OpenVR) (MIT) and [Monado](https://gitlab.freedesktop.org/monado/monado) (BSL-1.0); see [docs/third-party/rayneo](docs/third-party/rayneo/README.md). XREAL 1S support references [XRLinuxDriver](https://github.com/wheaney/XRLinuxDriver) and [xrealOneDeviceKit](https://github.com/wheaney/xrealOneDeviceKit) by @wheaney, [xreal_one_driver](https://github.com/rohitsangwan01/xreal_one_driver) by [@rohitsangwan01](https://github.com/rohitsangwan01) (MIT) and [xr-tools](https://github.com/0xcaff/xr-tools) by [@0xcaff](https://github.com/0xcaff). Rokid support follows the Rokid protocol notes in [ar-drivers-rs](https://github.com/badicsalex/ar-drivers-rs) and @badicsalex's [Void Computing write-ups](https://voidcomputing.hu/blog/worse-better-prettier/), and [Monado](https://gitlab.freedesktop.org/monado/monado)'s Rokid driver. The REDMAGIC glasses-display findings draw on [@mekhontsev](https://github.com/mekhontsev)'s [MagicDesk investigation](https://github.com/mekhontsev/magicdesk/blob/main/docs/xr-resolution-fix.md) and [@Coding-BR](https://github.com/Coding-BR)'s [decompiled Nubia kernel](https://github.com/Coding-BR/android_kernel_nubia_sm8850_qwjujube). VITURE, RayNeo, XREAL, Rokid and REDMAGIC are trademarks of their owners; this project is not affiliated with them.
Joy-Con VR controllers port the arm model of Google's [Google VR SDK for Unity](https://github.com/googlevr/gvr-unity-sdk) (Apache-2.0), adapt the hand skeleton of Valve's [OpenVR](https://github.com/ValveSoftware/openvr) `handskeletonsimulation` sample (BSD-3-Clause), which follows Moshi Turner's hand simulation in [Monado](https://gitlab.freedesktop.org/monado/monado), and use the Index controller offsets from Monado's `vive_poses.c` (BSL-1.0). Joy-Con behaviour was researched in Linux's [hid-nintendo](https://github.com/torvalds/linux/blob/master/drivers/hid/hid-nintendo.c) driver by Daniel J. Ogorchock, [@dekuNukem](https://github.com/dekuNukem)'s [Nintendo_Switch_Reverse_Engineering](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering), [SDL](https://github.com/libsdl-org/SDL) and the Android Open Source Project, and checked against [ALVR](https://github.com/alvr-org/ALVR), [OpenComposite](https://gitlab.com/znixian/OpenOVR), [PSMoveSteamVRBridge](https://github.com/HipsterSloth/PSMoveSteamVRBridge), [@F8LEFT](https://github.com/F8LEFT)'s [JoyConVr](https://github.com/F8LEFT/JoyConVr), [@krnelpan1c](https://github.com/krnelpan1c)'s [Daydream-Controller-SteamVR](https://github.com/krnelpan1c/Daydream-Controller-SteamVR), [@yoyobuae](https://github.com/yoyobuae)'s [joyconvr](https://github.com/yoyobuae/joyconvr), [Moonlight](https://github.com/moonlight-stream/moonlight-android) and [Dolphin](https://github.com/dolphin-emu/dolphin); see [docs/third-party/joycon](docs/third-party/joycon/README.md). Nintendo Switch and Joy-Con are trademarks of Nintendo; this project is not affiliated with Nintendo.
Camera hand tracking runs Google's [MediaPipe](https://github.com/google-ai-edge/mediapipe) Tasks Vision library with its Pose Landmarker (Lite) model, BlazePose GHUM 3D, and its Hand Landmarker model (all Apache-2.0), on frames from AndroidX [CameraX](https://developer.android.com/jetpack/androidx/releases/camera) (Apache-2.0); MediaPipe's usage reports are switched off. The design was checked against [@F8LEFT](https://github.com/F8LEFT)'s [JoyConVr](https://github.com/F8LEFT/JoyConVr) camera app (MIT), and the short Joy-Con movements follow the accelerometer mode of the [Google VR SDK for Unity](https://github.com/googlevr/gvr-unity-sdk)'s arm model, Eric Foxlin's zero-velocity updates and Frosio, Pedersini and Borghese's accelerometer autocalibration, and the camera and Joy-Con are joined by a Kalman filter (R. E. Kalman, 1960). Bare camera hands take their gestures after [ALVR](https://github.com/alvr-org/ALVR)'s `hand_gestures.rs` (MIT) and Meta Quest's menu pinch, with distances checked on photos from the [HaGRID](https://github.com/hukenovs/hagrid) gesture set (CC BY-SA 4.0, not included), fit the palm with Horn's quaternion method (1987) and smooth it with the 1€ filter (Casiez, Roussel and Vogel, 2012); the white glove model follows Valve's OpenVR render model reference and Index controller poses, is meshed with surface nets (Gibson, 1998; Mikola Lysenko) and blends and shades it with Inigo Quilez's smooth minimum and distance-field ambient occlusion, porting his polygon distance (MIT); see [docs/third-party/handtracking](docs/third-party/handtracking/README.md).
The Store installs and runs apps with [Flatpak](https://github.com/flatpak/flatpak) (LGPL-2.1). Its sandbox goes through DroidDeck's own bubblewrap shim, which follows how Flatpak hands bwrap its environment.
The Store installs and runs apps with [Flatpak](https://github.com/flatpak/flatpak) (LGPL-2.1). Its sandbox goes through DroidDeck's own bubblewrap shim, which follows how Flatpak hands bwrap its environment. Chromium and Electron apps from Flathub start their browser processes through [zypak](https://github.com/refi64/zypak) by [@refi64](https://github.com/refi64) (BSD-3-Clause); its source was read to see that it always spawns them through Flatpak's spawn portal, which is why DroidDeck starts them directly without Chromium's sandbox instead.
+4
View File
@@ -39,6 +39,10 @@ target_link_libraries(deviceinfo dl)
add_library(termux SHARED termux/termux.c)
add_library(ddvenc SHARED venc/venc_server.cpp)
target_compile_features(ddvenc PRIVATE cxx_std_17)
target_link_libraries(ddvenc mediandk log)
# The optional proprietary SDK is supplied locally; its headers/libraries are not vendored.
if(DROIDDECK_VITURE_SDK_DIR)
add_library(droiddeck_viture SHARED viture/sdk_bridge.cpp)
+55
View File
@@ -0,0 +1,55 @@
#ifndef DROIDDECK_VENC_PROTO_H
#define DROIDDECK_VENC_PROTO_H
#include <stdint.h>
/* SOCK_SEQPACKET between the guest's Remote Play hooks and the app: the emulated /dev/video-enc0 and
* MediaCodec encoder, and remote touches. A config carries the buffer memfds (inputs first) as SCM_RIGHTS;
* every frame gets one reply, touches get none. */
#define VENC_MAX_BUFFERS 16
enum venc_msg { VENC_CONFIG = 1, VENC_FRAME = 2, VENC_DONE = 3, VENC_BITRATE = 4, VENC_TOUCH = 5 };
enum venc_touch_action { VENC_TOUCH_DOWN = 0, VENC_TOUCH_MOVE = 1, VENC_TOUCH_UP = 2 };
enum venc_codec { VENC_H264 = 0, VENC_HEVC = 1 };
struct venc_config {
uint32_t type;
uint32_t codec;
uint32_t width, height, stride, rows;
uint32_t fps_num, fps_den;
uint32_t bitrate, peak_bitrate, vbr;
uint32_t gop;
int32_t profile, level;
uint32_t inputs, outputs;
uint32_t input_size, output_size;
};
struct venc_frame {
uint32_t type;
uint32_t input, output;
uint32_t bytes;
uint32_t keyframe;
int64_t pts_us;
};
struct venc_done {
uint32_t type;
int32_t status;
uint32_t bytes;
uint32_t keyframe;
};
struct venc_bitrate {
uint32_t type;
uint32_t bitrate;
};
/* Remote Play's touch-as-mouse turned back into a touch; x and y are fractions of the screen in 1/65535. */
struct venc_touch {
uint32_t type;
uint32_t action;
uint32_t x, y;
};
#endif
+346
View File
@@ -0,0 +1,346 @@
#include <android/log.h>
#include <dlfcn.h>
#include <jni.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaFormat.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
#include <algorithm>
#include <atomic>
#include <cerrno>
#include <cstring>
#include <string>
#include <thread>
#include <vector>
#include "venc_proto.h"
#define LOG(...) __android_log_print(ANDROID_LOG_INFO, "DroidDeckVenc", __VA_ARGS__)
namespace {
struct Mapping {
uint8_t *data = nullptr;
size_t size = 0;
};
constexpr int32_t kColorFormatYuv420SemiPlanar = 21;
constexpr uint32_t kBufferFlagKeyFrame = 1;
constexpr uint32_t kBufferFlagCodecConfig = 2;
constexpr int kTouchWidth = 1920, kTouchHeight = 1080; // InputSpace.kt
constexpr int kRemoteTouchId = 31; // the compositor's last touch slot (MAX_TOUCH_POINTS 32)
int32_t avc_profile(int32_t v4l2) {
switch (v4l2) {
case 0: return 1;
case 1: return 0x10000;
case 2: return 2;
case 3: return 4;
case 4: return 8;
default: return 0;
}
}
class Session {
public:
explicit Session(int fd) : fd_(fd) {}
~Session() {
release();
close(fd_);
}
void run() {
for (;;) {
uint8_t buf[256];
int fds[VENC_MAX_BUFFERS * 2];
int nfds = 0;
ssize_t n = receive(buf, sizeof buf, fds, &nfds);
if (n <= 0) return;
uint32_t type;
memcpy(&type, buf, sizeof type);
if (type == VENC_CONFIG && n == (ssize_t)sizeof(venc_config)) {
venc_config c;
memcpy(&c, buf, sizeof c);
bool ok = configure(c, fds, nfds);
for (int i = 0; i < nfds; i++) close(fds[i]);
reply(ok ? 0 : -1, 0, false);
} else if (type == VENC_FRAME && n == (ssize_t)sizeof(venc_frame)) {
venc_frame f;
memcpy(&f, buf, sizeof f);
uint32_t bytes = 0;
bool key = false;
bool ok = encode(f, &bytes, &key);
reply(ok ? 0 : -1, bytes, key);
} else if (type == VENC_TOUCH && n == (ssize_t)sizeof(venc_touch)) {
venc_touch t;
memcpy(&t, buf, sizeof t);
touch(t);
for (int i = 0; i < nfds; i++) close(fds[i]);
} else if (type == VENC_BITRATE && n == (ssize_t)sizeof(venc_bitrate)) {
venc_bitrate b;
memcpy(&b, buf, sizeof b);
set_bitrate(b.bitrate);
for (int i = 0; i < nfds; i++) close(fds[i]);
} else {
LOG("unexpected message %u of %zd bytes; closing", type, n);
for (int i = 0; i < nfds; i++) close(fds[i]);
return;
}
}
}
private:
ssize_t receive(uint8_t *buf, size_t len, int *fds, int *nfds) {
char control[CMSG_SPACE(sizeof(int) * VENC_MAX_BUFFERS * 2)];
iovec iov = {buf, len};
msghdr m = {};
m.msg_iov = &iov;
m.msg_iovlen = 1;
m.msg_control = control;
m.msg_controllen = sizeof control;
ssize_t n = recvmsg(fd_, &m, MSG_CMSG_CLOEXEC);
for (cmsghdr *c = CMSG_FIRSTHDR(&m); n > 0 && c; c = CMSG_NXTHDR(&m, c)) {
if (c->cmsg_level != SOL_SOCKET || c->cmsg_type != SCM_RIGHTS) continue;
int count = (int)((c->cmsg_len - CMSG_LEN(0)) / sizeof(int));
memcpy(fds, CMSG_DATA(c), sizeof(int) * std::min(count, VENC_MAX_BUFFERS * 2));
*nfds = std::min(count, VENC_MAX_BUFFERS * 2);
}
return n;
}
void reply(int32_t status, uint32_t bytes, bool key) {
venc_done d = {VENC_DONE, status, bytes, key ? 1u : 0u};
send(fd_, &d, sizeof d, MSG_NOSIGNAL);
}
void release() {
if (codec_) {
AMediaCodec_stop(codec_);
AMediaCodec_delete(codec_);
codec_ = nullptr;
}
for (auto &m : inputs_) munmap(m.data, m.size);
for (auto &m : outputs_) munmap(m.data, m.size);
inputs_.clear();
outputs_.clear();
header_.clear();
}
AMediaCodec *create(const venc_config &c, bool with_profile) {
const char *mime = c.codec == VENC_HEVC ? "video/hevc" : "video/avc";
AMediaCodec *codec = AMediaCodec_createEncoderByType(mime);
if (!codec) return nullptr;
float fps = c.fps_num ? (float)c.fps_den / (float)c.fps_num : 60.0f;
AMediaFormat *f = AMediaFormat_new();
AMediaFormat_setString(f, AMEDIAFORMAT_KEY_MIME, mime);
AMediaFormat_setInt32(f, AMEDIAFORMAT_KEY_WIDTH, (int32_t)c.width);
AMediaFormat_setInt32(f, AMEDIAFORMAT_KEY_HEIGHT, (int32_t)c.height);
AMediaFormat_setInt32(f, AMEDIAFORMAT_KEY_COLOR_FORMAT, kColorFormatYuv420SemiPlanar);
AMediaFormat_setInt32(f, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)std::max(c.bitrate, 500000u));
AMediaFormat_setInt32(f, "bitrate-mode", c.vbr ? 1 : 2);
AMediaFormat_setFloat(f, AMEDIAFORMAT_KEY_FRAME_RATE, fps);
AMediaFormat_setFloat(f, "operating-rate", fps);
AMediaFormat_setInt32(f, "priority", 0);
AMediaFormat_setInt32(f, "latency", 1);
AMediaFormat_setInt32(f, "max-bframes", 0);
AMediaFormat_setInt32(f, "prepend-sps-pps-to-idr-frames", 1);
float gop_seconds = c.gop && c.gop < 0xffff ? (float)c.gop / fps : 3600.0f;
AMediaFormat_setFloat(f, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, std::max(gop_seconds, 0.1f));
if (with_profile) {
int32_t profile = c.codec == VENC_HEVC ? (c.profile == 2 ? 2 : 1) : avc_profile(c.profile);
if (profile) AMediaFormat_setInt32(f, "profile", profile);
}
media_status_t s = AMediaCodec_configure(codec, f, nullptr, nullptr, AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
AMediaFormat_delete(f);
if (s == AMEDIA_OK) s = AMediaCodec_start(codec);
if (s != AMEDIA_OK) {
AMediaCodec_delete(codec);
return nullptr;
}
return codec;
}
bool configure(const venc_config &c, const int *fds, int nfds) {
release();
if (c.inputs + c.outputs != (uint32_t)nfds || c.width < 64 || c.height < 64 || c.stride < c.width ||
c.rows < c.height || (uint64_t)c.stride * c.rows * 3 / 2 > c.input_size) {
LOG("bad config: %u+%u buffers for %d fds, %ux%u stride %u", c.inputs, c.outputs, nfds, c.width, c.height,
c.stride);
return false;
}
for (int i = 0; i < nfds; i++) {
bool input = (uint32_t)i < c.inputs;
size_t size = input ? c.input_size : c.output_size;
void *p = mmap(nullptr, size, input ? PROT_READ : PROT_READ | PROT_WRITE, MAP_SHARED, fds[i], 0);
if (p == MAP_FAILED) {
LOG("could not map buffer %d: %s", i, strerror(errno));
release();
return false;
}
(input ? inputs_ : outputs_).push_back({(uint8_t *)p, size});
}
codec_ = create(c, true);
if (!codec_) codec_ = create(c, false);
if (!codec_) {
LOG("no %s encoder for %ux%u", c.codec == VENC_HEVC ? "HEVC" : "H.264", c.width, c.height);
release();
return false;
}
config_ = c;
dst_stride_ = (int32_t)c.width;
dst_rows_ = (int32_t)c.height;
using InputFormat = AMediaFormat *(*)(AMediaCodec *);
static auto input_format = (InputFormat)dlsym(RTLD_DEFAULT, "AMediaCodec_getInputFormat");
if (AMediaFormat *in = input_format ? input_format(codec_) : nullptr) {
int32_t v;
if (AMediaFormat_getInt32(in, "stride", &v) && v >= (int32_t)c.width) dst_stride_ = v;
if (AMediaFormat_getInt32(in, "slice-height", &v) && v >= (int32_t)c.height) dst_rows_ = v;
AMediaFormat_delete(in);
}
LOG("%s %ux%u at %.2f fps, %u kbit/s %s, input stride %d rows %d", c.codec == VENC_HEVC ? "HEVC" : "H.264",
c.width, c.height, c.fps_num ? (double)c.fps_den / c.fps_num : 0.0, c.bitrate / 1000,
c.vbr ? "VBR" : "CBR", dst_stride_, dst_rows_);
return true;
}
static void touch(const venc_touch &t) {
using SendTouch = void (*)(int, int, int, int);
static SendTouch send_touch = [] {
void *wayland = dlopen("libdroiddeckwayland.so", RTLD_NOW | RTLD_NOLOAD);
auto fn = wayland ? (SendTouch)dlsym(wayland, "droiddeck_wayland_send_touch") : nullptr;
if (!fn) LOG("remote touch unavailable: %s", dlerror());
return fn;
}();
if (!send_touch || t.action > VENC_TOUCH_UP) return;
int x = (int)((uint64_t)std::min(t.x, 65535u) * (kTouchWidth - 1) / 65535);
int y = (int)((uint64_t)std::min(t.y, 65535u) * (kTouchHeight - 1) / 65535);
send_touch((int)t.action, kRemoteTouchId, x, y);
}
void set_bitrate(uint32_t bitrate) {
if (!codec_) return;
AMediaFormat *p = AMediaFormat_new();
AMediaFormat_setInt32(p, "video-bitrate", (int32_t)std::max(bitrate, 500000u));
AMediaCodec_setParameters(codec_, p);
AMediaFormat_delete(p);
}
bool encode(const venc_frame &f, uint32_t *bytes, bool *key) {
if (!codec_ || f.input >= inputs_.size() || f.output >= outputs_.size()) return false;
if (f.keyframe) {
AMediaFormat *p = AMediaFormat_new();
AMediaFormat_setInt32(p, "request-sync", 0);
AMediaCodec_setParameters(codec_, p);
AMediaFormat_delete(p);
}
ssize_t in = AMediaCodec_dequeueInputBuffer(codec_, 100000);
if (in < 0) return false;
size_t capacity = 0;
uint8_t *dst = AMediaCodec_getInputBuffer(codec_, (size_t)in, &capacity);
size_t need = (size_t)dst_stride_ * dst_rows_ + (size_t)dst_stride_ * ((config_.height + 1) / 2);
if (!dst || capacity < need) return false;
const uint8_t *src = inputs_[f.input].data;
for (uint32_t y = 0; y < config_.height; y++)
memcpy(dst + (size_t)y * dst_stride_, src + (size_t)y * config_.stride, config_.width);
const uint8_t *src_uv = src + (size_t)config_.stride * config_.rows;
uint8_t *dst_uv = dst + (size_t)dst_stride_ * dst_rows_;
for (uint32_t y = 0; y < (config_.height + 1) / 2; y++)
memcpy(dst_uv + (size_t)y * dst_stride_, src_uv + (size_t)y * config_.stride, config_.width);
if (AMediaCodec_queueInputBuffer(codec_, (size_t)in, 0, need, (uint64_t)std::max<int64_t>(f.pts_us, 0), 0) !=
AMEDIA_OK)
return false;
Mapping &out = outputs_[f.output];
for (int tries = 0; tries < 20; tries++) {
AMediaCodecBufferInfo info;
ssize_t o = AMediaCodec_dequeueOutputBuffer(codec_, &info, 20000);
if (o == AMEDIACODEC_INFO_TRY_AGAIN_LATER || o == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED ||
o == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
continue;
if (o < 0) return false;
size_t size = 0;
uint8_t *data = AMediaCodec_getOutputBuffer(codec_, (size_t)o, &size);
const uint8_t *payload = data ? data + info.offset : nullptr;
size_t length = data ? (size_t)info.size : 0;
if (info.flags & kBufferFlagCodecConfig) {
header_.assign(payload, payload + length);
AMediaCodec_releaseOutputBuffer(codec_, (size_t)o, false);
continue;
}
*key = (info.flags & kBufferFlagKeyFrame) != 0;
bool prepend = *key && !header_.empty() &&
(length < header_.size() || memcmp(payload, header_.data(), header_.size()) != 0);
size_t total = length + (prepend ? header_.size() : 0);
bool fits = payload && total <= out.size;
if (fits) {
if (prepend) memcpy(out.data, header_.data(), header_.size());
memcpy(out.data + (prepend ? header_.size() : 0), payload, length);
*bytes = (uint32_t)total;
}
AMediaCodec_releaseOutputBuffer(codec_, (size_t)o, false);
return fits;
}
return false;
}
int fd_;
AMediaCodec *codec_ = nullptr;
venc_config config_ = {};
int32_t dst_stride_ = 0, dst_rows_ = 0;
std::vector<Mapping> inputs_, outputs_;
std::vector<uint8_t> header_;
};
std::atomic<int> g_listener{-1};
void serve(int listener) {
for (;;) {
int fd = accept4(listener, nullptr, nullptr, SOCK_CLOEXEC);
if (fd < 0) {
if (errno == EINTR) continue;
return;
}
std::thread([fd] {
Session s(fd);
s.run();
}).detach();
}
}
} // namespace
extern "C" JNIEXPORT jboolean JNICALL
Java_com_droiddeck_launcher_session_VideoEncodeBridge_nativeStart(JNIEnv *env, jobject, jstring jpath) {
if (g_listener.load() >= 0) return JNI_TRUE;
const char *path = env->GetStringUTFChars(jpath, nullptr);
sockaddr_un addr = {};
addr.sun_family = AF_UNIX;
bool fits = strlen(path) < sizeof addr.sun_path;
if (fits) strcpy(addr.sun_path, path);
int fd = fits ? socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0) : -1;
if (fd >= 0) {
unlink(path);
if (bind(fd, (sockaddr *)&addr, sizeof addr) != 0 || listen(fd, 4) != 0) {
LOG("could not listen on %s: %s", path, strerror(errno));
close(fd);
fd = -1;
}
}
env->ReleaseStringUTFChars(jpath, path);
if (fd < 0) return JNI_FALSE;
g_listener.store(fd);
std::thread(serve, fd).detach();
return JNI_TRUE;
}
extern "C" JNIEXPORT void JNICALL
Java_com_droiddeck_launcher_session_VideoEncodeBridge_nativeStop(JNIEnv *, jobject) {
int fd = g_listener.exchange(-1);
if (fd >= 0) {
shutdown(fd, SHUT_RDWR);
close(fd);
}
}
@@ -11,29 +11,46 @@ import java.io.File
internal class DeckyMenu(private val activity: android.app.Activity, private val ui: android.os.Handler) {
var deckyInstalled by mutableStateOf<String?>(null)
var deckyReleases by mutableStateOf<List<DeckyManager.Release>>(emptyList())
var deckyLatest by mutableStateOf<DeckyManager.Release?>(null)
var deckyBranch by mutableIntStateOf(DeckyManager.BRANCH_STABLE)
private var deckyChannels = DeckyManager.ReleaseChannels(emptyList(), emptyList())
var deckyChecking by mutableStateOf(false)
var deckyStage by mutableStateOf<String?>(null)
var deckyPercent by mutableIntStateOf(-1)
var deckyDownloadingBinary by mutableStateOf(false)
var deckySupervisor by mutableStateOf(false)
var deckyPendingZip by mutableStateOf<File?>(null)
var deckyReleaseRequest = 0
fun refreshDecky() {
val request = ++deckyReleaseRequest
deckyBranch = DeckyManager.branch(activity)
deckyChecking = true
Thread({
val channels = runCatching { DeckyManager.releaseChannels(activity) }
.getOrElse { DeckyManager.ReleaseChannels(emptyList(), emptyList()) }
ui.post {
if (request == deckyReleaseRequest) {
deckyReleases = channels.stable.ifEmpty { channels.prerelease }
deckyChannels = channels
deckyLatest = DeckyManager.latest(channels, deckyBranch)
deckyChecking = false
}
}
}, "decky-releases").start()
}
fun switchDeckyBranch(branch: Int) {
if (branch == deckyBranch || deckyStage != null || SessionState.running) return
val saved = runCatching { DeckyManager.setBranch(activity, branch) }
if (saved.isFailure) {
android.widget.Toast.makeText(activity, R.string.decky_channel_failed, android.widget.Toast.LENGTH_LONG).show()
return
}
deckyBranch = branch
deckyLatest = DeckyManager.latest(deckyChannels, branch)
refreshDecky()
}
fun installDecky(release: DeckyManager.Release) {
if (deckyStage != null || SessionState.running) return
deckyStage = activity.getString(R.string.store_starting); deckyPercent = -1
@@ -49,6 +66,17 @@ internal class DeckyMenu(private val activity: android.app.Activity, private val
}
fun importPluginZip(archive: File) {
if (deckyStage != null || SessionState.running || deckyInstalled == null) return
deckyPendingZip = archive
}
fun cancelPluginZip() {
deckyPendingZip = null
}
fun confirmPluginZip() {
val archive = deckyPendingZip ?: return
deckyPendingZip = null
if (deckyStage != null || SessionState.running || deckyInstalled == null) return
deckyStage = activity.getString(R.string.decky_plugin_starting); deckyPercent = -1
Thread({
@@ -768,6 +768,9 @@ class MainActivity : ComponentActivity() {
setContent {
DroidDeckTheme(theme, appScale = appScale) {
com.droiddeck.launcher.ui.FocusGlideHost(androidx.compose.ui.Modifier.fillMaxSize().exposeTestTags()) {
if (decky.deckyPendingZip != null) com.droiddeck.launcher.ui.DeckyZipWarningDialog(
onConfirm = { decky.confirmPluginZip() }, onCancel = { decky.cancelPluginZip() },
)
val page: (@Composable () -> Unit)? = when {
showPerformance -> { { PerformanceHost() } }
showComponents -> { { ComponentsHost() } }
@@ -1646,7 +1649,8 @@ class MainActivity : ComponentActivity() {
wifiDiscoveryAsked = wifiDiscoveryAsked,
wifiDiscoveryBlocked = wifiDiscoveryBlocked,
deckyInstalled = if (mode == SessionService.MODE_STEAM) decky.deckyInstalled else null,
deckyLatestRelease = if (mode == SessionService.MODE_STEAM) decky.deckyReleases.firstOrNull() else null,
deckyLatestRelease = if (mode == SessionService.MODE_STEAM) decky.deckyLatest else null,
deckyBranch = decky.deckyBranch,
deckyChecking = decky.deckyChecking, deckyStage = decky.deckyStage, deckyPercent = decky.deckyPercent,
deckyDownloadingBinary = decky.deckyDownloadingBinary,
deckyEnabled = decky.deckySupervisor, deckySessionRunning = SessionState.running,
@@ -1729,6 +1733,7 @@ class MainActivity : ComponentActivity() {
onBootMovieChanged = { loadBootMovie() },
onDeckyInstall = { release -> decky.installDecky(release) },
onDeckyCheck = { decky.refreshDecky() },
onDeckyBranch = { branch -> decky.switchDeckyBranch(branch) },
onDeckyEnabled = { enabled -> DeckyManager.setSupervisorEnabled(this, enabled); decky.deckySupervisor = enabled },
onDeckyUninstall = {
DeckyManager.uninstall(this, wipeData = false)
@@ -29,6 +29,7 @@ import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
@@ -306,6 +307,11 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
private var achievementsInFront by mutableStateOf<AchievementsInFront?>(null)
private var achievementsOpen by mutableStateOf(false)
private var hudOn by mutableStateOf(true)
private var hudFps by mutableStateOf(true)
private var hudBattery by mutableStateOf(true)
private var hudGraph by mutableStateOf(true)
private var hudColor by mutableStateOf(SessionPrefs.HUD_COLOR_MINT)
private var hudOpacity by mutableStateOf(SessionPrefs.HUD_OPACITY_DEFAULT)
private var upscaler by mutableStateOf(0)
private var upscaleSharpness by mutableStateOf(75)
private var effects by mutableStateOf(ScreenEffects.OFF)
@@ -638,8 +644,9 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
com.droiddeck.launcher.ui.FocusGlideHost(androidx.compose.ui.Modifier.fillMaxSize()) {
CursorOverlay({ cursorPos }, cursorVisible, resources.displayMetrics.density,
cursorImage, cursorHotX, cursorHotY, cursorImageScale)
if (hud.text.isNotEmpty()) HudText(hud.text)
if (glassesOutputActive && !loading.visible) com.droiddeck.launcher.ui.GlassesPlayingHint(glasses.model)
if (hud.text.isNotEmpty() || hud.graph.size >= 2) HudText(hud.text, hud.graph, hudColor, hudOpacity)
val phonePanel = glassesOutputActive && !loading.visible && !drawerOpen && !pcKeyboardOpen
if (phonePanel) GlassesPhonePanel(glasses, steamVrStatus == SteamVr.Status.RUNNING, headTracking)
if (trackingRecovery != null && !drawerOpen && !pcKeyboardOpen && !loading.visible) {
androidx.compose.ui.viewinterop.AndroidView(
factory = { com.droiddeck.launcher.ui.TrackingRecoveryView(it) },
@@ -647,14 +654,14 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
update = { it.update(trackingRecovery, !glassesOutputActive && glasses.usable && glasses.sbs) },
)
}
if (GlassesRendering.usesGlasses(glasses, glassesOutputActive, steamVrStatus == SteamVr.Status.RUNNING) &&
if (!phonePanel && GlassesRendering.usesGlasses(glasses, glassesOutputActive, steamVrStatus == SteamVr.Status.RUNNING) &&
headTracking && !drawerOpen && !pcKeyboardOpen && !loading.visible) com.droiddeck.launcher.ui.GlassesRecenterButton(
controllerSettings?.tint ?: android.graphics.Color.rgb(90, 160, 255), controllerSettings?.opacity ?: 100,
onRecenterJoyCons = if (steamVrStatus == SteamVr.Status.RUNNING &&
glasses.usesSpatialControllers(glassesSettings) && glassesSettings.joyConTracking)
joyConVr?.let { { it.recenter() } } else null,
) { headTracker?.recenter() }
if (glasses.present && !drawerOpen && !pcKeyboardOpen && !loading.visible) com.droiddeck.launcher.ui.GlassesCornerButton(glassesSlot,
if (!phonePanel && glasses.present && !drawerOpen && !pcKeyboardOpen && !loading.visible) com.droiddeck.launcher.ui.GlassesCornerButton(glassesSlot,
controllerSettings?.tint ?: android.graphics.Color.rgb(90, 160, 255), controllerSettings?.opacity ?: 100) {
drawerPage = com.droiddeck.launcher.ui.SessionDrawerPage.GLASSES
drawerOpen = true
@@ -752,6 +759,11 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
isHomeApp = isHomeApp,
androidApps = androidApps,
hudOn = hudOn,
hudFps = hudFps,
hudBattery = hudBattery,
hudGraph = hudGraph,
hudColor = hudColor,
hudOpacity = hudOpacity,
upscaler = upscaler, upscaleSharpness = upscaleSharpness,
effects = effects,
cardboard = cardboard,
@@ -779,6 +791,11 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
secondScreenDisplays = secondScreenDisplays,
selectedSecondScreenDisplay = selectedSecondScreenDisplay,
onHud = { on -> SessionPrefs.setHudEnabled(this@SessionActivity, on); hudOn = on; hud.refresh() },
onHudFps = { on -> SessionPrefs.setHudShowFps(this@SessionActivity, on); hudFps = on; hud.refresh() },
onHudBattery = { on -> SessionPrefs.setHudShowBattery(this@SessionActivity, on); hudBattery = on; hud.refresh() },
onHudGraph = { on -> SessionPrefs.setHudShowGraph(this@SessionActivity, on); hudGraph = on; hud.refresh() },
onHudColor = { color -> SessionPrefs.setHudColor(this@SessionActivity, color); hudColor = color },
onHudOpacity = { percent -> SessionPrefs.setHudOpacity(this@SessionActivity, percent); hudOpacity = percent },
onUpscaler = { m ->
SessionPrefs.setUpscaler(this@SessionActivity, m); upscaler = m
WaylandCompositor.nativeSetUpscaler(m)
@@ -998,6 +1015,54 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
}, 90)
}
@androidx.compose.runtime.Composable
private fun GlassesPhonePanel(glasses: com.droiddeck.launcher.glasses.GlassesState, vr: Boolean, headTracking: Boolean) {
val battery by androidx.compose.runtime.produceState<String?>(null) {
while (true) {
val b = registerReceiver(null, android.content.IntentFilter(android.content.Intent.ACTION_BATTERY_CHANGED))
val level = b?.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, -1) ?: -1
val scale = b?.getIntExtra(android.os.BatteryManager.EXTRA_SCALE, 100) ?: 100
val tenths = b?.getIntExtra(android.os.BatteryManager.EXTRA_TEMPERATURE, -1) ?: -1
value = if (level < 0) null else getString(R.string.glasses_phone_battery, level * 100 / scale.coerceAtLeast(1), tenths / 10)
kotlinx.coroutines.delay(30_000)
}
}
val pads = com.droiddeck.launcher.input.VrControllers.settings.collectAsState().value
com.droiddeck.launcher.ui.GlassesPhonePanel(glasses.model, battery, com.droiddeck.launcher.ui.GlassesPhoneActions(
onRecenter = if (headTracking) ({ headTracker?.recenter() }) else null,
onRecenterJoyCons = if (vr && glasses.usesSpatialControllers(glassesSettings) && glassesSettings.joyConTracking)
joyConVr?.let { { it.recenter() } } else null,
onSteamVrMenu = if (vr && SessionState.mode == SessionService.MODE_STEAM) ({ sendSteamGuide() }) else null,
onSwitchSticks = if (vr && pads.emulate != com.droiddeck.launcher.input.VrControllers.Emulate.OFF) ({ switchVrSticks() }) else null,
controllers = getString(when (pads.emulate) {
com.droiddeck.launcher.input.VrControllers.Emulate.OFF -> R.string.vr_controllers_off
com.droiddeck.launcher.input.VrControllers.Emulate.INDEX -> R.string.vr_controllers_index
com.droiddeck.launcher.input.VrControllers.Emulate.TOUCH -> R.string.vr_controllers_touch
com.droiddeck.launcher.input.VrControllers.Emulate.VIVE -> R.string.vr_controllers_vive
}),
onNextControllers = if (vr) ({
val all = com.droiddeck.launcher.input.VrControllers.Emulate.entries
com.droiddeck.launcher.input.VrControllers.setEmulate(this, all[(pads.emulate.ordinal + 1) % all.size])
}) else null,
onKeyboard = { keyboard?.toggle() },
onSessionMenu = { drawerOpen = true },
onStopSteamVr = if (vr) ({ steamVrAction("stop") }) else null,
brightness = glasses.brightness,
brightnessMax = glasses.brightnessMax,
onBrightness = if (glasses.canControl && glasses.hardwareControls) Glasses::setBrightness else null,
))
}
/** The SteamVR driver switches pad sticks between hands and game on both stick clicks together. */
private fun switchVrSticks() {
val chord = { down: Boolean -> padBridge?.applyTouch { state ->
state.press(com.droiddeck.launcher.input.PadState.L3, down)
state.press(com.droiddeck.launcher.input.PadState.R3, down)
} }
chord(true)
uiHandler.postDelayed({ chord(false) }, 120)
}
private fun triggerSteamQam() {
drawerOpen = false
padBridge?.triggerQam()
@@ -1343,6 +1408,11 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
unfoldedControls = SessionPrefs.unfoldedControls(this)
picturePosition = SessionPrefs.picturePosition(this)
hudOn = SessionPrefs.hudEnabled(this)
hudFps = SessionPrefs.hudShowFps(this)
hudBattery = SessionPrefs.hudShowBattery(this)
hudGraph = SessionPrefs.hudShowGraph(this)
hudColor = SessionPrefs.hudColor(this)
hudOpacity = SessionPrefs.hudOpacity(this)
upscaler = SessionPrefs.upscaler(this)
upscaleSharpness = SessionPrefs.upscaleSharpness(this)
effects = SessionPrefs.screenEffects(this)
@@ -1525,6 +1595,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
}
val runtimeDir = File(filesDir, ".wayland-rt").apply { mkdirs() }
FileUtils.copyAsset(this, "wayland/keymap.xkb", File(runtimeDir, "keymap.xkb"))
com.droiddeck.launcher.input.VrControllers.publish(this)
val turnip = TurnipDriver(this)
com.droiddeck.launcher.gpu.DriverSetupLog.write(this, "surface.driver-setup")
@@ -19,7 +19,10 @@ import java.io.FileInputStream
* yet to its pr-N release on DroidDeck-CI. The APK pins the pack's SHA-256, so only the bytes this build
* was made with install, whichever host serves them.
*/
internal class AddonPack(val name: String, private val sha256: String, val size: Long, private val required: List<String>) {
internal class AddonPack(
val name: String, private val sha256: String, val size: Long, private val required: List<String>,
private val reuseDeviceCopy: Boolean = sha256.isEmpty() && !BuildConfig.CI_BUILD,
) {
sealed interface State {
data object Missing : State
data class Downloading(val progress: Float) : State
@@ -40,10 +43,20 @@ internal class AddonPack(val name: String, private val sha256: String, val size:
private fun root(context: Context) = File(context.filesDir, "addons/$name")
/** App-private and written only after the archive matched the pinned digest. */
fun dir(context: Context) = File(root(context), sha256)
fun dir(context: Context) = File(root(context), version(context))
fun file(context: Context, relative: String) = File(dir(context), relative)
fun installed(context: Context): Boolean = available && File(dir(context), COMPLETE).isFile
fun installed(context: Context): Boolean = version(context).isNotEmpty() && File(dir(context), COMPLETE).isFile
// A build made outside CI pins no packs, so it runs the newest one a CI build already verified and installed.
private fun version(context: Context): String = if (!reuseDeviceCopy) sha256 else deviceCopy(context).orEmpty()
private fun deviceCopy(context: Context): String? = root(context).listFiles().orEmpty()
.filter { dir ->
dir.isDirectory && runCatching { File(dir, COMPLETE).readText().trim() }.getOrNull() == dir.name &&
required.all { File(dir, it).isFile }
}
.maxByOrNull { it.lastModified() }?.name
fun refresh(context: Context): State {
val now = mutableState.value
@@ -86,7 +99,7 @@ internal class AddonPack(val name: String, private val sha256: String, val size:
private fun install(context: Context): Boolean {
if (!available) {
Log.w(TAG, "$name: this build has no pack")
Log.w(TAG, if (reuseDeviceCopy) "$name: this build has no pack and none is installed" else "$name: this build has no pack")
return false
}
val root = root(context).apply { mkdirs() }
@@ -50,6 +50,7 @@ data class GlassesState(
val noSignal: Boolean = false,
val sbsSupport: Int = SBS_UNKNOWN,
val sbs90: Boolean = false,
val rates2d: List<Int> = listOf(60, 90, 120),
val experimental: Boolean = false,
val supportsScreen3dof: Boolean = false,
val supports30Hz: Boolean = false,
@@ -613,12 +614,13 @@ object Glasses {
switching3d = modeState.pendingStereo,
brightnessMax = m?.brightnessMax ?: 8, volumeMax = m?.volumeMax ?: 8,
sunblock = if (m === XrealModel) it.sunblock else _settings.value.sunblock ?: it.sunblock,
hardwareControls = device?.vendorId == VitureProtocol.VENDOR_ID || m === XrealModel,
hardwareControls = device?.vendorId == VitureProtocol.VENDOR_ID || m === XrealModel || m is RokidModel,
hasSunblock = m?.hasSunblock == true,
diagonalFovDeg = m?.diagonalFovDeg ?: 46f,
tracking = it.tracking && link != null,
noSignal = noSignal,
sbs90 = m?.sbs90 == true,
rates2d = m?.rates2d ?: listOf(60, 90, 120),
experimental = m === XrealModel,
supportsScreen3dof = link?.hasImu == true,
supports30Hz = display?.let(::supports30Hz) == true,
@@ -634,7 +636,8 @@ object Glasses {
scheduleModeCheck()
}
internal fun isGlassesVendor(vid: Int) = vid == VitureProtocol.VENDOR_ID || RayNeoModel.isVendor(vid) || vid == XrealModel.VENDOR_ID
internal fun isGlassesVendor(vid: Int) = vid == VitureProtocol.VENDOR_ID || RayNeoModel.isVendor(vid) ||
vid == XrealModel.VENDOR_ID || vid == RokidModel.VENDOR_ID
internal fun supports30Hz(display: Display): Boolean {
val current = display.mode
@@ -654,11 +657,13 @@ object Glasses {
?: VitureProtocol.model(device.productId, name)
}
else if (XrealModel.matches(device.vendorId, device.productId)) XrealModel
else RayNeoModel.model(device.vendorId, device.productId, name)
else RokidModel.model(device.vendorId, device.productId, name)
?: RayNeoModel.model(device.vendorId, device.productId, name)
}
internal fun isGlassesDisplayName(name: String) =
name.contains("VITURE", ignoreCase = true) || RayNeoModel.isDisplay(name) || XrealModel.isDisplay(name)
name.contains("VITURE", ignoreCase = true) || RayNeoModel.isDisplay(name) || XrealModel.isDisplay(name) ||
RokidModel.isDisplay(name)
private fun findDisplay(usbPresent: Boolean): Display? {
return selectGlassesDisplay(displays.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION).toList(), usbPresent)
@@ -723,6 +728,8 @@ object Glasses {
} else VitureLink.open(usb, device, linkListener(generation))
} else if (model === XrealModel) {
XrealLink.open(app, xrealListener(generation))
} else if (model is RokidModel) {
RokidLink.open(usb, device, rokidListener(generation))
} else {
val baseKey = calibrationKey!!
val gtUsb = RayNeoProtocol.isGt(device.vendorId, device.productId)
@@ -790,6 +797,33 @@ object Glasses {
}
}
private fun rokidListener(generation: Long) = object : RokidLink.Listener {
override fun onReady() = post {
if (generation != linkGeneration) return@post
publish { it.copy(connected = true, controlError = null) }
updateImu()
applyMode(force = false)
}
override fun onValue(message: Int, value: Int) = post {
if (generation != linkGeneration) return@post
when (message) {
VitureProtocol.MSG_GET_DISPLAY -> glassesMode = value
VitureProtocol.MSG_BRIGHTNESS -> publish { it.copy(brightness = value) }
}
}
override fun onPose(raw: ByteArray, pose: FloatArray, timeNs: Long) {
if (generation != linkGeneration) return
imuPackets++
probe?.invoke(raw, pose)
if (simulating.get() == null) deliver(pose, timeNs)
}
override fun onLost() = post {
if (generation != linkGeneration) return@post
closeLink()
refresh()
}
}
private fun sdkListener(generation: Long) = object : VitureSdkLink.Listener {
override fun onSpatial(pose: FloatArray, timeNs: Long, valid: Boolean) {
if (generation == linkGeneration) SpatialTracking.accept(pose, timeNs, generation, valid)
@@ -8,6 +8,7 @@ interface GlassesModel {
val volumeMax: Int
val diagonalFovDeg: Float
val sbs90: Boolean
val rates2d: List<Int> get() = listOf(60, 90, 120)
val hasSunblock: Boolean get() = true
val resolutions: List<GlassesResolution> get() = emptyList()
fun mode(hz: Int, sbs: Boolean, resolution: GlassesResolution?): Int = mode(hz, sbs)
@@ -12,8 +12,8 @@ internal object GlassesRendering {
fun refreshRates(settings: GlassesSettings, state: GlassesState): List<Int> = buildList {
if (native30HzAvailable(settings, state)) add(30)
add(60)
if (!state.sbs || state.sbs90) add(90)
if (!state.sbs) add(120)
if (state.sbs) { if (state.sbs90) add(90) }
else addAll(state.rates2d.filter { it > 60 })
}
fun outputHz(settings: GlassesSettings, state: GlassesState): Int {
@@ -21,6 +21,7 @@ internal object GlassesRendering {
return when {
requested == 30 -> if (native30HzAvailable(settings, state)) 30 else 60
state.sbs && !state.sbs90 -> 60
!state.sbs && requested !in state.rates2d -> state.rates2d.filter { it <= requested }.maxOrNull() ?: 60
else -> requested
}
}
@@ -0,0 +1,148 @@
package com.droiddeck.launcher.glasses
import android.hardware.usb.UsbConstants
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbEndpoint
import android.hardware.usb.UsbInterface
import android.hardware.usb.UsbManager
import android.os.SystemClock
import android.util.Log
/** Controls are vendor control transfers; the HID interrupt endpoint streams IMU reports unprompted. */
internal class RokidLink private constructor(
private val connection: UsbDeviceConnection,
private val usbInterface: UsbInterface,
private val endpoint: UsbEndpoint,
private val listener: Listener,
) : GlassesLink {
interface Listener {
fun onReady()
fun onValue(message: Int, value: Int)
fun onPose(raw: ByteArray, pose: FloatArray, timeNs: Long)
fun onLost()
}
@Volatile private var running = true
@Volatile override var ready = false
private set
@Volatile private var tracking = false
private val controlLock = Any()
private lateinit var worker: Thread
override val hasImu = true
override fun send(msgId: Int, payload: ByteArray): Boolean {
if (!running) return false
val value = payload.firstOrNull()?.toInt()?.and(0xff) ?: -1
return when (msgId) {
VitureProtocol.MSG_IMU -> (value in 0..1).also { if (it) tracking = value == 1 }
VitureProtocol.MSG_GET_DISPLAY -> display()?.let { listener.onValue(msgId, it) } != null
VitureProtocol.MSG_DISPLAY -> value in RokidModel.MODES &&
control(RokidModel.REQUEST_SET_DISPLAY, value, RokidModel.INDEX_DISPLAY) &&
true.also { listener.onValue(VitureProtocol.MSG_GET_DISPLAY, value) }
VitureProtocol.MSG_GET_BRIGHTNESS -> read(RokidModel.REQUEST_GET_BRIGHTNESS, RokidModel.INDEX_BRIGHTNESS)
?.let { listener.onValue(VitureProtocol.MSG_BRIGHTNESS, RokidModel.brightnessStep(it)) } != null
VitureProtocol.MSG_BRIGHTNESS -> value in 0..RokidModel.BRIGHTNESS_STEPS &&
control(RokidModel.REQUEST_SET_BRIGHTNESS, RokidModel.brightnessRaw(value), RokidModel.INDEX_BRIGHTNESS)
else -> false // Volume is the glasses' USB audio device; there is no film or IMU-rate control.
}
}
private fun display(): Int? = read(RokidModel.REQUEST_GET_DISPLAY, RokidModel.INDEX_DISPLAY)
private fun read(request: Int, index: Int): Int? = synchronized(controlLock) {
if (!running) return null
val buffer = ByteArray(64)
val count = connection.controlTransfer(VENDOR_IN, request, 0, index, buffer, buffer.size, TIMEOUT_MS)
// Display mode is reported in the second byte, brightness in the first.
val offset = if (request == RokidModel.REQUEST_GET_DISPLAY) 1 else 0
if (count > offset) buffer[offset].toInt() and 0xff else null
}
private fun control(request: Int, value: Int, index: Int): Boolean = synchronized(controlLock) {
running && connection.controlTransfer(VENDOR_OUT, request, value, index, byteArrayOf(1), 1, TIMEOUT_MS) >= 0
}
private fun run() {
val buffer = ByteArray(maxOf(endpoint.maxPacketSize, 64))
val parser = RokidProtocol.Parser()
var fusion = ImuFusion()
var wasTracking = false
var brightness = -1
var lastSensor = SystemClock.elapsedRealtime()
try {
ready = true
listener.onReady()
while (running) {
val count = connection.bulkTransfer(endpoint, buffer, buffer.size, 250)
val now = SystemClock.elapsedRealtime()
val sample = if (count > 0) parser.parse(buffer, count) else null
if (sample == null) {
if (now - lastSensor > 3000) error("Rokid IMU stream stalled")
continue
}
lastSensor = now
sample.brightness?.takeIf { it != brightness }?.let {
brightness = it
listener.onValue(VitureProtocol.MSG_BRIGHTNESS, RokidModel.brightnessStep(it))
}
val enabled = tracking
if (enabled && !wasTracking) fusion = ImuFusion()
wasTracking = enabled
if (!enabled) continue
// Max captures: already right/up/back; level gravity +Y, turn left +gyroY, look up +gyroX, roll right -gyroZ.
fusion.update(sample.timeNs, sample.accel, sample.gyro)?.let {
if (running && tracking) listener.onPose(buffer.copyOf(count), it, SystemClock.elapsedRealtimeNanos())
}
}
} catch (e: Exception) {
if (running) Log.w(TAG, "Rokid stream failed", e)
} finally {
ready = false
if (running) listener.onLost()
}
}
override fun close() {
synchronized(controlLock) {
if (!running) return
running = false
}
if (Thread.currentThread() !== worker) worker.join(500)
runCatching { connection.releaseInterface(usbInterface) }
connection.close()
}
companion object {
private const val TAG = "RokidLink"
private const val TIMEOUT_MS = 250
private const val VENDOR_IN = UsbConstants.USB_DIR_IN or UsbConstants.USB_TYPE_VENDOR
private const val VENDOR_OUT = UsbConstants.USB_DIR_OUT or UsbConstants.USB_TYPE_VENDOR
internal fun sensorEndpoint(device: UsbDevice): Pair<UsbInterface, UsbEndpoint>? {
for (i in 0 until device.interfaceCount) {
val iface = device.getInterface(i)
if (iface.interfaceClass != UsbConstants.USB_CLASS_HID) continue
for (e in 0 until iface.endpointCount) {
val endpoint = iface.getEndpoint(e)
if (endpoint.direction == UsbConstants.USB_DIR_IN &&
endpoint.type == UsbConstants.USB_ENDPOINT_XFER_INT) return iface to endpoint
}
}
return null
}
fun open(usb: UsbManager, device: UsbDevice, listener: Listener): RokidLink? {
val (iface, endpoint) = sensorEndpoint(device) ?: return null
val conn = usb.openDevice(device) ?: return null
if (!conn.claimInterface(iface, true)) {
conn.close()
return null
}
return RokidLink(conn, iface, endpoint, listener).also { link ->
link.worker = Thread({ link.run() }, "rokid-imu").apply { isDaemon = true }
link.worker.start()
}
}
}
}
@@ -0,0 +1,104 @@
package com.droiddeck.launcher.glasses
import java.nio.ByteBuffer
import java.nio.ByteOrder
/** Rokid Air/Max share one USB identity; the product string distinguishes them. */
internal class RokidModel private constructor(override val name: String, private val max: Boolean) : GlassesModel {
override val controllable = true
override val brightnessMax = BRIGHTNESS_STEPS
override val volumeMax = 0
override val hasSunblock = false
override val diagonalFovDeg = if (max) 50f else 43f
override val sbs90 = max
override val rates2d = if (max) listOf(60, 120) else listOf(60)
override val resolutions = if (max) listOf(GlassesResolution(1920, 1080), GlassesResolution(1920, 1200))
else listOf(GlassesResolution(1920, 1080))
override fun mode(hz: Int, sbs: Boolean): Int = mode(hz, sbs, null)
override fun mode(hz: Int, sbs: Boolean, resolution: GlassesResolution?): Int = when {
!max -> if (sbs) MODE_SBS_1080_60 else MODE_2D_60
sbs && resolution?.height == 1080 -> MODE_SBS_1080_60
sbs -> if (hz >= 90) MODE_SBS_1200_90 else MODE_SBS_1200_60
hz >= 120 -> MODE_2D_120
else -> MODE_2D_60
}
override fun modeForStep(step: Int): Int? = null
override fun equals(other: Any?) = other is RokidModel && other.name == name && other.max == max
override fun hashCode() = name.hashCode()
companion object {
const val VENDOR_ID = 0x04d2
const val PRODUCT_ID = 0x162f
const val BRIGHTNESS_STEPS = 10
// Vendor control requests, device recipient.
const val REQUEST_SET_DISPLAY = 0x01
const val REQUEST_GET_DISPLAY = 0x81
const val REQUEST_SET_BRIGHTNESS = 0x02
const val REQUEST_GET_BRIGHTNESS = 0x82
const val INDEX_DISPLAY = 0x01
const val INDEX_BRIGHTNESS = 0x02
const val MODE_2D_60 = 0
const val MODE_SBS_1080_60 = 1
const val MODE_2D_120 = 3
const val MODE_SBS_1200_90 = 4
const val MODE_SBS_1200_60 = 5
val MODES = setOf(MODE_2D_60, MODE_SBS_1080_60, MODE_2D_120, MODE_SBS_1200_90, MODE_SBS_1200_60)
// 0x04d2 is a shared vendor ID, so the Rokid product string is required too.
fun model(vid: Int, pid: Int, name: String?): GlassesModel? {
if (vid != VENDOR_ID || pid != PRODUCT_ID) return null
val product = name?.trim()?.takeIf { it.startsWith("Rokid", ignoreCase = true) } ?: return null
return RokidModel(product, product.contains("Max", ignoreCase = true))
}
fun isDisplay(name: String) = name.contains("Rokid", ignoreCase = true)
/** Device brightness is 0..100; the shared slider uses ten steps. */
fun brightnessStep(raw: Int): Int = ((raw.coerceIn(0, 100) + 5) / 10).coerceIn(0, BRIGHTNESS_STEPS)
fun brightnessRaw(step: Int): Int = step.coerceIn(0, BRIGHTNESS_STEPS) * 10
}
}
internal object RokidProtocol {
data class Sample(val timeNs: Long, val accel: Vec3, val gyro: Vec3, val brightness: Int?)
private const val COMBINED = 17
private const val SEPARATE = 4
private const val SENSOR_ACCEL = 1
private const val SENSOR_GYRO = 2
/** Max sends one combined report; Air sends accel and gyro reports that share a timestamp. */
class Parser {
private var accel: Vec3? = null
private var accelTime = -1L
private var gyro: Vec3? = null
private var gyroTime = -2L
fun parse(packet: ByteArray, length: Int = packet.size): Sample? {
if (length < 64) return null
val b = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.LITTLE_ENDIAN)
return when (packet[0].toInt() and 0xff) {
COMBINED -> Sample(b.getLong(1), vec(b, 9), vec(b, 21), packet[59].toInt() and 0xff)
SEPARATE -> {
val time = b.getLong(9) * 1000 // Air reports microseconds; Max reports nanoseconds.
when (packet[1].toInt() and 0xff) {
SENSOR_ACCEL -> { accel = vec(b, 21); accelTime = time }
SENSOR_GYRO -> { gyro = vec(b, 21); gyroTime = time }
else -> return null
}
if (accelTime != gyroTime) return null
Sample(time, accel!!, gyro!!, null).also { accelTime = -1L; gyroTime = -2L }
}
else -> null
}
}
private fun vec(b: ByteBuffer, offset: Int) = Vec3(b.getFloat(offset), b.getFloat(offset + 4), b.getFloat(offset + 8))
}
}
@@ -4,20 +4,27 @@ import kotlin.math.abs
/** 1S radians/sec and device nanoseconds, mapped using directed hardware captures. */
internal class XrealOrientationFilter {
private val fusion = ImuFusion()
// 1S reports right/down/forward. Rotate 180 degrees about X into the
// shared right/up/back basis before either gravity alignment or fusion.
// Captures: level gravity -Y; looking left -gyroY; up +gyroX; right tilt +gyroZ.
fun update(sample: XrealProtocol.Sample): FloatArray? = fusion.update(sample.timeNs,
Vec3(sample.accel.x, -sample.accel.y, -sample.accel.z),
Vec3(sample.gyro.x, -sample.gyro.y, -sample.gyro.z))
}
/** Gyro integration with gravity correction in the shared right/up/back basis, rad/s and device ns. */
internal class ImuFusion {
private var previous = 0L
private var rotation = Quaternion.IDENTITY
private var initialized = false
private var bias = Vec3(0f, 0f, 0f)
fun update(sample: XrealProtocol.Sample): FloatArray? {
if (sample.timeNs <= previous) return null
val dt = if (previous == 0L) 0f else (sample.timeNs - previous) * 1e-9f
previous = sample.timeNs
// 1S reports right/down/forward. Rotate 180 degrees about X into the
// shared right/up/back basis before either gravity alignment or fusion.
// Captures: level gravity -Y; looking left -gyroY; up +gyroX; right tilt +gyroZ.
val accel = Vec3(sample.accel.x, -sample.accel.y, -sample.accel.z)
val gyro = Vec3(sample.gyro.x, -sample.gyro.y, -sample.gyro.z)
fun update(timeNs: Long, accel: Vec3, gyro: Vec3): FloatArray? {
if (timeNs <= previous) return null
val dt = if (previous == 0L) 0f else (timeNs - previous) * 1e-9f
previous = timeNs
val norm = accel.length()
val gravityValid = abs(norm - 9.81f) < 1.5f
if (dt > 0.25f) initialized = false // Never integrate a reconnect/stall as motion.
@@ -211,7 +211,7 @@ object SteamTouchBindings {
fun libraryDir(context: Context) = File(SteamTouchConfig.steamRoot(context), "tenfoot/resource/images/library/controller/binding_icons")
fun gameIconsDir(context: Context, appId: Int): File? = try {
val manifest = File(SteamTouchConfig.steamRoot(context), "steamapps/appmanifest_$appId.acf")
val manifest = File(SteamTouchConfig.steamRoot(context), "steamapps/appmanifest_${SteamTouchConfig.steamId(appId)}.acf")
val installDir = KeyValues.parse(manifest.readText()).let { it.child("AppState") ?: it }.string("installdir")
installDir?.let { File(SteamTouchConfig.steamRoot(context), "steamapps/common/$it/TouchMenuIcons") }?.takeIf { it.isDirectory }
} catch (_: Exception) {
@@ -126,7 +126,11 @@ object SteamTouchConfig {
}
}
private val DEFAULT_SET = setOf(DPAD, A, B, X, Y, SELECT, START)
private val DEFAULT_SET = setOf(
JOYSTICK_LEFT, JOYSTICK_LEFT_BUTTON, JOYSTICK_RIGHT, JOYSTICK_RIGHT_BUTTON,
DPAD, A, B, X, Y, SELECT, START,
BUMPER_LEFT, BUMPER_RIGHT, TRIGGER_LEFT, TRIGGER_RIGHT,
)
private val ALWAYS = setOf(STEAM, THUMB, KEYBOARD)
fun steamId(appId: Int): String = Integer.toUnsignedString(appId)
@@ -301,9 +301,8 @@ class SteamTouchControls(
}
}
SteamTouchConfig.STEAM -> {
if (pressed) canvas.drawCircle(x, y, r, fill)
canvas.drawCircle(x, y, r, stroke)
drawMark(canvas, x, y, r * 0.5f, if (pressed) Color.argb(alpha, 23, 26, 33) else ink, alpha)
if (isSelected) canvas.drawCircle(x, y, r, stroke)
drawMark(canvas, x, y, r * 0.5f, if (pressed) accent else ink, alpha)
}
SteamTouchConfig.SELECT, SteamTouchConfig.START -> {
val binding = visuals[e.type]?.firstOrNull()?.binding
@@ -0,0 +1,58 @@
package com.droiddeck.launcher.input
import android.content.Context
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import java.io.File
/** What SteamVR sees for the game pad. The driver reads the file once, when SteamVR starts. */
object VrControllers {
enum class Emulate(val key: String) { OFF("off"), INDEX("index"), TOUCH("touch"), VIVE("vive") }
data class Settings(val emulate: Emulate = Emulate.INDEX, val sticksMoveHands: Boolean = false)
const val FILE = "droiddeck-vr-controllers"
private const val PREFS = "vr_controllers"
private val _settings = MutableStateFlow(Settings())
val settings: StateFlow<Settings> = _settings.asStateFlow()
private var loaded = false
fun load(context: Context): Settings {
if (!loaded) {
val p = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
_settings.value = Settings(
emulate = Emulate.entries.firstOrNull { it.key == p.getString("emulate", null) } ?: Emulate.INDEX,
sticksMoveHands = p.getBoolean("sticksMoveHands", false),
)
loaded = true
}
return _settings.value
}
fun setEmulate(context: Context, emulate: Emulate) = save(context, load(context).copy(emulate = emulate))
fun setSticksMoveHands(context: Context, on: Boolean) = save(context, load(context).copy(sticksMoveHands = on))
private fun save(context: Context, settings: Settings) {
_settings.value = settings
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE).edit()
.putString("emulate", settings.emulate.key)
.putBoolean("sticksMoveHands", settings.sticksMoveHands)
.apply()
publish(context)
}
fun encode(settings: Settings): String =
"emulate=${settings.emulate.key}\nsticks=${if (settings.sticksMoveHands) "hands" else "game"}\n"
/** Writes into the session's runtime dir, which the guest sees as /run/droiddeck. */
fun publish(context: Context) {
runCatching {
val dir = File(context.filesDir, ".wayland-rt").apply { mkdirs() }
val tmp = File(dir, "$FILE.tmp")
tmp.writeText(encode(load(context)))
tmp.renameTo(File(dir, FILE))
}
}
}
@@ -181,6 +181,7 @@ object BwrapSpawner {
request.optJSONObject("env")?.let { e -> e.keys().forEach { k -> env[k] = e.getString(k) } }
if (binds.any { it.guest == "/dev" }) gpu(rootfs, root, env)?.forEach { addBind(it) }
preload(session, rootfs, env).forEach { addBind(it) }
zypakShims(binds, root, dir).forEach { addBind(it) }
browserSandboxes(env)
return Plan(root, binds, request.optString("cwd", "/").ifEmpty { "/" }, argv, env)
}
@@ -227,6 +228,20 @@ object BwrapSpawner {
private const val PRELOAD_DIR = "/run/droiddeck-preload"
private const val ZYPAK_SHIM = "#!/bin/sh\nprogram=\$1\nshift\nexec \"\$program\" --no-sandbox \"\$@\"\n"
private fun zypakShims(binds: List<Bind>, root: File, dir: File): List<Bind> {
val wrappers = listOf("/app/bin/zypak-wrapper.sh", "/app/bin/zypak-wrapper").filter { guest ->
val host = File(hostPath(binds, root.path, guest))
host.isFile && !Files.isSymbolicLink(host.toPath())
}
if (wrappers.isEmpty()) return emptyList()
val shim = File(dir, "zypak-wrapper")
shim.writeText(ZYPAK_SHIM)
chmod(shim, 0x1ed)
return wrappers.map { Bind(shim.path, it) }
}
private fun browserSandboxes(env: MutableMap<String, String>) {
env.putIfAbsent("ZYPAK_ZYGOTE_STRATEGY_SPAWN", "0")
env.putIfAbsent("QTWEBENGINE_DISABLE_SANDBOX", "1")
@@ -22,6 +22,7 @@ object DeckyManager {
private const val RELEASES = "https://api.github.com/repos/$REPOSITORY/releases?per_page=30"
private const val PATH = "root/homebrew/services/PluginLoader"
private const val VERSION = "root/homebrew/services/.droiddeck-decky-version"
private const val SETTINGS = "root/homebrew/settings/loader.json"
// droiddeck-session reads the marker from the root of the client it runs.
private val CEF_REMOTE_DEBUG_MARKERS = listOf(
"root/.local/share/Steam/.cef-enable-remote-debugging",
@@ -32,7 +33,34 @@ object DeckyManager {
private set
data class Release(val tag: String, val prerelease: Boolean, val asset: String, val url: String, val digest: String?, val shaUrl: String?, val size: Long, val machine: Int)
data class ReleaseChannels(val stable: List<Release>, val prerelease: List<Release>)
data class ReleaseChannels(val stable: List<Release>, val prerelease: List<Release>, val all: List<Release> = stable + prerelease)
const val BRANCH_STABLE = 0
const val BRANCH_PRERELEASE = 1
const val BRANCH_TESTING = 2
private fun settingsFile(context: Context) = File(LinuxRuntime.rootDir(context), SETTINGS)
fun branch(context: Context): Int {
val saved = runCatching { JSONObject(settingsFile(context).readText()).optInt("branch", -1) }.getOrDefault(-1)
if (saved >= 0) return saved
val version = File(LinuxRuntime.rootDir(context), VERSION).takeIf { it.isFile }?.readText()?.trim().orEmpty()
return if (version.startsWith("v") && "-pre" in version) BRANCH_PRERELEASE else BRANCH_STABLE
}
fun setBranch(context: Context, branch: Int) {
val file = settingsFile(context)
val settings = runCatching { JSONObject(file.readText()) }.getOrDefault(JSONObject())
settings.put("branch", branch)
file.parentFile?.mkdirs()
val staged = File(file.parentFile, "${file.name}.tmp")
staged.writeText(settings.toString(4))
check(staged.renameTo(file)) { "cannot write ${file.path}" }
}
// Mirrors Decky's updater: Stable takes the newest non-prerelease tag, Prerelease the newest tag of either kind.
fun latest(channels: ReleaseChannels, branch: Int): Release? =
if (branch == BRANCH_STABLE) channels.stable.firstOrNull() else channels.all.firstOrNull()
fun installed(context: Context): String? {
val loader = loader(context)
@@ -74,17 +102,13 @@ object DeckyManager {
}
}
fun releases(context: Context, prerelease: Boolean): List<Release> {
val channels = releaseChannels(context)
return if (prerelease) channels.prerelease else channels.stable
}
fun releaseChannels(context: Context): ReleaseChannels {
val body = Downloader.downloadString(RELEASES) ?: return ReleaseChannels(emptyList(), emptyList())
return try {
val array = JSONArray(body)
val stable = mutableListOf<Release>()
val prerelease = mutableListOf<Release>()
val all = mutableListOf<Release>()
for (i in 0 until array.length()) {
val release = array.getJSONObject(i)
if (release.optBoolean("draft", false)) continue
@@ -105,9 +129,11 @@ object DeckyManager {
val size = binary.optLong("size", 0)
if (size <= 0) continue
val row = Release(release.optString("tag_name", "unknown"), isPrerelease, name, url, digest, checksum, size, if (name == "PluginLoader-arm64") 183 else 62)
(if (isPrerelease) prerelease else stable).add(row)
if (!row.tag.startsWith("v")) continue
all.add(row)
(if (isPrerelease || "-pre" in row.tag) prerelease else stable).add(row)
}
ReleaseChannels(stable, prerelease)
ReleaseChannels(stable, prerelease, all)
} catch (e: Exception) { Log.w(TAG, "release metadata", e); ReleaseChannels(emptyList(), emptyList()) }
}
@@ -25,6 +25,8 @@ import java.io.FileOutputStream
object ComponentsManager {
private const val TAG = "Components"
private const val NIGHTLIES = "The412Banner/Nightlies"
private const val DD_COMPONENTS = "Droid-Deck/DroidDeck-Components"
internal const val DD_NIGHTLY = "linux-nightly"
private val RELEASES = linkedMapOf(
"FexCore-Linux" to "fex",
"Dxvk-Linux" to "dxvk",
@@ -32,6 +34,10 @@ object ComponentsManager {
"Dxvk-gplasync-Linux" to "dxvk",
"Vkd3d-proton-Linux" to "vkd3d",
)
// DD_NIGHTLY holds every component in one release; the file name says which.
private val NIGHTLY_PREFIXES = linkedMapOf("DD-dxvk-" to "dxvk", "DD-vkd3d-proton-" to "vkd3d", "DD-FEXCore-" to "fex")
private val SOURCES = RELEASES.keys.map { NIGHTLIES to it } + (DD_COMPONENTS to DD_NIGHTLY)
private val DOWNLOAD_REPOS = listOf(NIGHTLIES, DD_COMPONENTS)
private val TYPES = mapOf("FEXCore-Linux" to "fex", "DXVK-Linux" to "dxvk", "VKD3D-Linux" to "vkd3d")
private val TYPE_OF = mapOf("fex" to "FEXCore-Linux", "dxvk" to "DXVK-Linux", "vkd3d" to "VKD3D-Linux")
val COMPONENTS = listOf("fex", "dxvk", "vkd3d")
@@ -815,14 +821,15 @@ object ComponentsManager {
if (!force && cache.isFile) runCatching { return parseCatalog(JSONObject(cache.readText())) }
if (!force) return Catalog(emptyList(), 0)
val items = JSONArray()
for ((tag, comp) in RELEASES) {
val body = Downloader.downloadString("https://api.github.com/repos/$NIGHTLIES/releases/tags/$tag") ?: continue
for ((repo, tag) in SOURCES) {
val body = Downloader.downloadString("https://api.github.com/repos/$repo/releases/tags/$tag") ?: continue
val assets = runCatching { JSONObject(body).optJSONArray("assets") }.getOrNull() ?: continue
for (i in 0 until assets.length()) {
val a = assets.getJSONObject(i)
val name = a.optString("name")
if (!name.endsWith(".wcp")) continue
if (!Hashes.isGithubSha256(a.optString("digest"))) continue
val comp = assetComp(tag, name) ?: continue
items.put(JSONObject().put("file", name).put("comp", comp).put("release", tag)
.put("url", a.optString("browser_download_url")).put("size", a.optLong("size")).put("digest", a.optString("digest")))
}
@@ -837,10 +844,32 @@ object ComponentsManager {
val arr = o.optJSONArray("items") ?: JSONArray()
val items = (0 until arr.length()).map { arr.getJSONObject(it) }.map {
CatalogItem(it.optString("file"), it.optString("comp"), it.optString("release"), it.optString("url"), it.optLong("size"), it.optString("digest"))
}.sortedWith(compareBy<CatalogItem> { it.comp }.then(newestFirst { it.file }))
}.sortedWith(CATALOG_ORDER)
return Catalog(items, o.optLong("fetchedAt"))
}
internal fun assetComp(release: String, name: String): String? =
RELEASES[release] ?: if (release == DD_NIGHTLY) NIGHTLY_PREFIXES.entries.firstOrNull { name.startsWith(it.key) }?.value else null
// Per component: the stable packages newest first, then the nightlies.
internal val CATALOG_ORDER: Comparator<CatalogItem> =
compareBy<CatalogItem> { it.comp }.thenBy { it.release == DD_NIGHTLY }.then(newestFirst { it.file })
// A nightly DD-<flavor>-<version>[+N]-nightly.wcp pairs with the newest stable <flavor>-<version>[-<rev>]-linux.wcp
// in the same list, so the stable row can offer it behind a Stable/Nightly switch. Unpaired nightlies keep their own row.
internal fun nightlyPairs(items: List<CatalogItem>): Map<CatalogItem, CatalogItem> {
val stable = items.filter { it.release != DD_NIGHTLY }
return items.filter { it.release == DD_NIGHTLY }.mapNotNull { n ->
val base = n.file.removePrefix("DD-").removeSuffix("-nightly.wcp").substringBefore('+')
val rev = Regex(Regex.escape(base) + "(-\\d+)?-linux\\.wcp")
stable.filter { it.comp == n.comp && rev.matches(it.file) }
.maxWithOrNull { a, b -> ProtonExtras.compareVersions(a.file, b.file) }?.let { it to n }
}.groupBy({ it.first }, { it.second })
.mapValues { (_, ns) -> ns.maxWith { a, b -> ProtonExtras.compareVersions(a.file, b.file) } }
}
internal fun allowedDownload(url: String) = DOWNLOAD_REPOS.any { url.startsWith("https://github.com/$it/releases/download/") }
private fun <T> newestFirst(of: (T) -> String): Comparator<T> =
Comparator { a, b -> ProtonExtras.compareVersions(of(b), of(a)) }
@@ -925,11 +954,13 @@ object ComponentsManager {
): CatalogItem? = catalogMatch(cached(), file, release) ?: catalogMatch(refresh(), file, release)
fun download(context: Context, item: CatalogItem, progress: (Int) -> Unit): Package {
require(item.url.startsWith("https://github.com/$NIGHTLIES/releases/download/")) { context.getString(R.string.cmgr_nightlies_only) }
require(allowedDownload(item.url)) { context.getString(R.string.cmgr_nightlies_only) }
require(Hashes.isGithubSha256(item.digest)) { context.getString(R.string.cmgr_list_predates_checksums) }
val dest = File(packagesDir(context), safeName(item.file))
val part = File(dest.parentFile, dest.name + ".part")
check(Downloader.downloadFile(item.url, part, true, item.digest.substringAfter(':')) { f -> progress(if (f < 0) -1 else (f * 100).toInt().coerceIn(0, 100)) }) { context.getString(R.string.user_apps_download_failed) }
check(Downloader.downloadFile(item.url, part, true, item.digest.substringAfter(':')) { f -> progress(if (f < 0) -1 else (f * 100).toInt().coerceIn(0, 100)) }) {
context.getString(if (item.release == DD_NIGHTLY) R.string.cmgr_nightly_replaced else R.string.user_apps_download_failed)
}
if (!Hashes.sha256(part).equals(item.digest.substringAfter(':'), true)) { part.delete(); error(context.getString(R.string.cmgr_checksum_mismatch)) }
val info = runCatching { packageInfo(context, part) }.getOrElse { part.delete(); throw it }
synchronized(lock) { part.renameTo(dest) }
@@ -1,6 +1,9 @@
package com.droiddeck.launcher.session
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Environment
import android.os.Handler
import android.os.Looper
@@ -15,21 +18,35 @@ import com.droiddeck.launcher.wayland.WaylandCompositor
import java.io.File
import java.util.Locale
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong
class PerfHud(context: Context) {
var text by mutableStateOf("")
private set
var graph by mutableStateOf(FloatArray(0))
private set
private val context = context.applicationContext
private val frames = AtomicInteger()
private var lastTick = 0L
private var lastFps = 0f
private var running = false
private val handler = Handler(Looper.getMainLooper())
private val intervals = FloatArray(GRAPH)
private val graphWrite = AtomicInteger()
private val lastFrameNs = AtomicLong()
@Volatile private var showFps = true
@Volatile private var showBattery = true
@Volatile private var showGraph = true
private val enabled: Boolean
get() = SessionPrefs.hudEnabled(context)
&& !File(Environment.getExternalStorageDirectory(), "Download/droiddeck-no-hud").exists()
private val anyPart: Boolean
get() = showFps || showBattery || showGraph
var onPresentingWindowChanged: (() -> Unit)? = null
private var lastWindow: String? = null
@@ -40,7 +57,17 @@ class PerfHud(context: Context) {
handler.post { onPresentingWindowChanged?.invoke() }
}
}
override fun onGameFrame() { frames.incrementAndGet() }
override fun onGameFrame() {
frames.incrementAndGet()
if (!showGraph) return
val now = System.nanoTime()
val previous = lastFrameNs.getAndSet(now)
if (previous == 0L) return
val ms = ((now - previous) / 1_000_000f).coerceIn(0f, 50f)
val slot = graphWrite.get()
intervals[slot and (GRAPH - 1)] = ms
graphWrite.compareAndSet(slot, slot + 1)
}
}
private val tick = object : Runnable {
@@ -49,28 +76,82 @@ class PerfHud(context: Context) {
val now = SystemClock.elapsedRealtime()
val dt = (now - lastTick).coerceAtLeast(1L) / 1000f
lastTick = now
text = line(frames.getAndSet(0) / dt)
handler.postDelayed(this, 1000)
lastFps = frames.getAndSet(0) / dt
text = readout(lastFps)
if (showGraph) publishGraph() else clearGraph()
handler.postDelayed(this, TICK_MS)
}
}
fun refresh() {
if (enabled) start() else stop()
readOptions()
if (!enabled || !anyPart) {
stop()
return
}
if (!running) start() else {
if (!showGraph) clearGraph() else publishGraph()
text = readout(lastFps)
}
}
fun start() {
if (!enabled || running) return
readOptions()
if (!enabled || !anyPart || running) return
running = true
lastTick = SystemClock.elapsedRealtime()
lastFrameNs.set(0L)
frames.set(0)
graphWrite.set(0)
WaylandCompositor.setGameListener(listener)
handler.post(tick)
handler.postDelayed(tick, TICK_MS)
}
fun stop() {
running = false
handler.removeCallbacks(tick)
WaylandCompositor.clearGameListener(listener)
text = ""
graph = FloatArray(0)
}
private fun readOptions() {
showFps = SessionPrefs.hudShowFps(context)
showBattery = SessionPrefs.hudShowBattery(context)
showGraph = SessionPrefs.hudShowGraph(context)
}
private fun readout(fpsValue: Float): String {
val parts = ArrayList<String>(2)
if (showFps) parts.add(line(fpsValue))
if (showBattery) batteryCelsius(readBatteryDeci())?.let { parts.add(it) }
return parts.joinToString("\n")
}
private fun readBatteryDeci(): Int {
val sticky = runCatching {
context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
}.getOrNull() ?: return 0
return sticky.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0)
}
private fun clearGraph() {
lastFrameNs.set(0L)
graphWrite.set(0)
if (graph.isNotEmpty()) graph = FloatArray(0)
}
private fun publishGraph() {
val count = graphWrite.get()
val shown = minOf(count, GRAPH)
if (shown < 2) {
graph = FloatArray(0)
return
}
val out = FloatArray(shown)
val start = count - shown
for (i in 0 until shown) out[i] = intervals[(start + i) and (GRAPH - 1)]
graph = out
}
private fun line(base: Float): String {
@@ -91,4 +172,12 @@ class PerfHud(context: Context) {
}
private fun fps(value: Float) = String.format(Locale.US, "%.0f fps", value)
companion object {
private const val TICK_MS = 1_000L
private const val GRAPH = 128
internal fun batteryCelsius(deci: Int): String? =
if (deci <= 0) null else String.format(Locale.US, "%.1f°C", deci / 10f)
}
}
@@ -82,8 +82,10 @@ object SessionFiles {
"usr/local/bin/droiddeck-x64-arm-webhelper" to "usr/local/bin/droiddeck-x64-arm-webhelper",
"usr/local/bin/droiddeck-x64-webhelper" to "usr/local/bin/droiddeck-x64-webhelper",
"usr/local/bin/droiddeck-steamvr" to "usr/local/bin/droiddeck-steamvr",
"usr/local/bin/droiddeck-pipewire" to "usr/local/bin/droiddeck-pipewire",
"usr/local/bin/droiddeck-steamvr-settings" to "usr/local/bin/droiddeck-steamvr-settings",
"usr/local/bin/droiddeck-steamvr-game" to "usr/local/bin/droiddeck-steamvr-game",
"usr/local/bin/droiddeck-steamvr-flat" to "usr/local/bin/droiddeck-steamvr-flat",
"usr/local/bin/droiddeck-bwrap" to "usr/local/bin/droiddeck-bwrap",
"usr/local/bin/droiddeck-flatpak" to "usr/local/bin/droiddeck-flatpak",
"usr/local/bin/droiddeck-flatpak-setup" to "usr/local/bin/droiddeck-flatpak-setup",
@@ -137,6 +139,7 @@ object SessionFiles {
val optional = (arrayOf(
"usr/local/bin/gamescope" to "usr/local/bin/gamescope",
"usr/local/lib/droiddeck/uruntime" to "usr/local/lib/droiddeck/uruntime",
"usr/local/lib/droiddeck-pipewire.tzst" to "usr/local/lib/droiddeck-pipewire.tzst",
"usr/local/share/licenses/uruntime/LICENSE" to "usr/local/share/licenses/uruntime/LICENSE",
) + mangoapp + msitools.map { it to it } + vr + fexPreloads).filter { (asset, _) ->
val dir = asset.substringBeforeLast('/')
@@ -21,6 +21,7 @@ object SessionPrefs {
const val SUSPEND_NEVER = "never"
private const val LEGACY_SUSPEND_DOWNLOADS = "downloads"
private const val STEAM_DOWNLOADS_IN_BACKGROUND = "steamDownloadsInBackground"
private const val DECKY_ZIP_WARNING_SEEN = "deckyZipWarningSeen"
const val CONTROLLER_DECK = "deck"
const val CONTROLLER_XBOX360 = "xbox360"
@@ -156,6 +157,43 @@ object SessionPrefs {
prefs(context).edit().putBoolean(hudKey(context), on).apply()
}
fun hudShowFps(context: Context): Boolean = prefs(context).getBoolean("hudFps", true)
fun setHudShowFps(context: Context, on: Boolean) {
prefs(context).edit().putBoolean("hudFps", on).apply()
}
fun hudShowBattery(context: Context): Boolean = prefs(context).getBoolean("hudBattery", true)
fun setHudShowBattery(context: Context, on: Boolean) {
prefs(context).edit().putBoolean("hudBattery", on).apply()
}
fun hudShowGraph(context: Context): Boolean = prefs(context).getBoolean("hudGraph", true)
fun setHudShowGraph(context: Context, on: Boolean) {
prefs(context).edit().putBoolean("hudGraph", on).apply()
}
fun hudColor(context: Context): String =
prefs(context).getString("hudColor", HUD_COLOR_MINT)?.takeIf { it in HUD_COLORS } ?: HUD_COLOR_MINT
fun setHudColor(context: Context, color: String) {
if (color in HUD_COLORS) prefs(context).edit().putString("hudColor", color).apply()
}
fun hudOpacity(context: Context): Int =
prefs(context).getInt("hudOpacity", HUD_OPACITY_DEFAULT).takeIf { it in HUD_OPACITY_RANGE } ?: HUD_OPACITY_DEFAULT
fun setHudOpacity(context: Context, percent: Int) {
prefs(context).edit().putInt("hudOpacity", percent.coerceIn(HUD_OPACITY_RANGE)).apply()
}
const val HUD_COLOR_MINT = "mint"
val HUD_COLORS = listOf(HUD_COLOR_MINT, "white", "sky", "amber", "violet")
val HUD_OPACITY_RANGE = 30..100
const val HUD_OPACITY_DEFAULT = 70
private fun hudKey(context: Context) = if (mangoappSession(context)) "hudDeck" else "hud"
private fun mangoappSession(context: Context) =
@@ -953,6 +991,12 @@ object SessionPrefs {
}.apply()
}
fun deckyZipWarningSeen(context: Context): Boolean = prefs(context).getBoolean(DECKY_ZIP_WARNING_SEEN, false)
fun setDeckyZipWarningSeen(context: Context) {
prefs(context).edit().putBoolean(DECKY_ZIP_WARNING_SEEN, true).apply()
}
fun steamDownloadsInBackground(context: Context): Boolean {
val prefs = prefs(context)
return prefs.getBoolean(STEAM_DOWNLOADS_IN_BACKGROUND, false) ||
@@ -71,6 +71,7 @@ class SessionService : Service() {
private val steamDownloadMonitor = SteamDownloadMonitor()
private var downloadMonitorTask: Runnable? = null
private var downloadActive = false
@Volatile private var steamLibraryMounts = emptyMap<String, File>()
private var suspendDownloadNow = false
private var suspendPolicy = SessionPrefs.SUSPEND_MANUAL
private var steamDownloadsInBackground = false
@@ -394,6 +395,12 @@ class SessionService : Service() {
val fastPathAt = guest.size
val pulse = startAudio(guest, sessionDir)
if (steamHere) {
val encoder = VideoEncodeBridge(File(filesDir, "venc/venc.sock"))
encoder.attach(this)
components.add(encoder)
guest.add("BL_VENC_SOCKET=" + encoder.socket.absolutePath)
}
guest.add("BL_WIDTH=" + size.first)
guest.add("BL_HEIGHT=" + size.second)
@@ -802,6 +809,7 @@ class SessionService : Service() {
File(home, "Storage").mkdirs()
binds.add(Environment.getExternalStorageDirectory().path + ":/root/Storage")
val library = GameStorage.effective(this)
steamLibraryMounts = emptyMap()
var storageDiagnosticLibrary: File? = null
if (library != null) {
val problem = GameStorage.prepare(this, library.path)
@@ -813,6 +821,7 @@ class SessionService : Service() {
val content = SecondaryLibrary.contentPath(configured)
binds.addAll(SecondaryLibrary.binds(filesDir, configured, content = content))
storageDiagnosticLibrary = content
steamLibraryMounts = SecondaryLibrary.CARD_GUESTS.associateWith { content }
val route = if (content === configured) "configured" else "verified-native"
Log.i(TAG, "game storage: ${content.path} ($route) -> /mnt/droiddeck-sd (\"${library.label}\"); prefixes and native tools private")
} catch (e: Exception) {
@@ -1271,13 +1280,13 @@ class SessionService : Service() {
private fun updateSuspendPolicy() {
if (!SessionState.running) return
if (suspendPolicy == SessionPrefs.SUSPEND_MANUAL && !hasVisibleSurface) {
manualPauseRequested = true
}
val controller = suspendController ?: return
val hidden = !hasVisibleSurface
val downloadsBlockingSuspend = steamDownloadsInBackground && SessionState.mode == MODE_STEAM &&
suspendPolicy != SessionPrefs.SUSPEND_NEVER && hidden && downloadActive && !suspendDownloadNow
if (suspendPolicy == SessionPrefs.SUSPEND_MANUAL && hidden && !downloadsBlockingSuspend) {
manualPauseRequested = true
}
val controller = suspendController ?: return
if (downloadsBlockingSuspend) acquireLocks()
val steamPause = SessionState.mode == MODE_STEAM && !downloadsBlockingSuspend && when (suspendPolicy) {
SessionPrefs.SUSPEND_AUTO, SessionPrefs.SUSPEND_NATIVE -> hidden
@@ -1712,6 +1721,7 @@ class SessionService : Service() {
LinuxRuntime.rootDir(this@SessionService),
receivedBytes = TrafficStats.getUidRxBytes(android.os.Process.myUid()),
client = SessionState.steamClientArch,
mounts = steamLibraryMounts,
)
if (wasActive != downloadActive) refreshNotification()
updateSuspendPolicy()
@@ -13,7 +13,7 @@ object SettingsReset {
internal val SESSION_KEYS = setOf(
"orientation", "launcherFullscreen", "animations", "theme", "runSteamAtStartup", "addedGamesArt",
"gameStoresEnabled", "gameStoresSpeedTier", "gameStoresParallel", "storesOpenTab", "storesShowMature",
"hud", "hudDeck", "backActionsInverted", "touch", "osc", "shape", "steamController",
"hud", "hudDeck", "hudFps", "hudBattery", "hudGraph", "hudColor", "hudOpacity", "backActionsInverted", "touch", "osc", "shape", "steamController",
"gamepadLeft", "gamepadRight", "pipAutoEnter", "unfoldedControls", "stretch16x9", "picturePosition",
"gpuDriverMode", "androidDriver", "linuxDriver", "linuxDriver.steam", "linuxDriver.desktop",
"tuSysmem", "glThread", "noGlError", "zinkLazy", "mangoapp", "gpuClockPin", "gamescopeRealtime",
@@ -18,8 +18,9 @@ internal class SteamDownloadMonitor {
private var lastReceivedBytes = -1L
private var lastReceivedAt = 0L
fun poll(runtimeRoot: File, now: Long = System.currentTimeMillis(), receivedBytes: Long = -1L, client: String? = null): Boolean {
val current = manifests(runtimeRoot).associate { it.path to read(it) }
fun poll(runtimeRoot: File, now: Long = System.currentTimeMillis(), receivedBytes: Long = -1L, client: String? = null,
mounts: Map<String, File> = emptyMap()): Boolean {
val current = manifests(runtimeRoot, mounts).associate { it.path to read(it) }
val progressed = current.any { (path, state) ->
state.incomplete && state.bytesDownloaded > (previous[path]?.bytesDownloaded ?: state.bytesDownloaded)
}
@@ -98,7 +99,7 @@ internal class SteamDownloadMonitor {
now - lastContentActivityAt <= CONTENT_ACTIVITY_GRACE_MS
}
private fun manifests(runtimeRoot: File): List<File> {
private fun manifests(runtimeRoot: File, mounts: Map<String, File>): List<File> {
val steamRoots = linkedSetOf<File>()
for (home in STEAM_HOMES) {
val primary = File(runtimeRoot, home)
@@ -106,7 +107,7 @@ internal class SteamDownloadMonitor {
val libraryFolders = File(primary, "steamapps/libraryfolders.vdf")
runCatching {
PATH.findAll(libraryFolders.readText()).forEach { match ->
steamRoots += File(runtimeRoot, match.groupValues[1].removePrefix("/"))
steamRoots += hostPath(runtimeRoot, match.groupValues[1], mounts)
}
}
}
@@ -117,6 +118,15 @@ internal class SteamDownloadMonitor {
}
}
private fun hostPath(runtimeRoot: File, guest: String, mounts: Map<String, File>): File {
val path = guest.trimEnd('/')
for ((mount, host) in mounts) {
if (path == mount) return host
if (path.startsWith("$mount/")) return File(host, path.removePrefix("$mount/"))
}
return File(runtimeRoot, path.removePrefix("/"))
}
private fun read(file: File): ManifestState {
val text = runCatching { file.readText() }.getOrDefault("")
val flags = value(text, "StateFlags")?.toLongOrNull() ?: 0L
@@ -0,0 +1,28 @@
package com.droiddeck.launcher.session
import android.util.Log
import com.droiddeck.launcher.core.SessionPart
import java.io.File
/** Steam's Remote Play V4L2 encoder in the guest talks to this MediaCodec encoder (venc.c, venc_server.cpp). */
class VideoEncodeBridge(val socket: File) : SessionPart() {
override fun start() {
socket.parentFile?.mkdirs()
val ok = runCatching { System.loadLibrary("ddvenc"); nativeStart(socket.absolutePath) }
.onFailure { Log.w(TAG, "hardware video encoding unavailable", it) }
.getOrDefault(false)
Log.i(TAG, if (ok) "Remote Play hardware encoding on at $socket" else "Remote Play hardware encoding off")
}
override fun stop() {
runCatching { nativeStop() }
socket.delete()
}
private external fun nativeStart(path: String): Boolean
private external fun nativeStop()
private companion object {
const val TAG = "VideoEncodeBridge"
}
}
@@ -40,6 +40,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalInputModeManager
import androidx.compose.ui.input.InputMode
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import android.content.Context
@@ -502,7 +508,7 @@ private fun ArtChooserDialog(
sgdb = found?.sgdb ?: SteamGridDb.Status.SERVER
}
val first = remember { FocusRequester() }
LaunchedEffect(Unit) { focusWithinFrames({ false }) { first } }
LaunchedEffect(options != null) { focusWithinFrames({ false }) { first } }
val apply: (AddedGameArt.Option) -> Unit = { option ->
scope.launch {
val saved = withContext(Dispatchers.IO) { target.set(app, slot, option) }
@@ -624,14 +630,23 @@ private fun SgdbSearchDialog(
}
}
LaunchedEffect(Unit) { search() }
AppDialog(shown, back, "sgdbSearch", wide = false, maxWidth = 460.dp) {
val firstItem = remember { FocusRequester() }
val focusManager = LocalFocusManager.current
val keyboardController = LocalSoftwareKeyboardController.current
val leaveField = { focusManager.clearFocus(); keyboardController?.hide() }
val keyboard = LocalInputModeManager.current.inputMode == InputMode.Keyboard
LaunchedEffect(picked?.id, matches?.size, images.size, busy) {
val ready = if (picked != null) images.isNotEmpty() else !matches.isNullOrEmpty()
if (keyboard && !busy && ready) focusSoon { firstItem }
}
AppDialog(shown, back, "sgdbSearch", wide = false, maxWidth = 460.dp, modifier = Modifier.pointerInput(Unit) { detectTapGestures { leaveField() } }) {
DialogTitleRow(stringResource(R.string.art_sgdb_title, slotName), onClose = { onCloseAll() }, leading = {
SmallIconButton(Icons.AutoMirrored.Filled.ArrowBack, stringResource(R.string.common_back), colors.onBackground, onClick = back)
})
androidx.compose.material3.OutlinedTextField(
query, { query = it }, singleLine = true, modifier = Modifier.fillMaxWidth(),
label = { Text(stringResource(R.string.art_sgdb_search_label)) },
keyboardActions = androidx.compose.foundation.text.KeyboardActions(onSearch = { search() }),
keyboardActions = androidx.compose.foundation.text.KeyboardActions(onSearch = { leaveField(); search() }),
keyboardOptions = androidx.compose.foundation.text.KeyboardOptions(imeAction = androidx.compose.ui.text.input.ImeAction.Search),
)
val maxHeight = (LocalConfiguration.current.screenHeightDp * 0.6f).dp
@@ -643,24 +658,24 @@ private fun SgdbSearchDialog(
val chosenGame = picked
val list = matches.orEmpty()
if (chosenGame == null) {
for (match in list) key(match.id) { PickerRow(null, match.name, null) { showImages(match) } }
list.forEachIndexed { i, match -> key(match.id) { PickerRow(null, match.name, null, focus = if (i == 0) firstItem else null) { leaveField(); showImages(match) } } }
if (matches != null && list.isEmpty() && !busy && status == SteamGridDb.Status.OK) {
Text(stringResource(R.string.art_sgdb_none), fontSize = 12.sp, color = colors.onSurfaceVariant, modifier = Modifier.padding(start = 2.dp, top = 4.dp))
}
} else {
Text(chosenGame.name, fontSize = 12.sp, color = colors.onSurfaceVariant, modifier = Modifier.padding(start = 2.dp, top = 4.dp))
FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
for (option in images) key(option.full) {
images.forEachIndexed { i, option -> key(option.full) {
ArtOption(
slot, option, selected = current?.chosen == true && option.full == chosenRef, focus = null,
slot, option, selected = current?.chosen == true && option.full == chosenRef, focus = if (i == 0) firstItem else null,
description = "${artSourceLabel(AddedGameArt.SGDB)} $slotName",
) { onPick(option) }
}
} }
}
if (images.isEmpty() && !busy && status == SteamGridDb.Status.OK) {
Text(stringResource(R.string.art_sgdb_none), fontSize = 12.sp, color = colors.onSurfaceVariant, modifier = Modifier.padding(start = 2.dp, top = 4.dp))
}
if (list.size > 1) PickerRow(null, stringResource(R.string.art_sgdb_other_games), null) { picked = null }
if (list.size > 1) PickerRow(null, stringResource(R.string.art_sgdb_other_games), null) { leaveField(); picked = null }
}
if (busy) androidx.compose.material3.LinearProgressIndicator(Modifier.fillMaxWidth().padding(vertical = 8.dp))
}
@@ -69,6 +69,7 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.input.InputMode
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalInputModeManager
@@ -558,13 +559,37 @@ private fun repoInfo(post: SteamDeckRepo.Post): String =
listOf(post.author, "♥ ${post.likes}", "⇩ ${post.downloads}", if (post.seconds > 0) stringResource(R.string.boot_movie_seconds, post.seconds) else "")
.filter { it.isNotEmpty() }.joinToString(" · ")
private const val AFTER_OPEN = 3
private const val AFTER_INSTALL = 1
private const val AFTER_USE = 2
/** Install and Use are different buttons in turn, and the button is disabled while installing; it takes focus back for the controller. */
@Composable
private fun RepoAction(installed: Boolean, inUse: Boolean, percent: Int?, busy: Boolean, modifier: Modifier, onInstall: () -> Unit, onUse: () -> Unit) {
if (inUse) SecondaryButton(stringResource(R.string.boot_movie_in_use), compact = true, modifier = modifier, onClick = {})
else if (installed) SecondaryButton(stringResource(R.string.boot_movie_repo_use), compact = true, modifier = modifier, onClick = onUse)
private fun RepoAction(
installed: Boolean, inUse: Boolean, percent: Int?, busy: Boolean, modifier: Modifier, onInstall: () -> Unit, onUse: () -> Unit,
takeFocus: Boolean = false,
) {
val requester = remember { FocusRequester() }
val focused = remember { booleanArrayOf(false) }
var pending by remember { mutableIntStateOf(if (takeFocus) AFTER_OPEN else 0) }
val inputMode = LocalInputModeManager.current
LaunchedEffect(installed, inUse, busy, percent != null, pending) {
if (pending == 0) return@LaunchedEffect
if (inputMode.inputMode != InputMode.Keyboard) { pending = 0; return@LaunchedEffect }
focusWithinFrames({ focused[0] }) { requester }
when (pending) {
AFTER_OPEN -> pending = 0
AFTER_INSTALL -> if (installed && focused[0]) pending = 0
AFTER_USE -> if (inUse && focused[0]) pending = 0
else -> Unit
}
}
val m = modifier.focusRequester(requester).onFocusChanged { focused[0] = it.hasFocus || it.isFocused }
if (inUse) SecondaryButton(stringResource(R.string.boot_movie_in_use), compact = true, modifier = m, onClick = {})
else if (installed) SecondaryButton(stringResource(R.string.boot_movie_repo_use), compact = true, modifier = m, onClick = { pending = AFTER_USE; onUse() })
else SecondaryButton(
if (percent != null) stringResource(R.string.boot_movie_converting, percent) else stringResource(R.string.boot_movie_repo_install),
enabled = !busy, compact = true, modifier = modifier, onClick = onInstall,
enabled = !busy, compact = true, modifier = m, onClick = { pending = AFTER_INSTALL; onInstall() },
)
}
@@ -576,9 +601,6 @@ private fun PreviewDialog(
) {
val shown = rememberShown(onDismiss)
val close = { shown.targetState = false }
val action = remember { FocusRequester() }
val inputMode = LocalInputModeManager.current
LaunchedEffect(Unit) { if (inputMode.inputMode == InputMode.Keyboard) focusSoon { action } }
val maxVideoHeight = (LocalConfiguration.current.screenHeightDp - 200).coerceAtLeast(120).dp
AppDialog(shown, close, "boot-movie-preview", wide = false, maxWidth = 620.dp) {
DialogTitleRow(post.title, close)
@@ -586,7 +608,7 @@ private fun PreviewDialog(
MoviePreview(post.video, Modifier.heightIn(max = maxVideoHeight).aspectRatio(16f / 9f))
}
Text(repoInfo(post), fontSize = 12.sp, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1, overflow = TextOverflow.Ellipsis)
RepoAction(installed, inUse, percent, busy, Modifier.fillMaxWidth().focusRequester(action), onInstall, onUse)
RepoAction(installed, inUse, percent, busy, Modifier.fillMaxWidth(), onInstall, onUse, takeFocus = true)
}
}
@@ -30,6 +30,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
@@ -73,6 +74,8 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalInputModeManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -381,6 +384,7 @@ fun ComponentsPage(
var stackAt by remember { mutableStateOf(Offset.Zero) }
var pageAt by remember { mutableStateOf(Offset.Zero) }
val landed = remember { mutableStateMapOf<String, Int>() }
val nightlyPicked = remember { mutableStateMapOf<String, Boolean>() }
val rings = remember { mutableStateMapOf<String, Int>() }
fun land(l: String) { landed[l] = (landed[l] ?: 0) + 1; rings[l] = (rings[l] ?: 0) + 1 }
val arrivedSeen = remember { intArrayOf(Hops.arrived) }
@@ -504,7 +508,7 @@ fun ComponentsPage(
val availableTitle: @Composable (String) -> String = { l ->
when (l) {
PROTON_TAB -> stringResource(R.string.comp_available_count, protons.rows.count { it.installed == null || it.update != null })
else -> stringResource(R.string.comp_nightlies_count, availableFor(l, catalog, snapshot).size)
else -> stringResource(R.string.comp_nightlies_count, availableRows(l, catalog, snapshot).size)
}
}
val installedRows: @Composable ColumnScope.(String, Boolean) -> Unit = { l, right ->
@@ -581,12 +585,16 @@ fun ComponentsPage(
) { protonActions.onInstall(row.id) }
}
else -> {
val available = availableFor(l, catalog, snapshot)
val available = availableRows(l, catalog, snapshot)
if (available.isEmpty()) EmptyLine(if (catalogAt == 0L) stringResource(R.string.comp_refresh_to_list) else stringResource(R.string.comp_nothing_new))
for (d in available) GetLine(
d.file.removeSuffix(".wcp"), "${d.release} · " + stringResource(R.string.common_size_mb, d.size / 1048576.0),
progress = downloads[d.file], enabled = busy == null,
) { onDownload(d) }
for ((stable, nightly) in available) {
val d = if (nightly != null && nightlyPicked[stable.file] == true) nightly else stable
GetLine(
d.file.removeSuffix(".wcp"), "${d.release} · " + stringResource(R.string.common_size_mb, d.size / 1048576.0),
progress = downloads[d.file], enabled = busy == null,
channel = if (nightly != null) ({ ChannelToggle(d === nightly, enabled = busy == null) { nightlyPicked[stable.file] = d !== nightly } }) else null,
) { onDownload(d) }
}
}
}
}
@@ -922,6 +930,14 @@ private fun availableFor(l: String, catalog: List<CatalogItem>, snapshot: Snapsh
return catalog.filter { it.comp == l && ComponentsManager.safeName(it.file) !in stored }
}
// The rows to show: each stable row carries its paired nightly (if any), and a paired nightly has no row of its own.
private fun availableRows(l: String, catalog: List<CatalogItem>, snapshot: Snapshot?): List<Pair<CatalogItem, CatalogItem?>> {
val available = availableFor(l, catalog, snapshot)
val pairs = ComponentsManager.nightlyPairs(available)
val paired = pairs.values.toSet()
return available.filter { it !in paired }.map { it to pairs[it] }
}
@Composable
private fun LayerTitle(l: String): String = when (l) {
GPU_TAB -> stringResource(R.string.comp_gpu_drivers)
@@ -1417,7 +1433,8 @@ private fun ChoiceLine(
@Composable
private fun GetLine(
name: String, detail: String, progress: Int?, enabled: Boolean,
badge: String? = null, stage: String? = null, onCancel: (() -> Unit)? = null, action: String? = null, onGet: () -> Unit,
badge: String? = null, stage: String? = null, onCancel: (() -> Unit)? = null, action: String? = null,
channel: (@Composable () -> Unit)? = null, onGet: () -> Unit,
) {
val colors = MaterialTheme.colorScheme
val pal = LocalPalette.current
@@ -1432,12 +1449,43 @@ private fun GetLine(
if (progress != null) ProgressBit(progress)
else {
if (onCancel != null) FocusText(stringResource(R.string.proton_cancel_queued), pal.signal, onClick = onCancel)
channel?.invoke()
SmallButton(action ?: stringResource(R.string.comp_get), enabled = enabled, accent = true, onClick = onGet)
}
}
Box(Modifier.fillMaxWidth().height(1.dp).background(pal.line))
}
// Stable | Nightly in the same box as SmallButton: one focus stop, A (or a tap) flips it.
@Composable
private fun ChannelToggle(nightly: Boolean, enabled: Boolean, onFlip: () -> Unit) {
val colors = MaterialTheme.colorScheme
val pal = LocalPalette.current
val src = remember { MutableInteractionSource() }
val hot = rememberHot(src) && enabled
val state = stringResource(if (nightly) R.string.comp_channel_nightly else R.string.comp_channel_stable)
Row(
verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier.heightIn(min = 44.dp).clip(RoundedCornerShape(10.dp))
.background(colors.surfaceVariant)
.glideBorder(hot, RoundedCornerShape(10.dp), colors.onBackground, pal.line2, restWidth = 2.dp)
.hoverable(src).toggleable(value = nightly, interactionSource = src, indication = null, enabled = enabled, role = Role.Switch, onValueChange = { onFlip() })
.controllerConfirm(enabled = enabled, onClick = onFlip)
.semantics { stateDescription = state }
.padding(4.dp),
) {
for ((label, on) in listOf(R.string.comp_channel_stable to !nightly, R.string.comp_channel_nightly to nightly)) {
Text(
stringResource(label), fontSize = 13.sp, fontWeight = FontWeight.SemiBold, maxLines = 1,
color = if (!enabled) colors.onSurfaceVariant else if (on) (if (hot) pal.onSignal else pal.signal) else colors.onSurfaceVariant,
modifier = Modifier.clip(RoundedCornerShape(7.dp))
.background(if (on && enabled) (if (hot) pal.signal else pal.signal.copy(alpha = 0.16f)) else Color.Transparent)
.padding(horizontal = 10.dp, vertical = 6.dp),
)
}
}
}
@Composable
private fun DetailLine(detail: String, badge: String?) {
val colors = MaterialTheme.colorScheme
@@ -268,6 +268,21 @@ private fun ManageSaves(g: Library.SteamGame, prefix: java.io.File, a: FrontEndA
}
}
/** A skipped sync is not a success: "0 files" used to show for a signed-out store or cloud saves turned off. */
internal fun cloudMessage(context: android.content.Context, r: com.droiddeck.launcher.stores.CloudSaves.Result): String = when (r.result) {
"ok" -> when {
r.conflicts > 0 -> context.getString(R.string.cloud_conflict_files, r.conflicts)
r.files == 0 -> context.getString(R.string.cloud_up_to_date)
else -> context.getString(R.string.cloud_done, r.files)
}
"skipped" -> context.getString(when (r.reason) {
"not-signed-in" -> R.string.cloud_signed_out
"no-cloud-saves" -> R.string.cloud_none
else -> R.string.cloud_not_synced
})
else -> context.getString(R.string.cloud_not_synced)
}
@Composable
private fun CloudRows(g: Library.SteamGame, open: Boolean, first: androidx.compose.ui.focus.FocusRequester) {
val store = com.droiddeck.launcher.stores.Store.byId(g.source)?.takeIf { it != com.droiddeck.launcher.stores.Store.AMAZON } ?: return
@@ -290,7 +305,7 @@ private fun CloudRows(g: Library.SteamGame, open: Boolean, first: androidx.compo
busy = if (up) "up" else "down"
Thread({
val r = if (up) com.droiddeck.launcher.stores.CloudSaves.upload(context, store, id, force) else com.droiddeck.launcher.stores.CloudSaves.download(context, store, id, force)
com.droiddeck.launcher.stores.StoresState.post { busy = null; tick++; android.widget.Toast.makeText(context, if (r.ok) context.getString(R.string.cloud_done, r.files) else r.reason, android.widget.Toast.LENGTH_SHORT).show() }
com.droiddeck.launcher.stores.StoresState.post { busy = null; tick++; android.widget.Toast.makeText(context, cloudMessage(context, r), android.widget.Toast.LENGTH_SHORT).show() }
}, "cloud-manual").start()
}
MenuItem(stringResource(R.string.store_cloud_saves), checked = enabled && supported, enabled = supported, focusRequester = first,
@@ -302,7 +317,7 @@ private fun CloudRows(g: Library.SteamGame, open: Boolean, first: androidx.compo
com.droiddeck.launcher.stores.StoresState.post { enabled = written?.cloud ?: enabled }
}, "cloud-switch").start()
}
val ready = st != null && supported && busy == null
val ready = st != null && supported && enabled && busy == null
val pending = stringResource(R.string.cloud_pending)
val summary = when {
st == null || busy != null -> pending
@@ -79,6 +79,33 @@ internal object GlassesTab {
const val VR = "vr"
const val HARDWARE = "hardware"
const val TRACKING = "tracking"
const val CONTROLLERS = "controllers"
}
@Composable
internal fun VrControllerGroups(host: MenuHost, track: (String) -> Modifier = { Modifier }) {
val context = androidx.compose.ui.platform.LocalContext.current
androidx.compose.runtime.LaunchedEffect(Unit) { com.droiddeck.launcher.input.VrControllers.load(context) }
val c by com.droiddeck.launcher.input.VrControllers.settings.collectAsState()
val emulate = com.droiddeck.launcher.input.VrControllers.Emulate.entries
SettingsGroup(stringResource(R.string.vr_controllers_group)) {
ChoiceRow(host, "vr-emulate", stringResource(R.string.vr_controllers_emulate), stringResource(R.string.vr_controllers_emulate_hint),
emulate.map { it to stringResource(when (it) {
com.droiddeck.launcher.input.VrControllers.Emulate.OFF -> R.string.vr_controllers_off
com.droiddeck.launcher.input.VrControllers.Emulate.INDEX -> R.string.vr_controllers_index
com.droiddeck.launcher.input.VrControllers.Emulate.TOUCH -> R.string.vr_controllers_touch
com.droiddeck.launcher.input.VrControllers.Emulate.VIVE -> R.string.vr_controllers_vive
}) }, c.emulate, chipModifier = track("vr-emulate")) { com.droiddeck.launcher.input.VrControllers.setEmulate(context, it) }
if (c.emulate != com.droiddeck.launcher.input.VrControllers.Emulate.OFF) ChoiceRow(host, "vr-sticks",
stringResource(R.string.vr_controllers_sticks), stringResource(R.string.vr_controllers_sticks_hint),
listOf(false to stringResource(R.string.vr_controllers_sticks_game), true to stringResource(R.string.vr_controllers_sticks_hands)),
c.sticksMoveHands, chipModifier = track("vr-sticks")) { com.droiddeck.launcher.input.VrControllers.setSticksMoveHands(context, it) }
SettingsRow(stringResource(R.string.vr_controllers_buttons), stringResource(when (c.emulate) {
com.droiddeck.launcher.input.VrControllers.Emulate.OFF -> R.string.vr_controllers_buttons_off
com.droiddeck.launcher.input.VrControllers.Emulate.VIVE -> R.string.vr_controllers_buttons_vive
else -> R.string.vr_controllers_buttons_stick
}), hintLines = 6) {}
}
}
@Composable
@@ -362,13 +389,3 @@ private fun GlassesRecenterAction(label: String, tag: String, tint: Int, opacity
}
}
@Composable
internal fun GlassesPlayingHint(model: String) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Icon(GlassesIcon, null, tint = Color.White.copy(alpha = 0.35f), modifier = Modifier.size(56.dp))
Spacer(Modifier.height(10.dp))
Text(stringResource(R.string.glasses_playing, model), color = Color.White.copy(alpha = 0.45f), fontSize = 15.sp)
}
}
}
@@ -0,0 +1,85 @@
package com.droiddeck.launcher.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.droiddeck.launcher.R
/** Actions for the phone while the picture is on the glasses. Null hides the button. */
internal class GlassesPhoneActions(
val onRecenter: (() -> Unit)?,
val onRecenterJoyCons: (() -> Unit)?,
val onSteamVrMenu: (() -> Unit)?,
val onSwitchSticks: (() -> Unit)?,
val controllers: String?,
val onNextControllers: (() -> Unit)?,
val onKeyboard: () -> Unit,
val onSessionMenu: () -> Unit,
val onStopSteamVr: (() -> Unit)?,
val brightness: Int,
val brightnessMax: Int,
val onBrightness: ((Int) -> Unit)?,
)
@OptIn(ExperimentalLayoutApi::class)
@Composable
internal fun GlassesPhonePanel(model: String, status: String?, a: GlassesPhoneActions) {
Box(Modifier.fillMaxSize().windowInsetsPadding(WindowInsets.displayCutout).padding(16.dp), contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.widthIn(max = 640.dp)) {
Icon(GlassesIcon, null, tint = Color.White.copy(alpha = 0.35f), modifier = Modifier.size(40.dp))
Spacer(Modifier.height(6.dp))
Text(stringResource(R.string.glasses_playing, model), color = Color.White.copy(alpha = 0.6f), fontSize = 15.sp)
if (status != null) Text(status, color = Color.White.copy(alpha = 0.4f), fontSize = 13.sp, textAlign = TextAlign.Center)
Spacer(Modifier.height(16.dp))
FlowRow(horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally),
verticalArrangement = Arrangement.spacedBy(10.dp)) {
a.onRecenter?.let { PanelButton(stringResource(R.string.glasses_phone_recenter), "phone-recenter", it) }
a.onRecenterJoyCons?.let { PanelButton(stringResource(R.string.glasses_recenter_joycons_button), "phone-recenter-joycons", it) }
a.onSteamVrMenu?.let { PanelButton(stringResource(R.string.glasses_phone_steamvr_menu), "phone-steamvr-menu", it) }
a.onNextControllers?.let { next -> a.controllers?.let {
PanelButton(stringResource(R.string.glasses_phone_controllers, it), "phone-controllers", next) } }
a.onSwitchSticks?.let { PanelButton(stringResource(R.string.glasses_phone_switch_sticks), "phone-switch-sticks", it) }
PanelButton(stringResource(R.string.glasses_phone_keyboard), "phone-keyboard", a.onKeyboard)
PanelButton(stringResource(R.string.glasses_phone_session_menu), "phone-session-menu", a.onSessionMenu)
a.onStopSteamVr?.let { PanelButton(stringResource(R.string.glasses_phone_stop_steamvr), "phone-stop-steamvr", it) }
}
val setBrightness = a.onBrightness
if (setBrightness != null && a.brightnessMax > 0) {
Spacer(Modifier.height(14.dp))
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp)) {
PanelButton("−", "phone-brightness-down") { setBrightness((a.brightness - 1).coerceAtLeast(0)) }
Text(stringResource(R.string.glasses_phone_brightness, a.brightness.coerceAtLeast(0), a.brightnessMax),
color = Color.White.copy(alpha = 0.6f), fontSize = 14.sp)
PanelButton("+", "phone-brightness-up") { setBrightness((a.brightness + 1).coerceAtMost(a.brightnessMax)) }
}
}
}
}
}
@Composable
private fun PanelButton(label: String, tag: String, onClick: () -> Unit) =
SecondaryButton(label, compact = true, modifier = Modifier.testTag(tag), onClick = onClick)
@@ -3,6 +3,9 @@ package com.droiddeck.launcher.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
@@ -105,7 +108,7 @@ private fun LogoPreview(hero: File?, logo: File?, value: LogoPosition.Value) {
}
@Composable
private fun PinChip(label: String, selected: Boolean, onClick: () -> Unit) {
private fun PinChip(label: String, selected: Boolean, focus: FocusRequester?, onClick: () -> Unit) {
val pal = LocalPalette.current
val colors = MaterialTheme.colorScheme
val src = remember { MutableInteractionSource() }
@@ -113,7 +116,7 @@ private fun PinChip(label: String, selected: Boolean, onClick: () -> Unit) {
val shape = RoundedCornerShape(8.dp)
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.clip(shape)
modifier = Modifier.then(if (focus != null) Modifier.focusRequester(focus) else Modifier).clip(shape)
.background(if (selected) pal.signal.copy(alpha = 0.14f) else Color.White.copy(alpha = 0.03f))
.border(if (selected) 2.dp else 1.dp, if (selected) pal.signal else pal.line, shape)
.glideBorder(hot, shape, pal.signal)
@@ -140,6 +143,9 @@ internal fun LogoPositionDialog(
val shown = rememberShown(onBack)
val back = { shown.targetState = false }
var value by remember { mutableStateOf(start ?: LogoPosition.DEFAULT) }
val startPin = remember { value.pin }
val first = remember { FocusRequester() }
LaunchedEffect(Unit) { focusSoon { first } }
var failed by remember { mutableStateOf(false) }
var busy by remember { mutableStateOf(false) }
val save: (LogoPosition.Value?) -> Unit = { next ->
@@ -172,7 +178,7 @@ internal fun LogoPositionDialog(
)
Text(stringResource(R.string.logo_pos_position), fontSize = 12.sp, color = colors.onSurfaceVariant, modifier = Modifier.padding(start = 2.dp, top = 2.dp))
FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
for (pin in LogoPosition.Pin.values()) PinChip(pin.label(), pin == value.pin) { value = value.copy(pin = pin) }
for (pin in LogoPosition.Pin.values()) PinChip(pin.label(), pin == value.pin, if (pin == startPin) first else null) { value = value.copy(pin = pin) }
}
ValueSlider(
value.widthPct, LogoPosition.MIN_PCT..LogoPosition.MAX_PCT, step = 1, enabled = true, label = stringResource(R.string.logo_pos_size),
@@ -14,6 +14,7 @@ import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@@ -98,6 +99,7 @@ class ModeSettings(
val wifiDiscoveryBlocked: Boolean = false,
val deckyInstalled: String? = null,
val deckyLatestRelease: DeckyManager.Release? = null,
val deckyBranch: Int = DeckyManager.BRANCH_STABLE,
val deckyChecking: Boolean = false,
val deckyStage: String? = null,
val deckyPercent: Int = -1,
@@ -144,6 +146,7 @@ class ModeSettingsActions(
val onWifiDiscoverySettings: () -> Unit = {},
val onDeckyInstall: (DeckyManager.Release) -> Unit = {},
val onDeckyCheck: () -> Unit = {},
val onDeckyBranch: (Int) -> Unit = {},
val onDeckyEnabled: (Boolean) -> Unit = {},
val onDeckyUninstall: () -> Unit = {},
val onPickDeckyPluginZip: () -> Unit = {},
@@ -423,6 +426,19 @@ fun ModeSheetRows(s: ModeSettings, a: ModeSettingsActions, tab: String, extras:
if (s.deckyInstalled != null) DeckyUninstall(enabled = s.deckyStage == null && !s.deckySessionRunning, onUninstall = a.onDeckyUninstall)
}
}
ChoiceRow(
host, "decky-channel", stringResource(R.string.decky_channel),
stringResource(R.string.decky_channel_hint),
listOf(
DeckyManager.BRANCH_STABLE to stringResource(R.string.decky_channel_stable),
DeckyManager.BRANCH_PRERELEASE to stringResource(R.string.decky_channel_prerelease),
) + if (s.deckyBranch == DeckyManager.BRANCH_TESTING) listOf(
DeckyManager.BRANCH_TESTING to stringResource(R.string.decky_channel_testing),
) else emptyList(),
s.deckyBranch,
enabled = s.deckyStage == null && !s.deckySessionRunning,
onPick = a.onDeckyBranch,
)
if (s.deckyInstalled != null) ToggleRow(
host, "decky-enabled", stringResource(R.string.mode_decky),
if (s.deckyEnabled) stringResource(R.string.mode_decky_on)
@@ -529,6 +545,35 @@ internal fun ProtonOptions(
GameEnvironmentRow()
}
@Composable
internal fun DeckyZipWarningDialog(onConfirm: () -> Unit, onCancel: () -> Unit) {
val context = androidx.compose.ui.platform.LocalContext.current
var left by remember { mutableIntStateOf(if (SessionPrefs.deckyZipWarningSeen(context)) 0 else DECKY_ZIP_WARNING_SECONDS) }
androidx.compose.runtime.LaunchedEffect(Unit) {
while (left > 0) {
kotlinx.coroutines.delay(1000L)
left--
}
SessionPrefs.setDeckyZipWarningSeen(context)
}
AlertDialog(
onDismissRequest = onCancel,
title = { Text(stringResource(R.string.decky_zip_warning_title)) },
text = { Text(stringResource(R.string.decky_zip_warning_text)) },
confirmButton = {
androidx.compose.material3.TextButton(onClick = onConfirm, enabled = left == 0) {
Text(
if (left > 0) androidx.compose.ui.res.pluralStringResource(R.plurals.decky_zip_warning_wait, left, left)
else stringResource(R.string.decky_zip_warning_continue),
)
}
},
dismissButton = { androidx.compose.material3.TextButton(onClick = onCancel) { Text(stringResource(R.string.common_cancel)) } },
)
}
private const val DECKY_ZIP_WARNING_SECONDS = 5
@Composable
private fun DeckyUninstall(enabled: Boolean, onUninstall: () -> Unit) {
val colors = MaterialTheme.colorScheme
@@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.heightIn
import androidx.compose.material.icons.filled.Pause
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.Icon
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -68,6 +69,8 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.font.FontWeight
@@ -78,21 +81,93 @@ import androidx.compose.ui.text.style.TextOverflow
@Composable
fun HudText(text: String) {
fun HudText(text: String, graph: FloatArray = FloatArray(0), color: String = "mint", opacity: Int = 70) {
if (text.isEmpty() && graph.size < 2) return
val accent = hudInk(color)
val wash = (opacity.coerceIn(30, 100) / 100f)
val ink = accent.copy(alpha = (0.5f + wash * 0.5f).coerceIn(0.62f, 1f))
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.TopEnd) {
Text(
text,
fontFamily = FontFamily.Monospace,
fontSize = 12.sp,
color = Color.White,
Column(
horizontalAlignment = Alignment.End,
modifier = Modifier
.padding(12.dp)
.background(Color(0x8C000000))
.padding(horizontal = 8.dp, vertical = 3.dp),
)
.background(
Brush.verticalGradient(
listOf(accent.copy(alpha = wash * 0.28f), Color.Black.copy(alpha = wash * 0.72f)),
),
RoundedCornerShape(8.dp),
)
.padding(horizontal = 8.dp, vertical = 5.dp),
) {
if (text.isNotEmpty()) Text(
text,
fontFamily = FontFamily.Monospace,
fontSize = 12.sp,
color = ink,
textAlign = TextAlign.End,
)
if (graph.size >= 2) {
if (text.isNotEmpty()) Spacer(Modifier.height(4.dp))
HudGraph(graph, accent, wash)
}
}
}
}
@Composable
private fun HudGraph(samples: FloatArray, accent: Color, wash: Float) {
Canvas(Modifier.width(148.dp).height(44.dp)) {
val maxMs = (samples.maxOrNull() ?: 16.7f).coerceAtLeast(16.7f)
val step = size.width / (samples.size - 1)
fun yOf(ms: Float) = size.height * (1f - (ms / maxMs).coerceIn(0f, 1f))
val fillAlpha = wash * 0.5f
val fill = Path().apply {
moveTo(0f, size.height)
samples.forEachIndexed { i, ms -> lineTo(i * step, yOf(ms)) }
lineTo(size.width, size.height)
close()
}
drawPath(
fill,
Brush.verticalGradient(listOf(HUD_SLOW.copy(alpha = fillAlpha), accent.copy(alpha = fillAlpha * 0.45f))),
)
val guide = yOf(16.7f)
drawLine(Color.White.copy(alpha = 0.32f), Offset(0f, guide), Offset(size.width, guide), strokeWidth = 1f)
for (i in 0 until samples.lastIndex) {
val tone = ((samples[i] - 8f) / 25f).coerceIn(0f, 1f)
drawLine(
mix(accent, HUD_SLOW, tone).copy(alpha = 0.55f + wash * 0.4f),
Offset(i * step, yOf(samples[i])),
Offset((i + 1) * step, yOf(samples[i + 1])),
strokeWidth = 2.5f,
cap = StrokeCap.Round,
)
}
}
}
private fun hudInk(color: String): Color = Color(
when (color) {
"white" -> 0xFFF2F5F8
"sky" -> 0xFF66C0F4
"amber" -> 0xFFFFB74D
"violet" -> 0xFFD0A2FF
else -> 0xFF3DDC84
}.toInt(),
)
private fun mix(from: Color, to: Color, t: Float): Color {
val u = t.coerceIn(0f, 1f)
return Color(
red = from.red + (to.red - from.red) * u,
green = from.green + (to.green - from.green) * u,
blue = from.blue + (to.blue - from.blue) * u,
alpha = 1f,
)
}
private val HUD_SLOW = Color(0xFFFF5C6C.toInt())
private class LoadStage(@androidx.annotation.StringRes val label: Int, @androidx.annotation.StringRes val detail: Int)
private fun loadStages(steam: Boolean): List<LoadStage> = if (steam) listOf(
@@ -110,6 +110,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
@@ -195,6 +196,11 @@ class DrawerActions(
val isHomeApp: Boolean,
val androidApps: List<HomeApp.LaunchableApp>,
val hudOn: Boolean,
val hudFps: Boolean = true,
val hudBattery: Boolean = true,
val hudGraph: Boolean = true,
val hudColor: String = SessionPrefs.HUD_COLOR_MINT,
val hudOpacity: Int = SessionPrefs.HUD_OPACITY_DEFAULT,
val frameGen: FrameGen.Mode,
val lossless: Lossless.State,
val oscMode: String,
@@ -222,6 +228,11 @@ class DrawerActions(
val secondScreenDisplays: List<SecondScreenDisplay>,
val selectedSecondScreenDisplay: Int,
val onHud: (Boolean) -> Unit,
val onHudFps: (Boolean) -> Unit = {},
val onHudBattery: (Boolean) -> Unit = {},
val onHudGraph: (Boolean) -> Unit = {},
val onHudColor: (String) -> Unit = {},
val onHudOpacity: (Int) -> Unit = {},
val onFrameGenPick: (FrameGen.Mode) -> Unit,
val onImportLossless: () -> Unit,
val onKeyboard: () -> Unit,
@@ -308,7 +319,7 @@ internal fun SessionDrawer(open: Boolean, requestedPage: SessionDrawerPage, cont
val pal = LocalPalette.current
val host = rememberMenuHost()
val (glasses, glassesSettings) = rememberGlasses()
val glassesPages = glassesTabs(glasses)
val glassesPages = glassesTabs(glasses) + (GlassesTab.CONTROLLERS to stringResource(R.string.vr_controllers_tab))
var selectedGlassesTab by rememberSaveable { mutableStateOf(GlassesTab.DISPLAY) }
val glassesTab = selectedGlassesTab.takeIf { key -> glassesPages.any { it.first == key } } ?: GlassesTab.DISPLAY
var androidAppsExpanded by rememberSaveable { mutableStateOf(false) }
@@ -462,6 +473,30 @@ internal fun SessionDrawer(open: Boolean, requestedPage: SessionDrawerPage, cont
SettingsGroup(stringResource(R.string.drawer_page_display)) {
ToggleRow(host, "hud", stringResource(R.string.drawer_hud), null, a.hudOn,
chipModifier = focus.track(page, "hud"), onChange = a.onHud)
if (a.hudOn) {
ToggleRow(host, "hud-fps", stringResource(R.string.drawer_hud_fps), null, a.hudFps,
chipModifier = focus.track(page, "hud-fps"), onChange = a.onHudFps)
ToggleRow(host, "hud-battery", stringResource(R.string.drawer_hud_battery), null, a.hudBattery,
chipModifier = focus.track(page, "hud-battery"), onChange = a.onHudBattery)
ToggleRow(host, "hud-graph", stringResource(R.string.drawer_hud_graph), null, a.hudGraph,
chipModifier = focus.track(page, "hud-graph"), onChange = a.onHudGraph)
ChoiceRow(
host, "hud-color", stringResource(R.string.drawer_hud_color), null,
listOf(
SessionPrefs.HUD_COLOR_MINT to stringResource(R.string.drawer_hud_color_mint),
"white" to stringResource(R.string.drawer_hud_color_white),
"sky" to stringResource(R.string.drawer_hud_color_sky),
"amber" to stringResource(R.string.drawer_hud_color_amber),
"violet" to stringResource(R.string.drawer_hud_color_violet),
),
a.hudColor, chipModifier = focus.track(page, "hud-color"), onPick = a.onHudColor,
)
SliderRow(
stringResource(R.string.drawer_hud_opacity), null, a.hudOpacity,
SessionPrefs.HUD_OPACITY_RANGE, step = 10, format = { "$it%" },
modifier = focus.track(page, "hud-opacity"), onChange = a.onHudOpacity,
)
}
val fgOpen = host.open == "fg"
val fgLabel = FrameGen.label(LocalContext.current, a.frameGen)
SettingsRow(stringResource(R.string.frame_gen_title), null, highlighted = fgOpen) {
@@ -557,7 +592,9 @@ internal fun SessionDrawer(open: Boolean, requestedPage: SessionDrawerPage, cont
SessionDrawerPage.SECOND_SCREEN -> {
SecondScreenGroup(host, a) { key -> focus.track(page, key) }
}
SessionDrawerPage.GLASSES -> {
SessionDrawerPage.GLASSES -> if (glassesTab == GlassesTab.CONTROLLERS) {
VrControllerGroups(host) { key -> focus.track(page, key) }
} else {
GlassesGroups(host, glasses, glassesSettings, { key -> focus.track(page, key) }, onRecenter = a.onGlassesRecenter,
tab = glassesTab, outputActive = a.glassesOutput, steamVrRunning = a.steamVr == SteamVr.Status.RUNNING,
steamVr = { SteamVrRow(a) })
@@ -1379,6 +1416,7 @@ internal fun ComponentDownloadsDrawerGroup(
) {
val colors = MaterialTheme.colorScheme
val installed = packages.map { it.file }.toSet()
val nightlyPicked = remember { mutableStateMapOf<String, Boolean>() }
SettingsGroup(stringResource(R.string.drawer_component_downloads)) {
Text(stringResource(R.string.drawer_component_downloads_hint), fontSize = 12.sp,
color = colors.onSurfaceVariant, modifier = Modifier.padding(horizontal = 14.dp, vertical = 8.dp))
@@ -1402,21 +1440,40 @@ internal fun ComponentDownloadsDrawerGroup(
}
AnchoredMenu(open, onDismiss = { if (host.open == key) host.open = null },
title = ComponentsManager.LABEL.getValue(comp)) { firstItemFocus ->
val firstAvailable = items.firstOrNull { ComponentsManager.safeName(it.file) !in installed && it.file !in downloads }
items.forEach { item ->
// A nightly paired with a stable build rides on that row; Stable/Nightly tabs beside the row pick which one.
val pairs = ComponentsManager.nightlyPairs(items)
val rows = items.filter { it !in pairs.values }
fun shown(row: ComponentsManager.CatalogItem) = pairs[row]?.takeIf { nightlyPicked[row.file] == true } ?: row
val firstAvailable = rows.firstOrNull { shown(it).let { s -> ComponentsManager.safeName(s.file) !in installed && s.file !in downloads } }
rows.forEach { row ->
val item = shown(row)
val nightly = pairs[row]
val stored = ComponentsManager.safeName(item.file) in installed
val progress = downloads[item.file]
MenuItem(item.file.removeSuffix(".wcp"), checked = stored,
enabled = !stored && progress == null,
detail = when {
stored -> stringResource(R.string.wincomp_downloaded)
progress != null -> if (progress < 0) stringResource(R.string.wincomp_downloading, item.file.removeSuffix(".wcp")) else "$progress%"
else -> item.release + " · " + stringResource(R.string.common_size_mb, item.size / 1048576.0)
},
focusRequester = if (item == firstAvailable) firstItemFocus else null,
) {
onDownload(item)
host.open = null
val choose = @Composable { rowModifier: Modifier ->
MenuItem(item.file.removeSuffix(".wcp"), checked = stored,
enabled = !stored && progress == null,
detail = when {
stored -> stringResource(R.string.wincomp_downloaded)
progress != null -> if (progress < 0) stringResource(R.string.wincomp_downloading, item.file.removeSuffix(".wcp")) else "$progress%"
else -> item.release + " · " + stringResource(R.string.common_size_mb, item.size / 1048576.0)
},
focusRequester = if (row == firstAvailable) firstItemFocus else null,
modifier = rowModifier,
) {
onDownload(item)
host.open = null
}
}
if (nightly == null) choose(Modifier)
else Row(verticalAlignment = Alignment.CenterVertically) {
choose(Modifier.weight(1f))
TabStrip(
listOf(stringResource(R.string.comp_channel_stable), stringResource(R.string.comp_channel_nightly)),
selected = if (item === nightly) 1 else 0,
onSelect = { nightlyPicked[row.file] = it == 1 },
bumpers = false, compact = true, modifier = Modifier.padding(start = 6.dp, end = 4.dp),
)
}
}
}
@@ -157,6 +157,7 @@ internal fun Modifier.bumpers(onPrevious: () -> Unit, onNext: () -> Unit): Modif
internal fun TabStrip(
tabs: List<String>, selected: Int, onSelect: (Int) -> Unit,
modifier: Modifier = Modifier, focusRequesters: List<FocusRequester>? = null,
bumpers: Boolean = true, compact: Boolean = false,
) {
val colors = MaterialTheme.colorScheme
val pal = LocalPalette.current
@@ -164,9 +165,9 @@ internal fun TabStrip(
val scroll = rememberScrollState()
var tight by remember(tabs) { mutableStateOf(false) }
LaunchedEffect(scroll.maxValue) { if (scroll.maxValue in 1 until Int.MAX_VALUE) tight = true }
val tabPadding = if (tight) 10.dp else 16.dp
val tabPadding = if (compact) 10.dp else if (tight) 10.dp else 16.dp
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp), modifier = modifier) {
BumperKey("LB", stringResource(R.string.widgets_prev_tab)) { onSelect((selected + tabs.size - 1) % tabs.size) }
if (bumpers) BumperKey("LB", stringResource(R.string.widgets_prev_tab)) { onSelect((selected + tabs.size - 1) % tabs.size) }
Row(
modifier = Modifier.weight(1f, fill = false).clip(shape).background(colors.surfaceVariant).border(1.dp, pal.line2, shape)
.horizontalScroll(scroll).padding(3.dp),
@@ -180,7 +181,7 @@ internal fun TabStrip(
val reveal = remember { androidx.compose.foundation.relocation.BringIntoViewRequester() }
if (on) LaunchedEffect(Unit) { reveal.bringIntoView() }
Text(
label, fontSize = 14.sp, fontWeight = if (on) FontWeight.Bold else FontWeight.SemiBold, maxLines = 1,
label, fontSize = if (compact) 12.sp else 14.sp, fontWeight = if (on) FontWeight.Bold else FontWeight.SemiBold, maxLines = 1,
color = if (on) pal.onSignal else if (hot) colors.onBackground else colors.onSurfaceVariant,
modifier = Modifier
.bringIntoViewRequester(reveal)
@@ -191,11 +192,11 @@ internal fun TabStrip(
.glideBorder(hot, tabShape, if (on) colors.onBackground else pal.signal)
.hoverable(src).clickable(interactionSource = src, indication = null, role = Role.Tab, onClick = pick)
.controllerConfirm(onClick = pick)
.padding(horizontal = tabPadding, vertical = 12.dp),
.padding(horizontal = tabPadding, vertical = if (compact) 6.dp else 12.dp),
)
}
}
BumperKey("RB", stringResource(R.string.widgets_next_tab)) { onSelect((selected + 1) % tabs.size) }
if (bumpers) BumperKey("RB", stringResource(R.string.widgets_next_tab)) { onSelect((selected + 1) % tabs.size) }
}
}
@@ -115,13 +115,14 @@ internal fun SteamHome(s: FrontEndState, a: FrontEndActions, modifier: Modifier)
drop = drop.takeIf { headset },
overlay = { lifted ->
if (headset) DropSheet(
drop, glassesTabs(glasses), covered = lifted,
drop, glassesTabs(glasses) + (GlassesTab.CONTROLLERS to stringResource(R.string.vr_controllers_tab)), covered = lifted,
button = { enabled ->
PrimaryButton(stringResource(R.string.games_play_steamvr), enabled = !s.busy && glasses.usable, large = true, icon = Icons.Filled.PlayArrow, fill = true,
modifier = Modifier.fillMaxWidth().testTag("play-steamvr")) { if (enabled) { drop.open = false; a.onPlaySteamVr() } }
},
) { tab ->
GlassesGroups(rememberMenuHost(), glasses, glassesSettings,
if (tab == GlassesTab.CONTROLLERS) VrControllerGroups(rememberMenuHost())
else GlassesGroups(rememberMenuHost(), glasses, glassesSettings,
onRecenter = GlassesMenuMirror::recenter, inSession = false, tab = tab)
}
},
@@ -65,7 +65,7 @@ internal fun InstallWhereDialog(item: CatalogItem, onDismiss: () -> Unit) {
)
Text(
stringResource(R.string.common_cancel), fontSize = 13.sp, fontWeight = FontWeight.SemiBold, color = colors.onSurfaceVariant,
modifier = Modifier.clip(Shape12).clickable(role = Role.Button, onClick = close).padding(horizontal = 10.dp, vertical = 6.dp),
modifier = Modifier.clip(Shape12).clickable(role = Role.Button, onClick = close).controllerConfirm(onClick = close).padding(horizontal = 10.dp, vertical = 6.dp),
)
}
}
@@ -201,12 +201,12 @@ internal fun StoresPage(s: FrontEndState, a: FrontEndActions, modifier: Modifier
val colors = MaterialTheme.colorScheme
val narrow = LocalNarrowPane.current
val padH = if (narrow) 14.dp else 22.dp
var chip by rememberSaveable { mutableStateOf(Store.GOG.id) }
val tabs = remember {
androidx.compose.runtime.mutableStateListOf<StoreTab>().apply {
addAll(arrangeStoreTabs(SessionPrefs.storesTabOrder(ctx), SessionPrefs.storesTabHidden(ctx)))
}
}
var chip by rememberSaveable { mutableStateOf(tabs.firstOrNull { it.shown }?.store?.id ?: Store.GOG.id) }
var arranging by remember { mutableStateOf(false) }
val shownStores = tabs.filter { it.shown }.map { it.store }
fun commitTabs() {
@@ -638,8 +638,9 @@ private fun StoreDot(store: Store, signedIn: Boolean) {
Box(
Modifier.size(12.dp)
.onGloballyPositioned { StoresMotion.dots[store] = it.boundsInRoot() }
.pulseRing(StoresMotion.pulses[store] ?: 0, c.dot),
) { Box(Modifier.matchParentSize().clip(CircleShape).background(c.dot).alpha(if (signedIn) 1f else 0.35f)) }
.pulseRing(StoresMotion.pulses[store] ?: 0, c.dot)
.background(c.dot.copy(alpha = if (signedIn) 1f else 0.35f), CircleShape),
)
}
@Composable
@@ -69,7 +69,7 @@ fun TouchGestureDialog(game: String?, onDismiss: () -> Unit, onSaved: () -> Unit
val actions = mouse + ACTION_SHOW_KEYBOARD + GestureKeys.codes.keys.map { "key_$it" } + ACTION_KEY_TILDE
val p = LocalPalette.current
GestureDialogFrame(stringResource(R.string.gesture_settings), stringResource(R.string.gesture_editor_subtitle), onDismiss,
GestureDialogFrame(onDismiss,
footer = {
Row(Modifier.fillMaxWidth().padding(horizontal = 20.dp, vertical = 12.dp), horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically) {
TextButton(onClick = onDismiss) { Text(stringResource(R.string.gesture_cancel)) }
@@ -83,15 +83,6 @@ fun TouchGestureDialog(game: String?, onDismiss: () -> Unit, onSaved: () -> Unit
}, modifier = Modifier.testTag("gesture-save")) { Text(stringResource(R.string.gesture_save_changes)) }
}
}) {
Column(Modifier.padding(horizontal = 20.dp)) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
GestureFilterChip(!forGame, onClick = { forGame = false }, label = { Text(stringResource(R.string.gesture_defaults)) }, modifier = Modifier.testTag("gesture-scope-default"))
if (targetGame != null) GestureFilterChip(forGame, onClick = { forGame = true }, label = { Text(stringResource(R.string.gesture_game)) }, modifier = Modifier.testTag("gesture-scope-game"))
if (forGame && gameDraft != null) TextButton(onClick = { gameDraft = null }, modifier = Modifier.testTag("gesture-inherit")) { Text(stringResource(R.string.gesture_use_defaults)) }
}
Text(stringResource(if (!forGame) R.string.gesture_scope_default else if (gameDraft == null) R.string.gesture_inheriting else R.string.gesture_scope_game),
color = p.onSurfaceVariant, style = MaterialTheme.typography.bodySmall, modifier = Modifier.padding(bottom = 12.dp))
}
ScrollableTabRow(tab, edgePadding = 12.dp, containerColor = p.surface, divider = { HorizontalDivider(color = p.line) }) {
tabs.forEachIndexed { index, title ->
Tab(tab == index, onClick = { tab = index }, text = { Text(stringResource(title)) }, selectedContentColor = p.onBackground,
@@ -100,9 +91,16 @@ fun TouchGestureDialog(game: String?, onDismiss: () -> Unit, onSaved: () -> Unit
}
key(tab) {
Column(Modifier.weight(1f).fillMaxWidth().verticalScroll(rememberScrollState()).padding(20.dp), verticalArrangement = Arrangement.spacedBy(14.dp)) {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
GestureFilterChip(!forGame, onClick = { forGame = false }, label = { Text(stringResource(R.string.gesture_defaults)) }, modifier = Modifier.testTag("gesture-scope-default"))
if (targetGame != null) GestureFilterChip(forGame, onClick = { forGame = true }, label = { Text(stringResource(R.string.gesture_game)) }, modifier = Modifier.testTag("gesture-scope-game"))
}
if (forGame && gameDraft != null) TextButton(onClick = { gameDraft = null }, modifier = Modifier.testTag("gesture-inherit")) { Text(stringResource(R.string.gesture_use_defaults)) }
}
when (tab) {
0 -> {
GestureSection(R.string.gesture_tab_one, R.string.gesture_one_hint)
GestureSection(R.string.gesture_tab_one)
GestureCard(R.string.gesture_tap, config.tapEnabled, { change(config.copy(tapEnabled = it)) }) {
GestureActionField("tap", R.string.gesture_tap, config.tapAction, actions) { change(config.copy(tapAction = it)) }
}
@@ -118,7 +116,7 @@ fun TouchGestureDialog(game: String?, onDismiss: () -> Unit, onSaved: () -> Unit
}
}
1 -> {
GestureSection(R.string.gesture_tab_two, R.string.gesture_two_hint)
GestureSection(R.string.gesture_tab_two)
GestureCard(R.string.gesture_two_tap, config.twoFingerTapEnabled, { change(config.copy(twoFingerTapEnabled = it)) }) {
GestureActionField("two-tap", R.string.gesture_two_tap, config.twoFingerTapAction, actions) { change(config.copy(twoFingerTapAction = it)) }
}
@@ -134,7 +132,7 @@ fun TouchGestureDialog(game: String?, onDismiss: () -> Unit, onSaved: () -> Unit
}
}
2 -> {
GestureSection(R.string.gesture_tab_three, R.string.gesture_three_hint)
GestureSection(R.string.gesture_tab_three)
GestureCard(R.string.gesture_three_tap, config.threeFingerTapEnabled, { change(config.copy(threeFingerTapEnabled = it)) }) {
GestureActionField("three-tap", R.string.gesture_three_tap, config.threeFingerTapAction, actions) { change(config.copy(threeFingerTapAction = it)) }
}
@@ -147,16 +145,13 @@ fun TouchGestureDialog(game: String?, onDismiss: () -> Unit, onSaved: () -> Unit
}
}
3 -> {
GestureSection(R.string.gesture_tab_options, R.string.gesture_options_hint)
GestureSection(R.string.gesture_tab_options)
GestureSettingsCard(R.string.gesture_movement) {
Text(stringResource(R.string.gesture_movement_hint), color = p.onSurfaceVariant, style = MaterialTheme.typography.bodyMedium)
GestureChoiceChips(config.mouseDragMovementMode, listOf(MOUSE_DRAG_MOVEMENT_DIRECT to stringResource(R.string.gesture_direct), MOUSE_DRAG_MOVEMENT_RELATIVE to stringResource(R.string.gesture_relative))) { change(config.copy(mouseDragMovementMode = it)) }
Text(stringResource(R.string.gesture_middle_relative_hint), color = p.onSurfaceVariant, style = MaterialTheme.typography.bodySmall)
}
GestureSettingsCard(R.string.gesture_recognition) {
Text(stringResource(R.string.gesture_threshold, config.gestureThreshold), style = MaterialTheme.typography.bodyMedium)
Slider(config.gestureThreshold.toFloat(), { change(config.copy(gestureThreshold = it.toInt())) }, valueRange = 10f..100f, steps = 17)
Text(stringResource(R.string.gesture_threshold_hint), color = p.onSurfaceVariant, style = MaterialTheme.typography.bodySmall)
}
GestureSettingsCard(R.string.gesture_feedback) {
GestureToggle(R.string.gesture_debug, config.showGestureDebugOverlay) { change(config.copy(showGestureDebugOverlay = it)) }
@@ -170,7 +165,7 @@ fun TouchGestureDialog(game: String?, onDismiss: () -> Unit, onSaved: () -> Unit
}
@Composable
private fun GestureDialogFrame(title: String, subtitle: String, onDismiss: () -> Unit,
private fun GestureDialogFrame(onDismiss: () -> Unit,
footer: @Composable () -> Unit = {}, content: @Composable ColumnScope.() -> Unit) {
val p = LocalPalette.current
// The app window does not opt into RTL, so these dialogs follow their resource locale explicitly.
@@ -181,15 +176,8 @@ private fun GestureDialogFrame(title: String, subtitle: String, onDismiss: () ->
Surface(Modifier.widthIn(max = 1040.dp).fillMaxWidth().fillMaxHeight(), shape = RoundedCornerShape(22.dp), color = p.background,
contentColor = p.onBackground, border = BorderStroke(1.dp, p.line2)) {
Column {
Row(Modifier.fillMaxWidth().padding(start = 20.dp, end = 8.dp, top = 14.dp, bottom = 12.dp), verticalAlignment = Alignment.CenterVertically) {
Surface(shape = RoundedCornerShape(12.dp), color = p.primary.copy(alpha = 0.14f)) {
Icon(Icons.Default.TouchApp, null, tint = p.primary, modifier = Modifier.padding(10.dp).size(24.dp))
}
Column(Modifier.weight(1f).padding(horizontal = 14.dp), verticalArrangement = Arrangement.spacedBy(3.dp)) {
Text(title, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.SemiBold)
Text(subtitle, style = MaterialTheme.typography.bodySmall, color = p.onSurfaceVariant)
}
IconButton(onClick = onDismiss) { Icon(Icons.Default.Close, stringResource(R.string.gesture_close)) }
Row(Modifier.fillMaxWidth().padding(end = 4.dp), horizontalArrangement = Arrangement.End) {
IconButton(onClick = onDismiss, modifier = Modifier.size(40.dp)) { Icon(Icons.Default.Close, stringResource(R.string.gesture_close)) }
}
content()
HorizontalDivider(color = p.line)
@@ -202,11 +190,8 @@ private fun GestureDialogFrame(title: String, subtitle: String, onDismiss: () ->
}
@Composable
private fun GestureSection(@StringRes title: Int, @StringRes hint: Int) {
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
Text(stringResource(title), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold)
Text(stringResource(hint), style = MaterialTheme.typography.bodyMedium, color = LocalPalette.current.onSurfaceVariant)
}
private fun GestureSection(@StringRes title: Int) {
Text(stringResource(title), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold)
}
@Composable
@@ -242,18 +227,18 @@ private fun GestureActionField(id: String, @StringRes gesture: Int, selected: St
Icon(Icons.AutoMirrored.Filled.ArrowForward, null, modifier = Modifier.size(19.dp), tint = p.onSurfaceVariant)
}
}
if (open) GestureActionPicker(choices, selected, stringResource(gesture), onDismiss = { open = false }) { open = false; onChoose(it) }
if (open) GestureActionPicker(choices, selected, onDismiss = { open = false }) { open = false; onChoose(it) }
}
@Composable
internal fun GestureActionPicker(choices: List<String>, selected: String, gesture: String, onDismiss: () -> Unit, onChoose: (String) -> Unit) {
internal fun GestureActionPicker(choices: List<String>, selected: String, onDismiss: () -> Unit, onChoose: (String) -> Unit) {
var query by rememberSaveable { mutableStateOf("") }
var category by remember { mutableStateOf<GestureActionGroup?>(null) }
val catalog = choices.distinct().map { GestureAction(it, gestureActionTitle(it), gestureActionGroup(it)) }
val groups = GestureActionGroup.entries.filter { group -> catalog.any { it.group == group } }
val shown = filterGestureActions(catalog, query, category)
val p = LocalPalette.current
GestureDialogFrame(stringResource(R.string.gesture_action), stringResource(R.string.gesture_action_for, gesture), onDismiss) {
GestureDialogFrame(onDismiss) {
OutlinedTextField(query, onValueChange = { query = it }, modifier = Modifier.fillMaxWidth().padding(horizontal = 20.dp).testTag("gesture-action-search"),
singleLine = true, shape = RoundedCornerShape(12.dp), placeholder = { Text(stringResource(R.string.gesture_search_actions)) },
leadingIcon = { Icon(Icons.Default.Search, null) }, trailingIcon = {
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">النقر مرة واحدة</string>
<string name="gesture_hold_delay">مهلة الضغط المستمر</string>
<string name="gesture_double_delay">الفاصل بين النقرتين</string>
<string name="gesture_scope_game">ينطبق على اللعبة الحالية</string>
<string name="gesture_scope_default">الإعدادات الافتراضية لجميع الألعاب</string>
<string name="gesture_reset">استعادة إعدادات الإيماءات الأصلية</string>
<string name="gesture_cancel">إلغاء</string>
<string name="gesture_action">اختيار إجراء</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">عجلة الفأرة</string>
<string name="gesture_threshold">عتبة الإيماءات: %1$d بكسل</string>
<string name="gesture_debug">إظهار الإيماءة المكتشفة</string>
<string name="gesture_editor_subtitle">عناصر تحكم الفأرة ولوحة المفاتيح مرتبة حسب الإيماءة</string>
<string name="gesture_tab_one">إصبع واحد</string>
<string name="gesture_tab_two">إصبعان</string>
<string name="gesture_tab_three">ثلاثة أصابع</string>
<string name="gesture_tab_options">خيارات</string>
<string name="gesture_one_hint">اختر إجراء النقر أو السحب أو الضغط المستمر.</string>
<string name="gesture_two_hint">اضبط تحريك الكاميرا والتكبير والنقرات الثانوية.</string>
<string name="gesture_three_hint">اجعل الاختصارات الإضافية في متناولك.</string>
<string name="gesture_options_hint">اضبط الحركة والتعرّف والاستجابة المرئية.</string>
<string name="gesture_defaults">الافتراضية</string>
<string name="gesture_game">هذه اللعبة</string>
<string name="gesture_use_defaults">استخدام الإعدادات الافتراضية</string>
<string name="gesture_inheriting">تُستخدم الإعدادات الافتراضية. يؤدي التعديل إلى إنشاء إعدادات خاصة باللعبة.</string>
<string name="gesture_save_changes">حفظ التغييرات</string>
<string name="gesture_close">إغلاق</string>
<string name="gesture_action_label">الإجراء</string>
<string name="gesture_action_for">لـ %1$s</string>
<string name="gesture_search_actions">البحث عن إجراءات الفأرة أو مفاتيح لوحة المفاتيح</string>
<string name="gesture_clear_search">مسح البحث</string>
<string name="gesture_all_actions">الكل</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">لوحة الأرقام</string>
<string name="gesture_group_symbols">الرموز</string>
<string name="gesture_movement">حركة الفأرة</string>
<string name="gesture_movement_hint">يتبع السحب المباشر موضع اللمس. ويتبع السحب النسبي حركة الإصبع، وهو مفيد عندما تعيد اللعبة الفأرة إلى المنتصف.</string>
<string name="gesture_middle_relative_hint">يتبع تحريك العرض بالزر الأوسط حركة الإصبع دائمًا لتجنّب قفزات المؤشر.</string>
<string name="gesture_direct">مباشر</string>
<string name="gesture_relative">نسبي</string>
<string name="gesture_recognition">التعرّف على الإيماءات</string>
<string name="gesture_threshold_hint">تحرّك هذه المسافة قبل أن تتحول إيماءة بإصبعين أو ثلاثة إلى تحريك العرض أو التكبير.</string>
<string name="gesture_feedback">الاستجابة المرئية</string>
<string name="gesture_mouse_behavior">سلوك زر الفأرة</string>
<string name="gesture_ms">%1$d مللي ثانية</string>
+28 -3
View File
@@ -512,7 +512,9 @@
<string name="comp_delete_original_title">هل تريد حذف هذه النسخة الأصلية؟</string>
<string name="comp_delete_original_body">هذه النسخة الأصلية من %1$s تعود إلى إصدار سابق من %2$s. يتم دائمًا الاحتفاظ بالنسخة الأصلية للإصدار الحالي.</string>
<string name="comp_nightlies_count">في الإصدارات الليلية · %1$d</string>
<string name="comp_refresh_to_list">حدّث لعرض الحزم في الإصدارات الليلية.</string>
<string name="comp_channel_stable">مستقر</string>
<string name="comp_channel_nightly">ليلي</string>
<string name="comp_refresh_to_list">حدّث لعرض الحزم في إصدارات Nightlies وDroidDeck.</string>
<string name="comp_nothing_new">لا جديد منذ آخر فحص.</string>
<string name="comp_import_wcp">استيراد ملف ‎.wcp</string>
<string name="comp_restore_original">استعادة النسخة الأصلية لـ Proton هذا</string>
@@ -590,6 +592,16 @@
<string name="drawer_prev_page">الصفحة السابقة</string>
<string name="drawer_next_page">الصفحة التالية</string>
<string name="drawer_hud">واجهة الأداء</string>
<string name="drawer_hud_fps">معدل الإطارات</string>
<string name="drawer_hud_battery">درجة حرارة البطارية</string>
<string name="drawer_hud_graph">مخطط الأداء</string>
<string name="drawer_hud_color">اللون</string>
<string name="drawer_hud_color_mint">نعناعي</string>
<string name="drawer_hud_color_white">أبيض</string>
<string name="drawer_hud_color_sky">سماوي</string>
<string name="drawer_hud_color_amber">كهرماني</string>
<string name="drawer_hud_color_violet">بنفسجي</string>
<string name="drawer_hud_opacity">العتامة</string>
<string name="drawer_scaling">وضع التحجيم</string>
<string name="drawer_scaling_sharpness">حدة التحجيم</string>
<string name="drawer_effects">مؤثرات الشاشة</string>
@@ -1854,7 +1866,8 @@
<string name="cmgr_original_kept">تم الاحتفاظ بأصل النسخة المثبَّتة: فهو طريق العودة.</string>
<string name="cmgr_not_stored">غير مخزَّن</string>
<string name="cmgr_deleted_original">تم حذف أصل %2$s من %1$s.</string>
<string name="cmgr_nightlies_only">التنزيلات تأتي فقط من إصدارات Nightlies</string>
<string name="cmgr_nightlies_only">التنزيلات تأتي فقط من إصدارات Nightlies وDroidDeck</string>
<string name="cmgr_nightly_replaced">فشل التنزيل: ربما استُبدل هذا الإصدار الليلي بإصدار أحدث. حدّث القائمة وحاول مرة أخرى.</string>
<string name="cmgr_list_predates_checksums">قائمة الحزم هذه أقدم من إضافة المجاميع الاختبارية - حدِّثها وحاوِل مرة أخرى</string>
<string name="cmgr_checksum_mismatch">عدم تطابق المجموع الاختباري</string>
@@ -2110,6 +2123,9 @@
<string name="cloud_last_sync">آخر مزامنة %1$s</string>
<string name="cloud_never">لم تتم المزامنة بعد</string>
<string name="cloud_done">%1$d ملفات</string>
<string name="cloud_up_to_date">محدَّث بالفعل</string>
<string name="cloud_signed_out">سجّل الدخول إلى المتجر لمزامنة الحفظ</string>
<string name="cloud_not_synced">لم تتم مزامنة الحفظ</string>
<string name="stores_eyebrow_installed">مثبَّتة</string>
<string name="stores_eyebrow_library">في مكتبتك</string>
<string name="stores_eyebrow_store">متجر</string>
@@ -2421,7 +2437,7 @@
<string name="touch_done">تم</string>
<string name="touch_save_failed">تعذّر حفظ تخطيط اللمس</string>
<string name="touch_saved">تم حفظ تخطيط اللمس في Steam</string>
<string name="touch_app_id">التطبيق %1$d</string>
<string name="touch_app_id">التطبيق %1$s</string>
<string name="touch_label_hint">التسمية (اختياري)</string>
<string name="touch_icons_missing">لم يتم العثور على أيقونات Steam</string>
<plurals name="touch_icons_found">
@@ -2520,6 +2536,15 @@
<string name="glasses_vr_fov">مجال رؤية SteamVR</string>
<string name="glasses_vr_fov_hint">القيمة الأقل تقرّب SteamVR وتملأ النظارة؛ والأعلى تُظهر المزيد مما حولك.</string>
<string name="glasses_playing">جارٍ اللعب على %1$s</string>
<string name="glasses_phone_recenter">إعادة التوسيط</string>
<string name="glasses_phone_steamvr_menu">قائمة SteamVR</string>
<string name="glasses_phone_switch_sticks">العصي: اليدان ⇄ اللعبة</string>
<string name="glasses_phone_controllers">وحدات التحكم: %1$s</string>
<string name="glasses_phone_keyboard">لوحة المفاتيح</string>
<string name="glasses_phone_session_menu">قائمة الجلسة</string>
<string name="glasses_phone_stop_steamvr">إيقاف SteamVR</string>
<string name="glasses_phone_brightness">السطوع %1$d / %2$d</string>
<string name="glasses_phone_battery">البطارية %1$d%% · %2$d °C</string>
<string name="glasses_calibration">معايرة التتبّع</string>
<string name="glasses_calibration_hint">يقلّل الانجراف ويضبط المرجع الأفقي.</string>
<string name="glasses_calibration_saved_hint">تُطبَّق المعايرة المحفوظة على هذه النظارة.</string>
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Hacer clic una vez</string>
<string name="gesture_hold_delay">Tiempo de pulsación sostenida</string>
<string name="gesture_double_delay">Intervalo de doble toque</string>
<string name="gesture_scope_game">Se aplica al juego actual</string>
<string name="gesture_scope_default">Ajustes predeterminados para todos los juegos</string>
<string name="gesture_reset">Restablecer los ajustes originales de gestos</string>
<string name="gesture_cancel">Cancelar</string>
<string name="gesture_action">Elegir acción</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Rueda del ratón</string>
<string name="gesture_threshold">Umbral de gestos: %1$d px</string>
<string name="gesture_debug">Mostrar gesto reconocido</string>
<string name="gesture_editor_subtitle">Controles de ratón y teclado organizados por gesto</string>
<string name="gesture_tab_one">Un dedo</string>
<string name="gesture_tab_two">Dos dedos</string>
<string name="gesture_tab_three">Tres dedos</string>
<string name="gesture_tab_options">Opciones</string>
<string name="gesture_one_hint">Elige qué debe hacer un toque, arrastre o pulsación sostenida.</string>
<string name="gesture_two_hint">Configura el movimiento de cámara, el zoom y los clics secundarios.</string>
<string name="gesture_three_hint">Ten más accesos directos al alcance de la mano.</string>
<string name="gesture_options_hint">Ajusta el movimiento, el reconocimiento y la respuesta visual.</string>
<string name="gesture_defaults">Predeterminados</string>
<string name="gesture_game">Este juego</string>
<string name="gesture_use_defaults">Usar valores predeterminados</string>
<string name="gesture_inheriting">Se usan los ajustes predeterminados. Al editarlos, se crean ajustes específicos del juego.</string>
<string name="gesture_save_changes">Guardar cambios</string>
<string name="gesture_close">Cerrar</string>
<string name="gesture_action_label">ACCIÓN</string>
<string name="gesture_action_for">Para %1$s</string>
<string name="gesture_search_actions">Buscar acciones de ratón o teclas del teclado</string>
<string name="gesture_clear_search">Borrar búsqueda</string>
<string name="gesture_all_actions">Todas</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Teclado numérico</string>
<string name="gesture_group_symbols">Símbolos</string>
<string name="gesture_movement">Movimiento del ratón</string>
<string name="gesture_movement_hint">El arrastre directo sigue la posición del toque. El relativo sigue el movimiento del dedo y resulta útil cuando un juego centra el ratón.</string>
<string name="gesture_middle_relative_hint">El desplazamiento con el botón central siempre sigue el movimiento del dedo para evitar saltos del cursor.</string>
<string name="gesture_direct">Directo</string>
<string name="gesture_relative">Relativo</string>
<string name="gesture_recognition">Reconocimiento de gestos</string>
<string name="gesture_threshold_hint">Recorre esta distancia antes de que un gesto con dos o tres dedos se convierta en desplazamiento o zoom.</string>
<string name="gesture_feedback">Respuesta visual</string>
<string name="gesture_mouse_behavior">Comportamiento del botón del ratón</string>
<string name="gesture_ms">%1$d ms</string>
+27 -2
View File
@@ -499,7 +499,9 @@
<string name="comp_delete_original_title">¿Eliminar este original?</string>
<string name="comp_delete_original_body">Este original de %1$s es de una versión anterior de %2$s. El original de la versión actual siempre se conserva.</string>
<string name="comp_nightlies_count">En las Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Actualiza para listar los paquetes de las Nightlies.</string>
<string name="comp_channel_stable">Estable</string>
<string name="comp_channel_nightly">Nocturna</string>
<string name="comp_refresh_to_list">Actualiza para listar los paquetes de Nightlies y DroidDeck.</string>
<string name="comp_nothing_new">Nada nuevo desde la última comprobación.</string>
<string name="comp_import_wcp">Importar .wcp</string>
<string name="comp_restore_original">Restaurar el original de este Proton</string>
@@ -577,6 +579,16 @@
<string name="drawer_prev_page">Página anterior</string>
<string name="drawer_next_page">Página siguiente</string>
<string name="drawer_hud">HUD de rendimiento</string>
<string name="drawer_hud_fps">Tasa de fotogramas</string>
<string name="drawer_hud_battery">Temperatura de la batería</string>
<string name="drawer_hud_graph">Gráfico de rendimiento</string>
<string name="drawer_hud_color">Color</string>
<string name="drawer_hud_color_mint">Menta</string>
<string name="drawer_hud_color_white">Blanco</string>
<string name="drawer_hud_color_sky">Celeste</string>
<string name="drawer_hud_color_amber">Ámbar</string>
<string name="drawer_hud_color_violet">Violeta</string>
<string name="drawer_hud_opacity">Opacidad</string>
<string name="drawer_scaling">Modo de escalado</string>
<string name="drawer_scaling_sharpness">Nitidez del escalado</string>
<string name="drawer_effects">Efectos de pantalla</string>
@@ -1830,7 +1842,8 @@
<string name="cmgr_original_kept">El original de la versión instalada se conserva: es el camino de vuelta.</string>
<string name="cmgr_not_stored">No guardado</string>
<string name="cmgr_deleted_original">Se eliminó el original de %1$s de %2$s.</string>
<string name="cmgr_nightlies_only">Las descargas solo proceden de las versiones Nightlies</string>
<string name="cmgr_nightlies_only">Las descargas solo proceden de las versiones de Nightlies y DroidDeck</string>
<string name="cmgr_nightly_replaced">Falló la descarga: es posible que esta compilación nocturna se haya reemplazado por una más nueva. Actualiza la lista e inténtalo de nuevo.</string>
<string name="cmgr_list_predates_checksums">Esta lista de paquetes es anterior a las sumas de verificación - actualízala e inténtalo de nuevo</string>
<string name="cmgr_checksum_mismatch">La suma de verificación no coincide</string>
<string name="sprefs_upscaler_linear">Lineal</string>
@@ -2053,6 +2066,9 @@
<string name="cloud_last_sync">Última sincronización %1$s</string>
<string name="cloud_never">Aún sin sincronizar</string>
<string name="cloud_done">%1$d archivos</string>
<string name="cloud_up_to_date">Ya está al día</string>
<string name="cloud_signed_out">Inicia sesión en la tienda para sincronizar las partidas</string>
<string name="cloud_not_synced">No se sincronizaron las partidas</string>
<string name="stores_eyebrow_installed">instalado</string>
<string name="stores_eyebrow_library">en tu biblioteca</string>
<string name="stores_eyebrow_store">tienda</string>
@@ -2458,6 +2474,15 @@
<string name="glasses_vr_fov">Campo de visión de SteamVR</string>
<string name="glasses_vr_fov_hint">Más bajo acerca SteamVR y llena las gafas; más alto muestra más a tu alrededor.</string>
<string name="glasses_playing">Jugando en %1$s</string>
<string name="glasses_phone_recenter">Recentrar</string>
<string name="glasses_phone_steamvr_menu">Menú de SteamVR</string>
<string name="glasses_phone_switch_sticks">Sticks: manos ⇄ juego</string>
<string name="glasses_phone_controllers">Controles: %1$s</string>
<string name="glasses_phone_keyboard">Teclado</string>
<string name="glasses_phone_session_menu">Menú de sesión</string>
<string name="glasses_phone_stop_steamvr">Detener SteamVR</string>
<string name="glasses_phone_brightness">Brillo %1$d / %2$d</string>
<string name="glasses_phone_battery">Batería %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Calibración del seguimiento</string>
<string name="glasses_calibration_hint">Reduce la deriva y alinea la referencia horizontal.</string>
<string name="glasses_calibration_saved_hint">Estas gafas usan la calibración guardada.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Еднократно щракване</string>
<string name="gesture_hold_delay">Закъснение за задържане</string>
<string name="gesture_double_delay">Интервал за двойно докосване</string>
<string name="gesture_scope_game">Прилага се към текущата игра</string>
<string name="gesture_scope_default">Настройки по подразбиране за всички игри</string>
<string name="gesture_reset">Възстановяване на първоначалните настройки на жестовете</string>
<string name="gesture_cancel">Отказ</string>
<string name="gesture_action">Избор на действие</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Колелце на мишката</string>
<string name="gesture_threshold">Праг на жестовете: %1$d пиксела</string>
<string name="gesture_debug">Показване на разпознатия жест</string>
<string name="gesture_editor_subtitle">Управление с мишка и клавиатура, подредено по жестове</string>
<string name="gesture_tab_one">Един пръст</string>
<string name="gesture_tab_two">Два пръста</string>
<string name="gesture_tab_three">Три пръста</string>
<string name="gesture_tab_options">Опции</string>
<string name="gesture_one_hint">Изберете действието при докосване, плъзгане или задържане.</string>
<string name="gesture_two_hint">Настройте преместването на камерата, мащабирането и вторичните щраквания.</string>
<string name="gesture_three_hint">Дръжте допълнителните команди подръка.</string>
<string name="gesture_options_hint">Настройте движението, разпознаването и визуалната обратна връзка.</string>
<string name="gesture_defaults">Стандартни настройки</string>
<string name="gesture_game">Тази игра</string>
<string name="gesture_use_defaults">Използване на подразбиращите се</string>
<string name="gesture_inheriting">Използват се настройките по подразбиране. Редактирането създава настройки за тази игра.</string>
<string name="gesture_save_changes">Запазване на промените</string>
<string name="gesture_close">Затвори</string>
<string name="gesture_action_label">ДЕЙСТВИЕ</string>
<string name="gesture_action_for">За %1$s</string>
<string name="gesture_search_actions">Търсене на действия с мишката или клавиши</string>
<string name="gesture_clear_search">Изчистване на търсенето</string>
<string name="gesture_all_actions">Всички</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Цифрова клавиатура</string>
<string name="gesture_group_symbols">Символи</string>
<string name="gesture_movement">Движение на мишката</string>
<string name="gesture_movement_hint">Директното плъзгане следва мястото на докосване. Относителното следва движението на пръста и е полезно, когато играта центрира мишката.</string>
<string name="gesture_middle_relative_hint">Преместването със средния бутон винаги следва движението на пръста, за да няма скокове на курсора.</string>
<string name="gesture_direct">Директно</string>
<string name="gesture_relative">Относително</string>
<string name="gesture_recognition">Разпознаване на жестове</string>
<string name="gesture_threshold_hint">Изминете това разстояние, преди жест с два или три пръста да стане преместване или мащабиране.</string>
<string name="gesture_feedback">Визуална обратна връзка</string>
<string name="gesture_mouse_behavior">Поведение на бутона на мишката</string>
<string name="gesture_ms">%1$d мс</string>
+28 -3
View File
@@ -504,7 +504,9 @@
<string name="comp_delete_original_title">Изтриване на този оригинал?</string>
<string name="comp_delete_original_body">Този оригинал на %1$s е от по-стара версия на %2$s. Оригиналът на текущата версия винаги се запазва.</string>
<string name="comp_nightlies_count">В Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Обновете, за да видите пакетите в Nightlies.</string>
<string name="comp_channel_stable">Стабилна</string>
<string name="comp_channel_nightly">Нощна</string>
<string name="comp_refresh_to_list">Обновете, за да видите пакетите в Nightlies и DroidDeck.</string>
<string name="comp_nothing_new">Нищо ново от последната проверка.</string>
<string name="comp_import_wcp">Импортиране на .wcp</string>
<string name="comp_restore_original">Възстановяване на оригинала на този Proton</string>
@@ -582,6 +584,16 @@
<string name="drawer_prev_page">Предишна страница</string>
<string name="drawer_next_page">Следваща страница</string>
<string name="drawer_hud">HUD за производителност</string>
<string name="drawer_hud_fps">Честота на кадрите</string>
<string name="drawer_hud_battery">Температура на батерията</string>
<string name="drawer_hud_graph">Графика на производителността</string>
<string name="drawer_hud_color">Цвят</string>
<string name="drawer_hud_color_mint">Мента</string>
<string name="drawer_hud_color_white">Бяло</string>
<string name="drawer_hud_color_sky">Небесно</string>
<string name="drawer_hud_color_amber">Кехлибарено</string>
<string name="drawer_hud_color_violet">Виолетово</string>
<string name="drawer_hud_opacity">Прозрачност</string>
<string name="drawer_scaling">Режим на мащабиране</string>
<string name="drawer_scaling_sharpness">Острота на мащабиране</string>
<string name="drawer_effects">Ефекти на екрана</string>
@@ -1770,7 +1782,8 @@
<string name="cmgr_original_kept">Оригиналът на инсталираната версия е запазен: той е пътят назад.</string>
<string name="cmgr_not_stored">Не е запазен</string>
<string name="cmgr_deleted_original">Изтрит е оригиналът %1$s на %2$s.</string>
<string name="cmgr_nightlies_only">Изтеглянията идват само от версиите Nightlies</string>
<string name="cmgr_nightlies_only">Изтеглянията идват само от версиите на Nightlies и DroidDeck</string>
<string name="cmgr_nightly_replaced">Изтеглянето не бе успешно: тази нощна версия може да е заменена с по-нова. Обновете списъка и опитайте отново.</string>
<string name="cmgr_list_predates_checksums">Този списък с пакети е отпреди въвеждането на контролни суми - обнови го и опитай отново</string>
<string name="cmgr_checksum_mismatch">Несъответствие в контролната сума</string>
@@ -2026,6 +2039,9 @@
<string name="cloud_last_sync">Последна синхронизация %1$s</string>
<string name="cloud_never">Още не е синхронизирано</string>
<string name="cloud_done">%1$d файла</string>
<string name="cloud_up_to_date">Вече е актуално</string>
<string name="cloud_signed_out">Влезте в магазина, за да синхронизирате записите</string>
<string name="cloud_not_synced">Записите не бяха синхронизирани</string>
<string name="stores_eyebrow_installed">инсталирана</string>
<string name="stores_eyebrow_library">в библиотеката ти</string>
<string name="stores_eyebrow_store">магазин</string>
@@ -2329,7 +2345,7 @@
<string name="touch_done">Готово</string>
<string name="touch_save_failed">Сензорното разположение не можа да се запази</string>
<string name="touch_saved">Сензорното разположение е запазено в Steam</string>
<string name="touch_app_id">Приложение %1$d</string>
<string name="touch_app_id">Приложение %1$s</string>
<string name="touch_label_hint">Етикет (незадължително)</string>
<string name="touch_icons_missing">Иконите на Steam не бяха намерени</string>
<plurals name="touch_icons_found">
@@ -2420,6 +2436,15 @@
<string name="glasses_vr_fov">Зрително поле на SteamVR</string>
<string name="glasses_vr_fov_hint">По-ниско приближава SteamVR и запълва очилата; по-високо показва повече около вас.</string>
<string name="glasses_playing">Играете на %1$s</string>
<string name="glasses_phone_recenter">Центриране отново</string>
<string name="glasses_phone_steamvr_menu">Меню на SteamVR</string>
<string name="glasses_phone_switch_sticks">Стикове: ръце ⇄ игра</string>
<string name="glasses_phone_controllers">Контролери: %1$s</string>
<string name="glasses_phone_keyboard">Клавиатура</string>
<string name="glasses_phone_session_menu">Меню на сесията</string>
<string name="glasses_phone_stop_steamvr">Спиране на SteamVR</string>
<string name="glasses_phone_brightness">Яркост %1$d / %2$d</string>
<string name="glasses_phone_battery">Батерия %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Калибриране на проследяването</string>
<string name="glasses_calibration_hint">Намалява дрейфа и подравнява хоризонта.</string>
<string name="glasses_calibration_saved_hint">За тези очила се прилага запазено калибриране.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Jednou kliknout</string>
<string name="gesture_hold_delay">Prodleva podržení</string>
<string name="gesture_double_delay">Interval dvojitého klepnutí</string>
<string name="gesture_scope_game">Platí pro aktuální hru</string>
<string name="gesture_scope_default">Výchozí nastavení pro všechny hry</string>
<string name="gesture_reset">Obnovit původní nastavení gest</string>
<string name="gesture_cancel">Zrušit</string>
<string name="gesture_action">Vybrat akci</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Kolečko myši</string>
<string name="gesture_threshold">Práh gest: %1$d px</string>
<string name="gesture_debug">Zobrazovat rozpoznané gesto</string>
<string name="gesture_editor_subtitle">Ovládání myši a klávesnice uspořádané podle gest</string>
<string name="gesture_tab_one">Jeden prst</string>
<string name="gesture_tab_two">Dva prsty</string>
<string name="gesture_tab_three">Tři prsty</string>
<string name="gesture_tab_options">Možnosti</string>
<string name="gesture_one_hint">Vyberte akci pro klepnutí, tažení nebo podržení.</string>
<string name="gesture_two_hint">Nastavte posouvání kamery, přiblížení a vedlejší kliknutí.</string>
<string name="gesture_three_hint">Mějte další zkratky na dosah.</string>
<string name="gesture_options_hint">Upravte pohyb, rozpoznávání a vizuální odezvu.</string>
<string name="gesture_defaults">Výchozí</string>
<string name="gesture_game">Tato hra</string>
<string name="gesture_use_defaults">Použít výchozí</string>
<string name="gesture_inheriting">Používá se výchozí nastavení. Úpravou vznikne nastavení pro tuto hru.</string>
<string name="gesture_save_changes">Uložit změny</string>
<string name="gesture_close">Zavřít</string>
<string name="gesture_action_label">AKCE</string>
<string name="gesture_action_for">Pro %1$s</string>
<string name="gesture_search_actions">Hledat akce myši nebo klávesy</string>
<string name="gesture_clear_search">Vymazat hledání</string>
<string name="gesture_all_actions">Vše</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Numerická klávesnice</string>
<string name="gesture_group_symbols">Symboly</string>
<string name="gesture_movement">Pohyb myši</string>
<string name="gesture_movement_hint">Přímé tažení sleduje polohu dotyku. Relativní tažení sleduje pohyb prstu a hodí se, když hra vrací myš do středu.</string>
<string name="gesture_middle_relative_hint">Posouvání prostředním tlačítkem vždy sleduje pohyb prstu, aby kurzor nepřeskakoval.</string>
<string name="gesture_direct">Přímé</string>
<string name="gesture_relative">Relativní</string>
<string name="gesture_recognition">Rozpoznávání gest</string>
<string name="gesture_threshold_hint">Po překonání této vzdálenosti se gesto dvěma či třemi prsty změní na posouvání nebo přiblížení.</string>
<string name="gesture_feedback">Vizuální odezva</string>
<string name="gesture_mouse_behavior">Chování tlačítka myši</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -508,7 +508,9 @@
<string name="comp_delete_original_title">Smazat tento originál?</string>
<string name="comp_delete_original_body">Tento originál %1$s je z dřívějšího sestavení %2$s. Originál aktuálního sestavení je vždy zachován.</string>
<string name="comp_nightlies_count">Na Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Obnovte pro zobrazení balíčků na Nightlies.</string>
<string name="comp_channel_stable">Stabilní</string>
<string name="comp_channel_nightly">Noční</string>
<string name="comp_refresh_to_list">Obnovte pro zobrazení balíčků na Nightlies a DroidDeck.</string>
<string name="comp_nothing_new">Od poslední kontroly nic nového.</string>
<string name="comp_import_wcp">Importovat .wcp</string>
<string name="comp_restore_original">Obnovit originál tohoto Protonu</string>
@@ -586,6 +588,16 @@
<string name="drawer_prev_page">Předchozí stránka</string>
<string name="drawer_next_page">Další stránka</string>
<string name="drawer_hud">HUD výkonu</string>
<string name="drawer_hud_fps">Snímková frekvence</string>
<string name="drawer_hud_battery">Teplota baterie</string>
<string name="drawer_hud_graph">Graf výkonu</string>
<string name="drawer_hud_color">Barva</string>
<string name="drawer_hud_color_mint">Máta</string>
<string name="drawer_hud_color_white">Bílá</string>
<string name="drawer_hud_color_sky">Nebeská</string>
<string name="drawer_hud_color_amber">Ambrová</string>
<string name="drawer_hud_color_violet">Fialová</string>
<string name="drawer_hud_opacity">Průhlednost</string>
<string name="drawer_scaling">Režim škálování</string>
<string name="drawer_scaling_sharpness">Ostrost škálování</string>
<string name="drawer_effects">Efekty obrazovky</string>
@@ -1812,7 +1824,8 @@
<string name="cmgr_original_kept">Původní verze nainstalovaného sestavení je zachována: je to cesta zpět.</string>
<string name="cmgr_not_stored">Není uloženo</string>
<string name="cmgr_deleted_original">Odstraněna původní verze %2$s z %1$s.</string>
<string name="cmgr_nightlies_only">Stahování pochází jen z vydání Nightlies</string>
<string name="cmgr_nightlies_only">Stahování pochází jen z vydání Nightlies a DroidDeck</string>
<string name="cmgr_nightly_replaced">Stažení selhalo: tento noční build mohl být nahrazen novějším. Obnovte seznam a zkuste to znovu.</string>
<string name="cmgr_list_predates_checksums">Tento seznam balíčků předchází kontrolním součtům - obnovte ho a zkuste to znovu</string>
<string name="cmgr_checksum_mismatch">Neshoda kontrolního součtu</string>
@@ -2068,6 +2081,9 @@
<string name="cloud_last_sync">Poslední synchronizace %1$s</string>
<string name="cloud_never">Ještě nesynchronizováno</string>
<string name="cloud_done">%1$d souborů</string>
<string name="cloud_up_to_date">Už je aktuální</string>
<string name="cloud_signed_out">Pro synchronizaci uložených pozic se přihlaste do obchodu</string>
<string name="cloud_not_synced">Uložené pozice nebyly synchronizovány</string>
<string name="stores_eyebrow_installed">nainstalováno</string>
<string name="stores_eyebrow_library">ve vaší knihovně</string>
<string name="stores_eyebrow_store">obchod</string>
@@ -2375,7 +2391,7 @@
<string name="touch_done">Hotovo</string>
<string name="touch_save_failed">Dotykové rozložení se nepodařilo uložit</string>
<string name="touch_saved">Dotykové rozložení uloženo ve Steamu</string>
<string name="touch_app_id">Aplikace %1$d</string>
<string name="touch_app_id">Aplikace %1$s</string>
<string name="touch_label_hint">Popisek (nepovinné)</string>
<string name="touch_icons_missing">Ikony Steamu nebyly nalezeny</string>
<plurals name="touch_icons_found">
@@ -2470,6 +2486,15 @@
<string name="glasses_vr_fov">Zorné pole SteamVR</string>
<string name="glasses_vr_fov_hint">Nižší hodnota přiblíží SteamVR a vyplní brýle; vyšší ukáže víc z okolí.</string>
<string name="glasses_playing">Hraje se na %1$s</string>
<string name="glasses_phone_recenter">Znovu vycentrovat</string>
<string name="glasses_phone_steamvr_menu">Nabídka SteamVR</string>
<string name="glasses_phone_switch_sticks">Páčky: ruce ⇄ hra</string>
<string name="glasses_phone_controllers">Ovladače: %1$s</string>
<string name="glasses_phone_keyboard">Klávesnice</string>
<string name="glasses_phone_session_menu">Nabídka relace</string>
<string name="glasses_phone_stop_steamvr">Zastavit SteamVR</string>
<string name="glasses_phone_brightness">Jas %1$d / %2$d</string>
<string name="glasses_phone_battery">Baterie %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Kalibrace sledování</string>
<string name="glasses_calibration_hint">Sníží drift a vyrovná vodorovnou referenci.</string>
<string name="glasses_calibration_saved_hint">Pro tyto brýle se používá uložená kalibrace.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Klik én gang</string>
<string name="gesture_hold_delay">Forsinkelse før hold</string>
<string name="gesture_double_delay">Interval for dobbelttryk</string>
<string name="gesture_scope_game">Gælder det aktuelle spil</string>
<string name="gesture_scope_default">Standardindstillinger for alle spil</string>
<string name="gesture_reset">Gendan de oprindelige bevægelsesindstillinger</string>
<string name="gesture_cancel">Annuller</string>
<string name="gesture_action">Vælg handling</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Musehjul</string>
<string name="gesture_threshold">Bevægelsestærskel: %1$d px</string>
<string name="gesture_debug">Vis genkendt bevægelse</string>
<string name="gesture_editor_subtitle">Muse- og tastaturstyring organiseret efter bevægelse</string>
<string name="gesture_tab_one">Én finger</string>
<string name="gesture_tab_two">To fingre</string>
<string name="gesture_tab_three">Tre fingre</string>
<string name="gesture_tab_options">Indstillinger</string>
<string name="gesture_one_hint">Vælg, hvad et tryk, træk eller hold skal gøre.</string>
<string name="gesture_two_hint">Indstil kamerapanorering, zoom og sekundære klik.</string>
<string name="gesture_three_hint">Hav flere genveje inden for rækkevidde.</string>
<string name="gesture_options_hint">Juster bevægelse, genkendelse og visuel feedback.</string>
<string name="gesture_defaults">Standarder</string>
<string name="gesture_game">Dette spil</string>
<string name="gesture_use_defaults">Brug standardindstillinger</string>
<string name="gesture_inheriting">Bruger standardindstillingerne. Redigering opretter særlige indstillinger for spillet.</string>
<string name="gesture_save_changes">Gem ændringer</string>
<string name="gesture_close">Luk</string>
<string name="gesture_action_label">HANDLING</string>
<string name="gesture_action_for">For %1$s</string>
<string name="gesture_search_actions">Søg efter musehandlinger eller tastaturtaster</string>
<string name="gesture_clear_search">Ryd søgning</string>
<string name="gesture_all_actions">Alle</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Numerisk tastatur</string>
<string name="gesture_group_symbols">Symboler</string>
<string name="gesture_movement">Musebevægelse</string>
<string name="gesture_movement_hint">Direkte træk følger berøringspositionen. Relative træk følger fingerbevægelsen og er nyttige, når et spil centrerer musen.</string>
<string name="gesture_middle_relative_hint">Panorering med midterste museknap følger altid fingerbevægelsen for at undgå markørspring.</string>
<string name="gesture_direct">Direkte</string>
<string name="gesture_relative">Relativ</string>
<string name="gesture_recognition">Genkendelse af bevægelser</string>
<string name="gesture_threshold_hint">Bevæg fingrene så langt, før en bevægelse med to eller tre fingre bliver til panorering eller zoom.</string>
<string name="gesture_feedback">Visuel feedback</string>
<string name="gesture_mouse_behavior">Museknappens funktion</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -504,7 +504,9 @@
<string name="comp_delete_original_title">Slet denne original?</string>
<string name="comp_delete_original_body">Denne original af %1$s er fra en tidligere build af %2$s. Den aktuelle builds original bevares altid.</string>
<string name="comp_nightlies_count">På Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Opdater for at se pakker på Nightlies.</string>
<string name="comp_channel_stable">Stabil</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Opdater for at se pakker på Nightlies og DroidDeck.</string>
<string name="comp_nothing_new">Intet nyt siden sidste kontrol.</string>
<string name="comp_import_wcp">Importer .wcp</string>
<string name="comp_restore_original">Gendan denne Protons original</string>
@@ -582,6 +584,16 @@
<string name="drawer_prev_page">Forrige side</string>
<string name="drawer_next_page">Næste side</string>
<string name="drawer_hud">Ydelses-HUD</string>
<string name="drawer_hud_fps">Billedhastighed</string>
<string name="drawer_hud_battery">Batteritemperatur</string>
<string name="drawer_hud_graph">Ydelsesgraf</string>
<string name="drawer_hud_color">Farve</string>
<string name="drawer_hud_color_mint">Mint</string>
<string name="drawer_hud_color_white">Hvid</string>
<string name="drawer_hud_color_sky">Himmelblå</string>
<string name="drawer_hud_color_amber">Ravgul</string>
<string name="drawer_hud_color_violet">Violet</string>
<string name="drawer_hud_opacity">Gennemsigtighed</string>
<string name="drawer_scaling">Skaleringstilstand</string>
<string name="drawer_scaling_sharpness">Skaleringsskarphed</string>
<string name="drawer_effects">Skærmeffekter</string>
@@ -1770,7 +1782,8 @@
<string name="cmgr_original_kept">Originalen af den installerede version beholdes: den er vejen tilbage.</string>
<string name="cmgr_not_stored">Ikke gemt</string>
<string name="cmgr_deleted_original">Slettede %1$s-originalen af %2$s.</string>
<string name="cmgr_nightlies_only">Downloads kommer kun fra Nightlies-udgivelserne</string>
<string name="cmgr_nightlies_only">Downloads kommer kun fra Nightlies- og DroidDeck-udgivelserne</string>
<string name="cmgr_nightly_replaced">Download mislykkedes: denne nightly kan være erstattet af en nyere build. Opdater listen, og prøv igen.</string>
<string name="cmgr_list_predates_checksums">Denne pakkeliste er ældre end tjeksummer - opdater den, og forsøg igen</string>
<string name="cmgr_checksum_mismatch">Tjeksum stemmer ikke</string>
@@ -2026,6 +2039,9 @@
<string name="cloud_last_sync">Senest synkroniseret %1$s</string>
<string name="cloud_never">Ikke synkroniseret endnu</string>
<string name="cloud_done">%1$d filer</string>
<string name="cloud_up_to_date">Allerede opdateret</string>
<string name="cloud_signed_out">Log ind i butikken for at synkronisere gemte spil</string>
<string name="cloud_not_synced">Gemte spil blev ikke synkroniseret</string>
<string name="stores_eyebrow_installed">installeret</string>
<string name="stores_eyebrow_library">i dit bibliotek</string>
<string name="stores_eyebrow_store">butik</string>
@@ -2329,7 +2345,7 @@
<string name="touch_done">Udført</string>
<string name="touch_save_failed">Berøringslayoutet kunne ikke gemmes</string>
<string name="touch_saved">Berøringslayout gemt i Steam</string>
<string name="touch_app_id">App %1$d</string>
<string name="touch_app_id">App %1$s</string>
<string name="touch_label_hint">Etiket (valgfrit)</string>
<string name="touch_icons_missing">Steams ikoner blev ikke fundet</string>
<plurals name="touch_icons_found">
@@ -2420,6 +2436,15 @@
<string name="glasses_vr_fov">SteamVR-synsfelt</string>
<string name="glasses_vr_fov_hint">Lavere bringer SteamVR tættere på og fylder brillen; højere viser mere omkring dig.</string>
<string name="glasses_playing">Spiller på %1$s</string>
<string name="glasses_phone_recenter">Centrér igen</string>
<string name="glasses_phone_steamvr_menu">SteamVR-menu</string>
<string name="glasses_phone_switch_sticks">Pinde: hænder ⇄ spil</string>
<string name="glasses_phone_controllers">Controllere: %1$s</string>
<string name="glasses_phone_keyboard">Tastatur</string>
<string name="glasses_phone_session_menu">Sessionsmenu</string>
<string name="glasses_phone_stop_steamvr">Stop SteamVR</string>
<string name="glasses_phone_brightness">Lysstyrke %1$d / %2$d</string>
<string name="glasses_phone_battery">Batteri %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Sporingskalibrering</string>
<string name="glasses_calibration_hint">Mindsker drift og justerer den vandrette reference.</string>
<string name="glasses_calibration_saved_hint">Gemt kalibrering anvendes på denne brille.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Einmal klicken</string>
<string name="gesture_hold_delay">Halteverzögerung</string>
<string name="gesture_double_delay">Doppeltipp-Intervall</string>
<string name="gesture_scope_game">Gilt für das aktuelle Spiel</string>
<string name="gesture_scope_default">Standardeinstellungen für alle Spiele</string>
<string name="gesture_reset">Ursprüngliche Gesteneinstellungen wiederherstellen</string>
<string name="gesture_cancel">Abbrechen</string>
<string name="gesture_action">Aktion auswählen</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Mausrad</string>
<string name="gesture_threshold">Gestenschwelle: %1$d px</string>
<string name="gesture_debug">Erkannte Geste anzeigen</string>
<string name="gesture_editor_subtitle">Maus- und Tastatursteuerung nach Gesten geordnet</string>
<string name="gesture_tab_one">Ein Finger</string>
<string name="gesture_tab_two">Zwei Finger</string>
<string name="gesture_tab_three">Drei Finger</string>
<string name="gesture_tab_options">Optionen</string>
<string name="gesture_one_hint">Wähle die Aktion für Tippen, Ziehen oder Halten.</string>
<string name="gesture_two_hint">Kameraschwenks, Zoom und sekundäre Klicks anpassen.</string>
<string name="gesture_three_hint">Zusätzliche Kurzbefehle griffbereit halten.</string>
<string name="gesture_options_hint">Bewegung, Erkennung und visuelle Rückmeldung anpassen.</string>
<string name="gesture_defaults">Standardwerte</string>
<string name="gesture_game">Dieses Spiel</string>
<string name="gesture_use_defaults">Standardeinstellungen verwenden</string>
<string name="gesture_inheriting">Standardeinstellungen werden verwendet. Änderungen erstellen eine Spielanpassung.</string>
<string name="gesture_save_changes">Änderungen speichern</string>
<string name="gesture_close">Schließen</string>
<string name="gesture_action_label">AKTION</string>
<string name="gesture_action_for">Für %1$s</string>
<string name="gesture_search_actions">Mausaktionen oder Tastaturtasten suchen</string>
<string name="gesture_clear_search">Suche leeren</string>
<string name="gesture_all_actions">Alle</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Ziffernblock</string>
<string name="gesture_group_symbols">Symbole</string>
<string name="gesture_movement">Mausbewegung</string>
<string name="gesture_movement_hint">Direktes Ziehen folgt der Berührungsposition. Relatives Ziehen folgt der Fingerbewegung und eignet sich für Spiele, die die Maus zentrieren.</string>
<string name="gesture_middle_relative_hint">Schwenks mit mittlerer Maustaste folgen immer der Fingerbewegung, um Zeigersprünge zu vermeiden.</string>
<string name="gesture_direct">Direkt</string>
<string name="gesture_relative">Relativ</string>
<string name="gesture_recognition">Gestenerkennung</string>
<string name="gesture_threshold_hint">Bewege die Finger um diese Strecke, bevor eine Zwei- oder Dreifingergeste als Schwenken oder Zoomen gilt.</string>
<string name="gesture_feedback">Visuelle Rückmeldung</string>
<string name="gesture_mouse_behavior">Verhalten der Maustaste</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -501,7 +501,9 @@
<string name="comp_delete_original_title">Dieses Original löschen?</string>
<string name="comp_delete_original_body">Dieses %1$s-Original stammt aus einem früheren Build von %2$s. Das Original des aktuellen Builds wird immer behalten.</string>
<string name="comp_nightlies_count">In den Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Aktualisiere, um die Pakete in den Nightlies aufzulisten.</string>
<string name="comp_channel_stable">Stabil</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Aktualisiere, um die Pakete in den Nightlies und bei DroidDeck aufzulisten.</string>
<string name="comp_nothing_new">Nichts Neues seit der letzten Prüfung.</string>
<string name="comp_import_wcp">.wcp importieren</string>
<string name="comp_restore_original">Original dieses Protons wiederherstellen</string>
@@ -579,6 +581,16 @@
<string name="drawer_prev_page">Vorherige Seite</string>
<string name="drawer_next_page">Nächste Seite</string>
<string name="drawer_hud">Leistungs-HUD</string>
<string name="drawer_hud_fps">Bildrate</string>
<string name="drawer_hud_battery">Akkutemperatur</string>
<string name="drawer_hud_graph">Leistungsdiagramm</string>
<string name="drawer_hud_color">Farbe</string>
<string name="drawer_hud_color_mint">Minze</string>
<string name="drawer_hud_color_white">Weiß</string>
<string name="drawer_hud_color_sky">Himmelblau</string>
<string name="drawer_hud_color_amber">Bernstein</string>
<string name="drawer_hud_color_violet">Violett</string>
<string name="drawer_hud_opacity">Deckkraft</string>
<string name="drawer_scaling">Skalierungsmodus</string>
<string name="drawer_scaling_sharpness">Skalierungsschärfe</string>
<string name="drawer_effects">Bildschirmeffekte</string>
@@ -1759,7 +1771,8 @@
<string name="cmgr_original_kept">Das Original des installierten Builds bleibt erhalten: Es ist der Weg zurück.</string>
<string name="cmgr_not_stored">Nicht gespeichert</string>
<string name="cmgr_deleted_original">Das %1$s-Original von %2$s wurde gelöscht.</string>
<string name="cmgr_nightlies_only">Downloads kommen nur aus den Nightlies-Releases</string>
<string name="cmgr_nightlies_only">Downloads kommen nur aus den Nightlies- und DroidDeck-Releases</string>
<string name="cmgr_nightly_replaced">Download fehlgeschlagen: Dieser Nightly-Build wurde vielleicht durch einen neueren ersetzt. Aktualisiere die Liste und versuche es erneut.</string>
<string name="cmgr_list_predates_checksums">Diese Paketliste stammt aus der Zeit vor Prüfsummen - aktualisiere sie und versuche es erneut</string>
<string name="cmgr_checksum_mismatch">Prüfsumme stimmt nicht überein</string>
@@ -2015,6 +2028,9 @@
<string name="cloud_last_sync">Zuletzt synchronisiert %1$s</string>
<string name="cloud_never">Noch nicht synchronisiert</string>
<string name="cloud_done">%1$d Dateien</string>
<string name="cloud_up_to_date">Bereits aktuell</string>
<string name="cloud_signed_out">Im Store anmelden, um Spielstände zu synchronisieren</string>
<string name="cloud_not_synced">Spielstände wurden nicht synchronisiert</string>
<string name="stores_eyebrow_installed">installiert</string>
<string name="stores_eyebrow_library">in deiner Bibliothek</string>
<string name="stores_eyebrow_store">Store</string>
@@ -2315,7 +2331,7 @@
<string name="touch_done">Fertig</string>
<string name="touch_save_failed">Das Touch-Layout konnte nicht gespeichert werden</string>
<string name="touch_saved">Touch-Layout in Steam gespeichert</string>
<string name="touch_app_id">App %1$d</string>
<string name="touch_app_id">App %1$s</string>
<string name="touch_label_hint">Bezeichnung (optional)</string>
<string name="touch_icons_missing">Steams Symbole wurden nicht gefunden</string>
<plurals name="touch_icons_found">
@@ -2406,6 +2422,15 @@
<string name="glasses_vr_fov">SteamVR-Sichtfeld</string>
<string name="glasses_vr_fov_hint">Niedriger holt SteamVR näher heran und füllt die Brille; höher zeigt mehr von deiner Umgebung.</string>
<string name="glasses_playing">Spiel läuft auf %1$s</string>
<string name="glasses_phone_recenter">Neu zentrieren</string>
<string name="glasses_phone_steamvr_menu">SteamVR-Menü</string>
<string name="glasses_phone_switch_sticks">Sticks: Hände ⇄ Spiel</string>
<string name="glasses_phone_controllers">Controller: %1$s</string>
<string name="glasses_phone_keyboard">Tastatur</string>
<string name="glasses_phone_session_menu">Sitzungsmenü</string>
<string name="glasses_phone_stop_steamvr">SteamVR beenden</string>
<string name="glasses_phone_brightness">Helligkeit %1$d / %2$d</string>
<string name="glasses_phone_battery">Akku %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Tracking-Kalibrierung</string>
<string name="glasses_calibration_hint">Verringert Drift und richtet die waagerechte Referenz aus.</string>
<string name="glasses_calibration_saved_hint">Für diese Brille wird eine gespeicherte Kalibrierung verwendet.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Ένα κλικ</string>
<string name="gesture_hold_delay">Καθυστέρηση κρατήματος</string>
<string name="gesture_double_delay">Διάστημα διπλού πατήματος</string>
<string name="gesture_scope_game">Ισχύει για το τρέχον παιχνίδι</string>
<string name="gesture_scope_default">Προεπιλεγμένες ρυθμίσεις για όλα τα παιχνίδια</string>
<string name="gesture_reset">Επαναφορά αρχικών ρυθμίσεων χειρονομιών</string>
<string name="gesture_cancel">Ακύρωση</string>
<string name="gesture_action">Επιλογή ενέργειας</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Ροδέλα ποντικιού</string>
<string name="gesture_threshold">Όριο χειρονομιών: %1$d px</string>
<string name="gesture_debug">Εμφάνιση αναγνωρισμένης χειρονομίας</string>
<string name="gesture_editor_subtitle">Χειρισμοί ποντικιού και πληκτρολογίου ανά χειρονομία</string>
<string name="gesture_tab_one">Ένα δάχτυλο</string>
<string name="gesture_tab_two">Δύο δάχτυλα</string>
<string name="gesture_tab_three">Τρία δάχτυλα</string>
<string name="gesture_tab_options">Επιλογές</string>
<string name="gesture_one_hint">Επιλέξτε την ενέργεια για πάτημα, σύρσιμο ή κράτημα.</string>
<string name="gesture_two_hint">Ρυθμίστε τη μετατόπιση της κάμερας, τη μεγέθυνση και τα δευτερεύοντα κλικ.</string>
<string name="gesture_three_hint">Κρατήστε επιπλέον συντομεύσεις κοντά σας.</string>
<string name="gesture_options_hint">Ρυθμίστε την κίνηση, την αναγνώριση και την οπτική ανάδραση.</string>
<string name="gesture_defaults">Προεπιλογές</string>
<string name="gesture_game">Αυτό το παιχνίδι</string>
<string name="gesture_use_defaults">Χρήση προεπιλογών</string>
<string name="gesture_inheriting">Χρησιμοποιούνται οι προεπιλογές. Η επεξεργασία δημιουργεί ρυθμίσεις για αυτό το παιχνίδι.</string>
<string name="gesture_save_changes">Αποθήκευση αλλαγών</string>
<string name="gesture_close">Κλείσιμο</string>
<string name="gesture_action_label">ΕΝΕΡΓΕΙΑ</string>
<string name="gesture_action_for">Για %1$s</string>
<string name="gesture_search_actions">Αναζήτηση ενεργειών ποντικιού ή πλήκτρων</string>
<string name="gesture_clear_search">Εκκαθάριση αναζήτησης</string>
<string name="gesture_all_actions">Όλα</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Αριθμητικό πληκτρολόγιο</string>
<string name="gesture_group_symbols">Σύμβολα</string>
<string name="gesture_movement">Κίνηση ποντικιού</string>
<string name="gesture_movement_hint">Το άμεσο σύρσιμο ακολουθεί τη θέση αφής. Το σχετικό σύρσιμο ακολουθεί την κίνηση του δαχτύλου, χρήσιμο όταν το παιχνίδι επαναφέρει το ποντίκι στο κέντρο.</string>
<string name="gesture_middle_relative_hint">Η μετατόπιση με το μεσαίο κουμπί ακολουθεί πάντα την κίνηση του δαχτύλου για να αποφεύγονται άλματα του δείκτη.</string>
<string name="gesture_direct">Απευθείας</string>
<string name="gesture_relative">Σχετική</string>
<string name="gesture_recognition">Αναγνώριση χειρονομιών</string>
<string name="gesture_threshold_hint">Κινηθείτε κατά αυτή την απόσταση προτού μια χειρονομία με δύο ή τρία δάχτυλα γίνει μετατόπιση ή μεγέθυνση.</string>
<string name="gesture_feedback">Οπτική ανάδραση</string>
<string name="gesture_mouse_behavior">Συμπεριφορά κουμπιού ποντικιού</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -504,7 +504,9 @@
<string name="comp_delete_original_title">Διαγραφή αυτού του πρωτοτύπου;</string>
<string name="comp_delete_original_body">Αυτό το πρωτότυπο %1$s είναι από προηγούμενο build του %2$s. Το πρωτότυπο του τρέχοντος build διατηρείται πάντα.</string>
<string name="comp_nightlies_count">Στα Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Ανανεώστε για να εμφανιστούν τα πακέτα στα Nightlies.</string>
<string name="comp_channel_stable">Σταθερή</string>
<string name="comp_channel_nightly">Νυχτερινή</string>
<string name="comp_refresh_to_list">Ανανεώστε για να εμφανιστούν τα πακέτα στα Nightlies και στο DroidDeck.</string>
<string name="comp_nothing_new">Τίποτα νέο από τον τελευταίο έλεγχο.</string>
<string name="comp_import_wcp">Εισαγωγή .wcp</string>
<string name="comp_restore_original">Επαναφορά του πρωτοτύπου αυτού του Proton</string>
@@ -582,6 +584,16 @@
<string name="drawer_prev_page">Προηγούμενη σελίδα</string>
<string name="drawer_next_page">Επόμενη σελίδα</string>
<string name="drawer_hud">HUD απόδοσης</string>
<string name="drawer_hud_fps">Ρυθμός καρέ</string>
<string name="drawer_hud_battery">Θερμοκρασία μπαταρίας</string>
<string name="drawer_hud_graph">Γράφημα απόδοσης</string>
<string name="drawer_hud_color">Χρώμα</string>
<string name="drawer_hud_color_mint">Μέντα</string>
<string name="drawer_hud_color_white">Λευκό</string>
<string name="drawer_hud_color_sky">Γαλάζιο</string>
<string name="drawer_hud_color_amber">Κεχριμπαρί</string>
<string name="drawer_hud_color_violet">Βιολετί</string>
<string name="drawer_hud_opacity">Διαφάνεια</string>
<string name="drawer_scaling">Λειτουργία κλιμάκωσης</string>
<string name="drawer_scaling_sharpness">Οξύτητα κλιμάκωσης</string>
<string name="drawer_effects">Εφέ οθόνης</string>
@@ -1770,7 +1782,8 @@
<string name="cmgr_original_kept">Το αρχικό της εγκατεστημένης έκδοσης διατηρείται: είναι ο δρόμος της επιστροφής.</string>
<string name="cmgr_not_stored">Δεν είναι αποθηκευμένο</string>
<string name="cmgr_deleted_original">Διαγράφηκε το αρχικό %1$s του %2$s.</string>
<string name="cmgr_nightlies_only">Οι λήψεις προέρχονται μόνο από τις κυκλοφορίες Nightlies</string>
<string name="cmgr_nightlies_only">Οι λήψεις προέρχονται μόνο από τις κυκλοφορίες Nightlies και DroidDeck</string>
<string name="cmgr_nightly_replaced">Η λήψη απέτυχε: αυτή η νυχτερινή έκδοση ίσως αντικαταστάθηκε από νεότερη. Ανανεώστε τη λίστα και δοκιμάστε ξανά.</string>
<string name="cmgr_list_predates_checksums">Αυτή η λίστα πακέτων προηγείται των αθροισμάτων ελέγχου - ανανεώστε την και δοκιμάστε ξανά</string>
<string name="cmgr_checksum_mismatch">Αναντιστοιχία αθροίσματος ελέγχου</string>
@@ -2026,6 +2039,9 @@
<string name="cloud_last_sync">Τελευταίος συγχρονισμός %1$s</string>
<string name="cloud_never">Δεν έχει συγχρονιστεί ακόμα</string>
<string name="cloud_done">%1$d αρχεία</string>
<string name="cloud_up_to_date">Ήδη ενημερωμένο</string>
<string name="cloud_signed_out">Συνδεθείτε στο κατάστημα για συγχρονισμό αποθηκεύσεων</string>
<string name="cloud_not_synced">Οι αποθηκεύσεις δεν συγχρονίστηκαν</string>
<string name="stores_eyebrow_installed">εγκατεστημένο</string>
<string name="stores_eyebrow_library">στη βιβλιοθήκη σας</string>
<string name="stores_eyebrow_store">κατάστημα</string>
@@ -2329,7 +2345,7 @@
<string name="touch_done">Τέλος</string>
<string name="touch_save_failed">Δεν ήταν δυνατή η αποθήκευση της διάταξης αφής</string>
<string name="touch_saved">Η διάταξη αφής αποθηκεύτηκε στο Steam</string>
<string name="touch_app_id">Εφαρμογή %1$d</string>
<string name="touch_app_id">Εφαρμογή %1$s</string>
<string name="touch_label_hint">Ετικέτα (προαιρετικό)</string>
<string name="touch_icons_missing">Τα εικονίδια του Steam δεν βρέθηκαν</string>
<plurals name="touch_icons_found">
@@ -2420,6 +2436,15 @@
<string name="glasses_vr_fov">Οπτικό πεδίο SteamVR</string>
<string name="glasses_vr_fov_hint">Χαμηλότερο: το SteamVR έρχεται πιο κοντά και γεμίζει τα γυαλιά· υψηλότερο: βλέπετε περισσότερα γύρω σας.</string>
<string name="glasses_playing">Παίζετε στα %1$s</string>
<string name="glasses_phone_recenter">Επανακεντράρισμα</string>
<string name="glasses_phone_steamvr_menu">Μενού SteamVR</string>
<string name="glasses_phone_switch_sticks">Μοχλοί: χέρια ⇄ παιχνίδι</string>
<string name="glasses_phone_controllers">Χειριστήρια: %1$s</string>
<string name="glasses_phone_keyboard">Πληκτρολόγιο</string>
<string name="glasses_phone_session_menu">Μενού συνεδρίας</string>
<string name="glasses_phone_stop_steamvr">Διακοπή SteamVR</string>
<string name="glasses_phone_brightness">Φωτεινότητα %1$d / %2$d</string>
<string name="glasses_phone_battery">Μπαταρία %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Βαθμονόμηση παρακολούθησης</string>
<string name="glasses_calibration_hint">Μειώνει την ολίσθηση και ευθυγραμμίζει την οριζόντια αναφορά.</string>
<string name="glasses_calibration_saved_hint">Σε αυτά τα γυαλιά εφαρμόζεται αποθηκευμένη βαθμονόμηση.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Hacer clic una vez</string>
<string name="gesture_hold_delay">Tiempo de pulsación sostenida</string>
<string name="gesture_double_delay">Intervalo de doble toque</string>
<string name="gesture_scope_game">Se aplica al juego actual</string>
<string name="gesture_scope_default">Ajustes predeterminados para todos los juegos</string>
<string name="gesture_reset">Restablecer los ajustes originales de gestos</string>
<string name="gesture_cancel">Cancelar</string>
<string name="gesture_action">Elegir acción</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Rueda del ratón</string>
<string name="gesture_threshold">Umbral de gestos: %1$d px</string>
<string name="gesture_debug">Mostrar gesto reconocido</string>
<string name="gesture_editor_subtitle">Controles de ratón y teclado organizados por gesto</string>
<string name="gesture_tab_one">Un dedo</string>
<string name="gesture_tab_two">Dos dedos</string>
<string name="gesture_tab_three">Tres dedos</string>
<string name="gesture_tab_options">Opciones</string>
<string name="gesture_one_hint">Elige qué debe hacer un toque, arrastre o pulsación sostenida.</string>
<string name="gesture_two_hint">Configura el movimiento de cámara, el zoom y los clics secundarios.</string>
<string name="gesture_three_hint">Ten más accesos directos al alcance de la mano.</string>
<string name="gesture_options_hint">Ajusta el movimiento, el reconocimiento y la respuesta visual.</string>
<string name="gesture_defaults">Predeterminados</string>
<string name="gesture_game">Este juego</string>
<string name="gesture_use_defaults">Usar valores predeterminados</string>
<string name="gesture_inheriting">Se usan los ajustes predeterminados. Al editarlos, se crean ajustes específicos del juego.</string>
<string name="gesture_save_changes">Guardar cambios</string>
<string name="gesture_close">Cerrar</string>
<string name="gesture_action_label">ACCIÓN</string>
<string name="gesture_action_for">Para %1$s</string>
<string name="gesture_search_actions">Buscar acciones de ratón o teclas del teclado</string>
<string name="gesture_clear_search">Borrar búsqueda</string>
<string name="gesture_all_actions">Todas</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Teclado numérico</string>
<string name="gesture_group_symbols">Símbolos</string>
<string name="gesture_movement">Movimiento del ratón</string>
<string name="gesture_movement_hint">El arrastre directo sigue la posición del toque. El relativo sigue el movimiento del dedo y resulta útil cuando un juego centra el ratón.</string>
<string name="gesture_middle_relative_hint">El desplazamiento con el botón central siempre sigue el movimiento del dedo para evitar saltos del cursor.</string>
<string name="gesture_direct">Directo</string>
<string name="gesture_relative">Relativo</string>
<string name="gesture_recognition">Reconocimiento de gestos</string>
<string name="gesture_threshold_hint">Recorre esta distancia antes de que un gesto con dos o tres dedos se convierta en desplazamiento o zoom.</string>
<string name="gesture_feedback">Respuesta visual</string>
<string name="gesture_mouse_behavior">Comportamiento del botón del ratón</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -503,7 +503,9 @@
<string name="comp_delete_original_title">¿Eliminar este original?</string>
<string name="comp_delete_original_body">Este original de %1$s es de una versión anterior de %2$s. El original de la versión actual siempre se conserva.</string>
<string name="comp_nightlies_count">En las Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Actualiza para listar los paquetes de las Nightlies.</string>
<string name="comp_channel_stable">Estable</string>
<string name="comp_channel_nightly">Nocturna</string>
<string name="comp_refresh_to_list">Actualiza para listar los paquetes de Nightlies y DroidDeck.</string>
<string name="comp_nothing_new">Nada nuevo desde la última comprobación.</string>
<string name="comp_import_wcp">Importar .wcp</string>
<string name="comp_restore_original">Restaurar el original de este Proton</string>
@@ -581,6 +583,16 @@
<string name="drawer_prev_page">Página anterior</string>
<string name="drawer_next_page">Página siguiente</string>
<string name="drawer_hud">HUD de rendimiento</string>
<string name="drawer_hud_fps">Tasa de fotogramas</string>
<string name="drawer_hud_battery">Temperatura de la batería</string>
<string name="drawer_hud_graph">Gráfico de rendimiento</string>
<string name="drawer_hud_color">Color</string>
<string name="drawer_hud_color_mint">Menta</string>
<string name="drawer_hud_color_white">Blanco</string>
<string name="drawer_hud_color_sky">Celeste</string>
<string name="drawer_hud_color_amber">Ámbar</string>
<string name="drawer_hud_color_violet">Violeta</string>
<string name="drawer_hud_opacity">Opacidad</string>
<string name="drawer_scaling">Modo de escalado</string>
<string name="drawer_scaling_sharpness">Nitidez del escalado</string>
<string name="drawer_effects">Efectos de pantalla</string>
@@ -1788,7 +1800,8 @@
<string name="cmgr_original_kept">El original de la versión instalada se conserva: es el camino de vuelta.</string>
<string name="cmgr_not_stored">No guardado</string>
<string name="cmgr_deleted_original">Se eliminó el original de %1$s de %2$s.</string>
<string name="cmgr_nightlies_only">Las descargas solo proceden de las versiones Nightlies</string>
<string name="cmgr_nightlies_only">Las descargas solo proceden de las versiones de Nightlies y DroidDeck</string>
<string name="cmgr_nightly_replaced">Error en la descarga: puede que esta compilación nocturna se haya sustituido por una más reciente. Actualiza la lista y vuelve a intentarlo.</string>
<string name="cmgr_list_predates_checksums">Esta lista de paquetes es anterior a las sumas de verificación - actualízala e inténtalo de nuevo</string>
<string name="cmgr_checksum_mismatch">La suma de verificación no coincide</string>
@@ -2044,6 +2057,9 @@
<string name="cloud_last_sync">Última sincronización %1$s</string>
<string name="cloud_never">Aún sin sincronizar</string>
<string name="cloud_done">%1$d archivos</string>
<string name="cloud_up_to_date">Ya está al día</string>
<string name="cloud_signed_out">Inicia sesión en la tienda para sincronizar las partidas</string>
<string name="cloud_not_synced">No se sincronizaron las partidas</string>
<string name="stores_eyebrow_installed">instalado</string>
<string name="stores_eyebrow_library">en tu biblioteca</string>
<string name="stores_eyebrow_store">tienda</string>
@@ -2346,7 +2362,7 @@
<string name="touch_done">Hecho</string>
<string name="touch_save_failed">No se pudo guardar la disposición táctil</string>
<string name="touch_saved">Disposición táctil guardada en Steam</string>
<string name="touch_app_id">App %1$d</string>
<string name="touch_app_id">App %1$s</string>
<string name="touch_label_hint">Etiqueta (opcional)</string>
<string name="touch_icons_missing">No se encontraron los iconos de Steam</string>
<plurals name="touch_icons_found">
@@ -2428,6 +2444,15 @@
<string name="glasses_vr_fov">Campo de visión de SteamVR</string>
<string name="glasses_vr_fov_hint">Más bajo acerca SteamVR y llena las gafas; más alto muestra más a tu alrededor.</string>
<string name="glasses_playing">Jugando en %1$s</string>
<string name="glasses_phone_recenter">Recentrar</string>
<string name="glasses_phone_steamvr_menu">Menú de SteamVR</string>
<string name="glasses_phone_switch_sticks">Sticks: manos ⇄ juego</string>
<string name="glasses_phone_controllers">Mandos: %1$s</string>
<string name="glasses_phone_keyboard">Teclado</string>
<string name="glasses_phone_session_menu">Menú de sesión</string>
<string name="glasses_phone_stop_steamvr">Detener SteamVR</string>
<string name="glasses_phone_brightness">Brillo %1$d / %2$d</string>
<string name="glasses_phone_battery">Batería %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Calibración del seguimiento</string>
<string name="glasses_calibration_hint">Reduce la deriva y alinea la referencia horizontal.</string>
<string name="glasses_calibration_saved_hint">Estas gafas usan la calibración guardada.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Napsauta kerran</string>
<string name="gesture_hold_delay">Pidon viive</string>
<string name="gesture_double_delay">Kaksoisnapautuksen aikaväli</string>
<string name="gesture_scope_game">Koskee nykyistä peliä</string>
<string name="gesture_scope_default">Kaikkien pelien oletusasetukset</string>
<string name="gesture_reset">Palauta alkuperäiset eleasetukset</string>
<string name="gesture_cancel">Peruuta</string>
<string name="gesture_action">Valitse toiminto</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Hiiren rulla</string>
<string name="gesture_threshold">Elekynnys: %1$d px</string>
<string name="gesture_debug">Näytä tunnistettu ele</string>
<string name="gesture_editor_subtitle">Hiiri- ja näppäimistöohjaus eleittäin</string>
<string name="gesture_tab_one">Yksi sormi</string>
<string name="gesture_tab_two">Kaksi sormea</string>
<string name="gesture_tab_three">Kolme sormea</string>
<string name="gesture_tab_options">Asetukset</string>
<string name="gesture_one_hint">Valitse napautuksen, vedon tai pidon toiminto.</string>
<string name="gesture_two_hint">Määritä kameran panorointi, zoomaus ja toissijaiset napsautukset.</string>
<string name="gesture_three_hint">Pidä lisäpikakomennot ulottuvillasi.</string>
<string name="gesture_options_hint">Säädä liikettä, tunnistusta ja visuaalista palautetta.</string>
<string name="gesture_defaults">Oletukset</string>
<string name="gesture_game">Tämä peli</string>
<string name="gesture_use_defaults">Käytä oletuksia</string>
<string name="gesture_inheriting">Oletusasetukset ovat käytössä. Muokkaaminen luo pelikohtaiset asetukset.</string>
<string name="gesture_save_changes">Tallenna muutokset</string>
<string name="gesture_close">Sulje</string>
<string name="gesture_action_label">TOIMINTO</string>
<string name="gesture_action_for">Kohteelle %1$s</string>
<string name="gesture_search_actions">Etsi hiiritoimintoja tai näppäimiä</string>
<string name="gesture_clear_search">Tyhjennä haku</string>
<string name="gesture_all_actions">Kaikki</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Numeronäppäimistö</string>
<string name="gesture_group_symbols">Symbolit</string>
<string name="gesture_movement">Hiiren liike</string>
<string name="gesture_movement_hint">Suora veto seuraa kosketuskohtaa. Suhteellinen veto seuraa sormen liikettä ja sopii peleihin, jotka keskittävät hiiren.</string>
<string name="gesture_middle_relative_hint">Panorointi keskipainikkeella seuraa aina sormen liikettä, jotta osoitin ei hypi.</string>
<string name="gesture_direct">Suora</string>
<string name="gesture_relative">Suhteellinen</string>
<string name="gesture_recognition">Eleiden tunnistus</string>
<string name="gesture_threshold_hint">Liikuta sormia tämän matkan verran, ennen kuin kahden tai kolmen sormen ele muuttuu panoroinniksi tai zoomaukseksi.</string>
<string name="gesture_feedback">Visuaalinen palaute</string>
<string name="gesture_mouse_behavior">Hiiripainikkeen toiminta</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -504,7 +504,9 @@
<string name="comp_delete_original_title">Poistetaanko tämä alkuperäinen?</string>
<string name="comp_delete_original_body">Tämä %1$s:n alkuperäinen on aiemmasta %2$s-versiosta. Nykyisen version alkuperäinen säilytetään aina.</string>
<string name="comp_nightlies_count">Nightliesissä · %1$d</string>
<string name="comp_refresh_to_list">Päivitä nähdäksesi Nightliesin paketit.</string>
<string name="comp_channel_stable">Vakaa</string>
<string name="comp_channel_nightly">Yöversio</string>
<string name="comp_refresh_to_list">Päivitä nähdäksesi Nightliesin ja DroidDeckin paketit.</string>
<string name="comp_nothing_new">Ei mitään uutta viimeisimmän tarkistuksen jälkeen.</string>
<string name="comp_import_wcp">Tuo .wcp</string>
<string name="comp_restore_original">Palauta tämän Protonin alkuperäinen</string>
@@ -582,6 +584,16 @@
<string name="drawer_prev_page">Edellinen sivu</string>
<string name="drawer_next_page">Seuraava sivu</string>
<string name="drawer_hud">Suorituskyky-HUD</string>
<string name="drawer_hud_fps">Kuvataajuus</string>
<string name="drawer_hud_battery">Akun lämpötila</string>
<string name="drawer_hud_graph">Suorituskykykäyrä</string>
<string name="drawer_hud_color">Väri</string>
<string name="drawer_hud_color_mint">Minttu</string>
<string name="drawer_hud_color_white">Valkoinen</string>
<string name="drawer_hud_color_sky">Taivaansininen</string>
<string name="drawer_hud_color_amber">Meripihka</string>
<string name="drawer_hud_color_violet">Violetti</string>
<string name="drawer_hud_opacity">Peittävyys</string>
<string name="drawer_scaling">Skaalaustila</string>
<string name="drawer_scaling_sharpness">Skaalauksen terävyys</string>
<string name="drawer_effects">Näyttötehosteet</string>
@@ -1770,7 +1782,8 @@
<string name="cmgr_original_kept">Asennetun version alkuperäinen säilytetään: se on tie takaisin.</string>
<string name="cmgr_not_stored">Ei tallennettu</string>
<string name="cmgr_deleted_original">Poistettu %2$s:n %1$s-alkuperäinen.</string>
<string name="cmgr_nightlies_only">Lataukset tulevat vain Nightlies-julkaisuista</string>
<string name="cmgr_nightlies_only">Lataukset tulevat vain Nightlies- ja DroidDeck-julkaisuista</string>
<string name="cmgr_nightly_replaced">Lataus epäonnistui: tämä yöversio on ehkä korvattu uudemmalla. Päivitä luettelo ja yritä uudelleen.</string>
<string name="cmgr_list_predates_checksums">Tämä pakettiluettelo on tarkistussummia vanhempi - päivitä se ja yritä uudelleen</string>
<string name="cmgr_checksum_mismatch">Tarkistussumma ei täsmää</string>
@@ -2026,6 +2039,9 @@
<string name="cloud_last_sync">Viimeisin synkronointi %1$s</string>
<string name="cloud_never">Ei synkronoitu vielä</string>
<string name="cloud_done">%1$d tiedostoa</string>
<string name="cloud_up_to_date">Jo ajan tasalla</string>
<string name="cloud_signed_out">Kirjaudu kauppaan synkronoidaksesi tallennukset</string>
<string name="cloud_not_synced">Tallennuksia ei synkronoitu</string>
<string name="stores_eyebrow_installed">asennettu</string>
<string name="stores_eyebrow_library">kirjastossasi</string>
<string name="stores_eyebrow_store">kauppa</string>
@@ -2329,7 +2345,7 @@
<string name="touch_done">Valmis</string>
<string name="touch_save_failed">Kosketusasettelua ei voitu tallentaa</string>
<string name="touch_saved">Kosketusasettelu tallennettu Steamiin</string>
<string name="touch_app_id">Sovellus %1$d</string>
<string name="touch_app_id">Sovellus %1$s</string>
<string name="touch_label_hint">Nimike (valinnainen)</string>
<string name="touch_icons_missing">Steamin kuvakkeita ei löytynyt</string>
<plurals name="touch_icons_found">
@@ -2420,6 +2436,15 @@
<string name="glasses_vr_fov">SteamVR:n näkökenttä</string>
<string name="glasses_vr_fov_hint">Pienempi tuo SteamVR:n lähemmäs ja täyttää lasit; suurempi näyttää enemmän ympäriltäsi.</string>
<string name="glasses_playing">Pelataan laitteella %1$s</string>
<string name="glasses_phone_recenter">Keskitä uudelleen</string>
<string name="glasses_phone_steamvr_menu">SteamVR-valikko</string>
<string name="glasses_phone_switch_sticks">Sauvat: kädet ⇄ peli</string>
<string name="glasses_phone_controllers">Ohjaimet: %1$s</string>
<string name="glasses_phone_keyboard">Näppäimistö</string>
<string name="glasses_phone_session_menu">Istuntovalikko</string>
<string name="glasses_phone_stop_steamvr">Pysäytä SteamVR</string>
<string name="glasses_phone_brightness">Kirkkaus %1$d / %2$d</string>
<string name="glasses_phone_battery">Akku %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Seurannan kalibrointi</string>
<string name="glasses_calibration_hint">Vähentää ryömintää ja kohdistaa vaakatason.</string>
<string name="glasses_calibration_saved_hint">Tallennettu kalibrointi on käytössä näissä laseissa.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Cliquer une fois</string>
<string name="gesture_hold_delay">Délai de maintien</string>
<string name="gesture_double_delay">Intervalle du double appui</string>
<string name="gesture_scope_game">S\'applique au jeu actuel</string>
<string name="gesture_scope_default">Paramètres par défaut pour tous les jeux</string>
<string name="gesture_reset">Rétablir les paramètres des gestes d\'origine</string>
<string name="gesture_cancel">Annuler</string>
<string name="gesture_action">Choisir une action</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Molette de la souris</string>
<string name="gesture_threshold">Seuil des gestes : %1$d px</string>
<string name="gesture_debug">Afficher le geste reconnu</string>
<string name="gesture_editor_subtitle">Commandes de souris et de clavier organisées par geste</string>
<string name="gesture_tab_one">Un doigt</string>
<string name="gesture_tab_two">Deux doigts</string>
<string name="gesture_tab_three">Trois doigts</string>
<string name="gesture_tab_options">Options</string>
<string name="gesture_one_hint">Choisissez l\'action d\'un appui, d\'un glissement ou d\'un maintien.</string>
<string name="gesture_two_hint">Configurez les déplacements de caméra, le zoom et les clics secondaires.</string>
<string name="gesture_three_hint">Gardez des raccourcis supplémentaires à portée de main.</string>
<string name="gesture_options_hint">Ajustez les mouvements, la reconnaissance et le retour visuel.</string>
<string name="gesture_defaults">Valeurs par défaut</string>
<string name="gesture_game">Ce jeu</string>
<string name="gesture_use_defaults">Utiliser les valeurs par défaut</string>
<string name="gesture_inheriting">Paramètres par défaut utilisés. Une modification crée des paramètres propres au jeu.</string>
<string name="gesture_save_changes">Enregistrer les modifications</string>
<string name="gesture_close">Fermer</string>
<string name="gesture_action_label">ACTION</string>
<string name="gesture_action_for">Pour %1$s</string>
<string name="gesture_search_actions">Rechercher des actions de souris ou des touches du clavier</string>
<string name="gesture_clear_search">Effacer la recherche</string>
<string name="gesture_all_actions">Tout</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Pavé numérique</string>
<string name="gesture_group_symbols">Symboles</string>
<string name="gesture_movement">Mouvement de la souris</string>
<string name="gesture_movement_hint">Le glissement direct suit la position du toucher. Le glissement relatif suit le mouvement du doigt, utile lorsqu\'un jeu recentre la souris.</string>
<string name="gesture_middle_relative_hint">Le déplacement avec le bouton du milieu suit toujours le mouvement du doigt pour éviter les sauts du curseur.</string>
<string name="gesture_direct">Direct</string>
<string name="gesture_relative">Relatif</string>
<string name="gesture_recognition">Reconnaissance des gestes</string>
<string name="gesture_threshold_hint">Parcourez cette distance avant qu\'un geste à deux ou trois doigts soit reconnu comme un déplacement ou un zoom.</string>
<string name="gesture_feedback">Retour visuel</string>
<string name="gesture_mouse_behavior">Comportement du bouton de souris</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -503,7 +503,9 @@
<string name="comp_delete_original_title">Supprimer cette version originale ?</string>
<string name="comp_delete_original_body">Cette version originale de %1$s provient d\'une version antérieure de %2$s. La version originale de la version actuelle sera toujours conservée.</string>
<string name="comp_nightlies_count">Dans Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Actualiser pour lister les paquets dans Nightlies.</string>
<string name="comp_channel_stable">Stable</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Actualiser pour lister les paquets dans Nightlies et DroidDeck.</string>
<string name="comp_nothing_new">Aucun nouvel élément depuis la dernière vérification.</string>
<string name="comp_import_wcp">Importer .wcp</string>
<string name="comp_restore_original">Restaurer les fichiers originaux de ce Proton</string>
@@ -581,6 +583,16 @@
<string name="drawer_prev_page">Page précédente</string>
<string name="drawer_next_page">Page suivante</string>
<string name="drawer_hud">HUD de performance</string>
<string name="drawer_hud_fps">Fréquence d\'images</string>
<string name="drawer_hud_battery">Température de la batterie</string>
<string name="drawer_hud_graph">Graphique de performance</string>
<string name="drawer_hud_color">Couleur</string>
<string name="drawer_hud_color_mint">Menthe</string>
<string name="drawer_hud_color_white">Blanc</string>
<string name="drawer_hud_color_sky">Ciel</string>
<string name="drawer_hud_color_amber">Ambre</string>
<string name="drawer_hud_color_violet">Violet</string>
<string name="drawer_hud_opacity">Opacité</string>
<string name="drawer_scaling">Mode de mise à l\'échelle</string>
<string name="drawer_scaling_sharpness">Netteté de la mise à l\'échelle</string>
<string name="drawer_effects">Effets d\'écran</string>
@@ -1788,7 +1800,8 @@
<string name="cmgr_original_kept">L\'original de la version installée est conservé : c\'est le moyen d\'y revenir.</string>
<string name="cmgr_not_stored">Non enregistré</string>
<string name="cmgr_deleted_original">Original %1$s de %2$s supprimé.</string>
<string name="cmgr_nightlies_only">Les téléchargements proviennent uniquement des versions Nightlies</string>
<string name="cmgr_nightlies_only">Les téléchargements proviennent uniquement des versions Nightlies et DroidDeck</string>
<string name="cmgr_nightly_replaced">Échec du téléchargement : cette version nightly a peut-être été remplacée par une plus récente. Actualisez la liste et réessayez.</string>
<string name="cmgr_list_predates_checksums">Cette liste de paquets est antérieure aux sommes de contrôle - actualisez-la et réessayez</string>
<string name="cmgr_checksum_mismatch">Somme de contrôle incorrecte</string>
@@ -2044,6 +2057,9 @@
<string name="cloud_last_sync">Dernière synchro : %1$s</string>
<string name="cloud_never">Pas encore synchronisé</string>
<string name="cloud_done">%1$d fichiers</string>
<string name="cloud_up_to_date">Déjà à jour</string>
<string name="cloud_signed_out">Connectez-vous à la boutique pour synchroniser les sauvegardes</string>
<string name="cloud_not_synced">Les sauvegardes n’ont pas été synchronisées</string>
<string name="stores_eyebrow_installed">installé</string>
<string name="stores_eyebrow_library">dans votre bibliothèque</string>
<string name="stores_eyebrow_store">boutique</string>
@@ -2346,7 +2362,7 @@
<string name="touch_done">Terminé</string>
<string name="touch_save_failed">Impossible d\'enregistrer la disposition tactile</string>
<string name="touch_saved">Disposition tactile enregistrée sur Steam</string>
<string name="touch_app_id">Appli %1$d</string>
<string name="touch_app_id">Appli %1$s</string>
<string name="touch_label_hint">Libellé (facultatif)</string>
<string name="touch_icons_missing">Les icônes de Steam n\'ont pas été trouvées</string>
<plurals name="touch_icons_found">
@@ -2439,6 +2455,15 @@
<string name="glasses_vr_fov">Champ de vision SteamVR</string>
<string name="glasses_vr_fov_hint">Plus bas rapproche SteamVR et remplit les lunettes ; plus haut montre davantage autour de vous.</string>
<string name="glasses_playing">En jeu sur %1$s</string>
<string name="glasses_phone_recenter">Recentrer</string>
<string name="glasses_phone_steamvr_menu">Menu SteamVR</string>
<string name="glasses_phone_switch_sticks">Sticks : mains ⇄ jeu</string>
<string name="glasses_phone_controllers">Manettes : %1$s</string>
<string name="glasses_phone_keyboard">Clavier</string>
<string name="glasses_phone_session_menu">Menu de session</string>
<string name="glasses_phone_stop_steamvr">Arrêter SteamVR</string>
<string name="glasses_phone_brightness">Luminosité %1$d / %2$d</string>
<string name="glasses_phone_battery">Batterie %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Calibrage du suivi</string>
<string name="glasses_calibration_hint">Réduit la dérive et aligne la référence horizontale.</string>
<string name="glasses_calibration_saved_hint">Le calibrage enregistré est appliqué à ces lunettes.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">एक बार क्लिक करें</string>
<string name="gesture_hold_delay">दबाए रखने का विलंब</string>
<string name="gesture_double_delay">दो टैप के बीच का अंतराल</string>
<string name="gesture_scope_game">मौजूदा गेम पर लागू होता है</string>
<string name="gesture_scope_default">सभी गेम की डिफ़ॉल्ट सेटिंग</string>
<string name="gesture_reset">जेस्चर की मूल सेटिंग वापस लाएँ</string>
<string name="gesture_cancel">रद्द करें</string>
<string name="gesture_action">कार्रवाई चुनें</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">माउस व्हील</string>
<string name="gesture_threshold">जेस्चर की सीमा: %1$d पिक्सेल</string>
<string name="gesture_debug">पहचाना गया जेस्चर दिखाएँ</string>
<string name="gesture_editor_subtitle">जेस्चर के अनुसार माउस और कीबोर्ड कंट्रोल</string>
<string name="gesture_tab_one">एक उँगली</string>
<string name="gesture_tab_two">दो उँगलियाँ</string>
<string name="gesture_tab_three">तीन उँगलियाँ</string>
<string name="gesture_tab_options">विकल्प</string>
<string name="gesture_one_hint">चुनें कि टैप करने, खींचने या दबाए रखने पर क्या हो।</string>
<string name="gesture_two_hint">कैमरा खिसकाना, ज़ूम और दूसरे क्लिक सेट करें।</string>
<string name="gesture_three_hint">अतिरिक्त शॉर्टकट आसानी से इस्तेमाल करें।</string>
<string name="gesture_options_hint">गति, पहचान और दृश्य प्रतिक्रिया में बदलाव करें।</string>
<string name="gesture_defaults">डिफ़ॉल्ट</string>
<string name="gesture_game">यह गेम</string>
<string name="gesture_use_defaults">डिफ़ॉल्ट इस्तेमाल करें</string>
<string name="gesture_inheriting">डिफ़ॉल्ट सेटिंग इस्तेमाल हो रही हैं। बदलाव करने पर इस गेम की अलग सेटिंग बनेंगी।</string>
<string name="gesture_save_changes">बदलाव सेव करें</string>
<string name="gesture_close">बंद करें</string>
<string name="gesture_action_label">कार्रवाई</string>
<string name="gesture_action_for">%1$s के लिए</string>
<string name="gesture_search_actions">माउस की कार्रवाइयाँ या कीबोर्ड की कुंजियाँ खोजें</string>
<string name="gesture_clear_search">खोज मिटाएँ</string>
<string name="gesture_all_actions">सभी</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">नंबर पैड</string>
<string name="gesture_group_symbols">चिह्न</string>
<string name="gesture_movement">माउस की गति</string>
<string name="gesture_movement_hint">सीधे खींचना छुई गई जगह के अनुसार चलता है। सापेक्ष खींचना उँगली की गति के अनुसार चलता है और गेम के माउस को बीच में लाने पर उपयोगी है।</string>
<string name="gesture_middle_relative_hint">माउस के बीच वाले बटन से दृश्य खिसकाना हमेशा उँगली की गति के अनुसार चलता है, ताकि कर्सर न उछले।</string>
<string name="gesture_direct">डायरेक्ट</string>
<string name="gesture_relative">सापेक्ष</string>
<string name="gesture_recognition">जेस्चर की पहचान</string>
<string name="gesture_threshold_hint">दो या तीन उँगलियों का जेस्चर दृश्य खिसकाने या ज़ूम में बदलने से पहले इतनी दूरी तय करें।</string>
<string name="gesture_feedback">दृश्य प्रतिक्रिया</string>
<string name="gesture_mouse_behavior">माउस बटन का व्यवहार</string>
<string name="gesture_ms">%1$d मिलीसेकंड</string>
+28 -3
View File
@@ -504,7 +504,9 @@
<string name="comp_delete_original_title">यह ओरिजिनल हटाएं?</string>
<string name="comp_delete_original_body">यह %1$s ओरिजिनल %2$s के पहले वाले बिल्ड से है। मौजूदा बिल्ड का ओरिजिनल हमेशा रखा जाता है।</string>
<string name="comp_nightlies_count">Nightlies पर · %1$d</string>
<string name="comp_refresh_to_list">Nightlies के पैकेज सूचीबद्ध करने के लिए रीफ़्रेश करें।</string>
<string name="comp_channel_stable">स्थिर</string>
<string name="comp_channel_nightly">नाइटली</string>
<string name="comp_refresh_to_list">Nightlies और DroidDeck के पैकेज सूचीबद्ध करने के लिए रीफ़्रेश करें।</string>
<string name="comp_nothing_new">पिछली जांच के बाद कुछ नया नहीं है।</string>
<string name="comp_import_wcp">.wcp इंपोर्ट करें</string>
<string name="comp_restore_original">इस Proton का ओरिजिनल वापस लाएं</string>
@@ -582,6 +584,16 @@
<string name="drawer_prev_page">पिछला पेज</string>
<string name="drawer_next_page">अगला पेज</string>
<string name="drawer_hud">परफ़ॉर्मेंस HUD</string>
<string name="drawer_hud_fps">फ़्रेम दर</string>
<string name="drawer_hud_battery">बैटरी तापमान</string>
<string name="drawer_hud_graph">परफ़ॉर्मेंस ग्राफ़</string>
<string name="drawer_hud_color">रंग</string>
<string name="drawer_hud_color_mint">मिंट</string>
<string name="drawer_hud_color_white">सफ़ेद</string>
<string name="drawer_hud_color_sky">स्काई</string>
<string name="drawer_hud_color_amber">एम्बर</string>
<string name="drawer_hud_color_violet">वायलेट</string>
<string name="drawer_hud_opacity">ओपैसिटी</string>
<string name="drawer_scaling">स्केलिंग मोड</string>
<string name="drawer_scaling_sharpness">स्केलिंग शार्पनेस</string>
<string name="drawer_effects">स्क्रीन इफ़ेक्ट</string>
@@ -1770,7 +1782,8 @@
<string name="cmgr_original_kept">इंस्टॉल किए बिल्ड का ओरिजिनल रखा गया है: यह वापस जाने का रास्ता है।</string>
<string name="cmgr_not_stored">सेव नहीं है</string>
<string name="cmgr_deleted_original">%2$s का %1$s ओरिजिनल हटाया गया।</string>
<string name="cmgr_nightlies_only">डाउनलोड सिर्फ़ Nightlies रिलीज़ से आते हैं</string>
<string name="cmgr_nightlies_only">डाउनलोड सिर्फ़ Nightlies और DroidDeck रिलीज़ से आते हैं</string>
<string name="cmgr_nightly_replaced">डाउनलोड विफल: हो सकता है यह नाइटली बिल्ड किसी नए बिल्ड से बदल दिया गया हो। सूची रीफ़्रेश करें और फिर से कोशिश करें।</string>
<string name="cmgr_list_predates_checksums">यह पैकेज लिस्ट चेकसम से पुरानी है - इसे रीफ़्रेश करें और फिर कोशिश करें</string>
<string name="cmgr_checksum_mismatch">चेकसम मेल नहीं खाया</string>
@@ -2026,6 +2039,9 @@
<string name="cloud_last_sync">आख़िरी सिंक %1$s</string>
<string name="cloud_never">अभी सिंक नहीं हुआ</string>
<string name="cloud_done">%1$d फ़ाइलें</string>
<string name="cloud_up_to_date">पहले से अप टू डेट</string>
<string name="cloud_signed_out">सेव सिंक करने के लिए स्टोर में साइन इन करें</string>
<string name="cloud_not_synced">सेव सिंक नहीं हुए</string>
<string name="stores_eyebrow_installed">इंस्टॉल है</string>
<string name="stores_eyebrow_library">आपकी लाइब्रेरी में</string>
<string name="stores_eyebrow_store">स्टोर</string>
@@ -2329,7 +2345,7 @@
<string name="touch_done">हो गया</string>
<string name="touch_save_failed">टच लेआउट सेव नहीं हो सका</string>
<string name="touch_saved">टच लेआउट Steam में सेव हो गया</string>
<string name="touch_app_id">ऐप %1$d</string>
<string name="touch_app_id">ऐप %1$s</string>
<string name="touch_label_hint">लेबल (वैकल्पिक)</string>
<string name="touch_icons_missing">Steam के आइकॉन नहीं मिले</string>
<plurals name="touch_icons_found">
@@ -2420,6 +2436,15 @@
<string name="glasses_vr_fov">SteamVR फ़ील्ड ऑफ़ व्यू</string>
<string name="glasses_vr_fov_hint">कम करने पर SteamVR पास आता है और चश्मा भर देता है; ज़्यादा करने पर आपके आस-पास ज़्यादा दिखता है।</string>
<string name="glasses_playing">%1$s पर खेल रहे हैं</string>
<string name="glasses_phone_recenter">फिर से केंद्रित करें</string>
<string name="glasses_phone_steamvr_menu">SteamVR मेनू</string>
<string name="glasses_phone_switch_sticks">स्टिक: हाथ ⇄ गेम</string>
<string name="glasses_phone_controllers">कंट्रोलर: %1$s</string>
<string name="glasses_phone_keyboard">कीबोर्ड</string>
<string name="glasses_phone_session_menu">सत्र मेनू</string>
<string name="glasses_phone_stop_steamvr">SteamVR रोकें</string>
<string name="glasses_phone_brightness">चमक %1$d / %2$d</string>
<string name="glasses_phone_battery">बैटरी %1$d%% · %2$d °C</string>
<string name="glasses_calibration">ट्रैकिंग कैलिब्रेशन</string>
<string name="glasses_calibration_hint">ड्रिफ़्ट कम करता है और क्षैतिज संदर्भ को सीध में लाता है।</string>
<string name="glasses_calibration_saved_hint">इस चश्मे पर सेव किया गया कैलिब्रेशन लागू है।</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Egyszeri kattintás</string>
<string name="gesture_hold_delay">Nyomva tartás késleltetése</string>
<string name="gesture_double_delay">Dupla koppintás időköze</string>
<string name="gesture_scope_game">Az aktuális játékra érvényes</string>
<string name="gesture_scope_default">Alapbeállítások minden játékhoz</string>
<string name="gesture_reset">Eredeti gesztusbeállítások visszaállítása</string>
<string name="gesture_cancel">Mégse</string>
<string name="gesture_action">Művelet kiválasztása</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Egérgörgő</string>
<string name="gesture_threshold">Gesztusküszöb: %1$d px</string>
<string name="gesture_debug">Felismert gesztus megjelenítése</string>
<string name="gesture_editor_subtitle">Egér- és billentyűzetvezérlés gesztusok szerint</string>
<string name="gesture_tab_one">Egy ujj</string>
<string name="gesture_tab_two">Két ujj</string>
<string name="gesture_tab_three">Három ujj</string>
<string name="gesture_tab_options">Beállítások</string>
<string name="gesture_one_hint">Válaszd ki a koppintás, húzás vagy nyomva tartás műveletét.</string>
<string name="gesture_two_hint">Állítsd be a kamera pásztázását, a nagyítást és a másodlagos kattintásokat.</string>
<string name="gesture_three_hint">Tarts további gyorsparancsokat kéznél.</string>
<string name="gesture_options_hint">Finomhangold a mozgást, a felismerést és a vizuális visszajelzést.</string>
<string name="gesture_defaults">Alapértelmezések</string>
<string name="gesture_game">Ez a játék</string>
<string name="gesture_use_defaults">Alapbeállítások használata</string>
<string name="gesture_inheriting">Az alapbeállítások érvényesek. A szerkesztés játékhoz tartozó beállításokat hoz létre.</string>
<string name="gesture_save_changes">Módosítások mentése</string>
<string name="gesture_close">Bezárás</string>
<string name="gesture_action_label">MŰVELET</string>
<string name="gesture_action_for">Ehhez: %1$s</string>
<string name="gesture_search_actions">Egérműveletek vagy billentyűk keresése</string>
<string name="gesture_clear_search">Keresés törlése</string>
<string name="gesture_all_actions">Összes</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Numerikus billentyűzet</string>
<string name="gesture_group_symbols">Szimbólumok</string>
<string name="gesture_movement">Egérmozgás</string>
<string name="gesture_movement_hint">A közvetlen húzás az érintési helyet követi. A relatív húzás az ujj mozgását követi, ami hasznos, ha a játék középre állítja az egeret.</string>
<string name="gesture_middle_relative_hint">A középső egérgombos pásztázás mindig az ujj mozgását követi, hogy a kurzor ne ugorjon el.</string>
<string name="gesture_direct">Közvetlen</string>
<string name="gesture_relative">Relatív</string>
<string name="gesture_recognition">Gesztusfelismerés</string>
<string name="gesture_threshold_hint">Ennyit kell elmozdítani az ujjakat, mielőtt a két- vagy háromujjas gesztus pásztázássá vagy nagyítássá válik.</string>
<string name="gesture_feedback">Vizuális visszajelzés</string>
<string name="gesture_mouse_behavior">Egérgomb működése</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -504,7 +504,9 @@
<string name="comp_delete_original_title">Törli ezt az eredetit?</string>
<string name="comp_delete_original_body">Ez a %1$s eredeti a %2$s egy korábbi buildjéből származik. Az aktuális build eredetije mindig megmarad.</string>
<string name="comp_nightlies_count">A Nightliesen · %1$d</string>
<string name="comp_refresh_to_list">Frissítsen a Nightliesen lévő csomagok listázásához.</string>
<string name="comp_channel_stable">Stabil</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Frissítsen a Nightlies és a DroidDeck csomagjainak listázásához.</string>
<string name="comp_nothing_new">Nincs semmi új az utolsó ellenőrzés óta.</string>
<string name="comp_import_wcp">.wcp importálása</string>
<string name="comp_restore_original">Ennek a Protonnak az eredetijének visszaállítása</string>
@@ -582,6 +584,16 @@
<string name="drawer_prev_page">Előző oldal</string>
<string name="drawer_next_page">Következő oldal</string>
<string name="drawer_hud">Teljesítmény HUD</string>
<string name="drawer_hud_fps">Képkockasebesség</string>
<string name="drawer_hud_battery">Akkuhőmérséklet</string>
<string name="drawer_hud_graph">Teljesítménygrafikon</string>
<string name="drawer_hud_color">Szín</string>
<string name="drawer_hud_color_mint">Menta</string>
<string name="drawer_hud_color_white">Fehér</string>
<string name="drawer_hud_color_sky">Égszínkék</string>
<string name="drawer_hud_color_amber">Borostyán</string>
<string name="drawer_hud_color_violet">Lila</string>
<string name="drawer_hud_opacity">Átlátszatlanság</string>
<string name="drawer_scaling">Méretezési mód</string>
<string name="drawer_scaling_sharpness">Méretezési élesség</string>
<string name="drawer_effects">Képernyőeffektek</string>
@@ -1770,7 +1782,8 @@
<string name="cmgr_original_kept">A telepített build eredetije megmarad: ez a visszaút.</string>
<string name="cmgr_not_stored">Nincs tárolva</string>
<string name="cmgr_deleted_original">A %2$s %1$s eredetije törölve.</string>
<string name="cmgr_nightlies_only">A letöltések csak a Nightlies kiadásokból érkeznek</string>
<string name="cmgr_nightlies_only">A letöltések csak a Nightlies és a DroidDeck kiadásokból érkeznek</string>
<string name="cmgr_nightly_replaced">A letöltés sikertelen: lehet, hogy ezt a nightly buildet egy újabb váltotta. Frissítse a listát, és próbálja újra.</string>
<string name="cmgr_list_predates_checksums">Ez a csomaglista régebbi, mint az ellenőrzőösszegek – frissítse, és próbálja újra</string>
<string name="cmgr_checksum_mismatch">Az ellenőrzőösszeg nem egyezik</string>
@@ -2026,6 +2039,9 @@
<string name="cloud_last_sync">Utolsó szinkronizálás: %1$s</string>
<string name="cloud_never">Még nincs szinkronizálva</string>
<string name="cloud_done">%1$d fájl</string>
<string name="cloud_up_to_date">Már naprakész</string>
<string name="cloud_signed_out">Jelentkezz be az áruházba a mentések szinkronizálásához</string>
<string name="cloud_not_synced">A mentések nem lettek szinkronizálva</string>
<string name="stores_eyebrow_installed">telepítve</string>
<string name="stores_eyebrow_library">a könyvtárában</string>
<string name="stores_eyebrow_store">áruház</string>
@@ -2329,7 +2345,7 @@
<string name="touch_done">Kész</string>
<string name="touch_save_failed">Az érintőelrendezést nem sikerült elmenteni</string>
<string name="touch_saved">Az érintőelrendezés elmentve a Steambe</string>
<string name="touch_app_id">%1$d. alkalmazás</string>
<string name="touch_app_id">%1$s. alkalmazás</string>
<string name="touch_label_hint">Felirat (nem kötelező)</string>
<string name="touch_icons_missing">A Steam ikonjai nem találhatók</string>
<plurals name="touch_icons_found">
@@ -2420,6 +2436,15 @@
<string name="glasses_vr_fov">SteamVR látómező</string>
<string name="glasses_vr_fov_hint">Kisebb érték közelebb hozza a SteamVR-t és kitölti a szemüveget; nagyobb többet mutat a környezetéből.</string>
<string name="glasses_playing">Játék ezen: %1$s</string>
<string name="glasses_phone_recenter">Középre igazítás</string>
<string name="glasses_phone_steamvr_menu">SteamVR menü</string>
<string name="glasses_phone_switch_sticks">Karok: kezek ⇄ játék</string>
<string name="glasses_phone_controllers">Kontrollerek: %1$s</string>
<string name="glasses_phone_keyboard">Billentyűzet</string>
<string name="glasses_phone_session_menu">Munkamenet menü</string>
<string name="glasses_phone_stop_steamvr">SteamVR leállítása</string>
<string name="glasses_phone_brightness">Fényerő %1$d / %2$d</string>
<string name="glasses_phone_battery">Akkumulátor %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Követés kalibrálása</string>
<string name="glasses_calibration_hint">Csökkenti a sodródást, és beállítja a vízszintes referenciát.</string>
<string name="glasses_calibration_saved_hint">A szemüveg a mentett kalibrációt használja.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Klik sekali</string>
<string name="gesture_hold_delay">Jeda sebelum menahan</string>
<string name="gesture_double_delay">Interval ketuk dua kali</string>
<string name="gesture_scope_game">Berlaku untuk game saat ini</string>
<string name="gesture_scope_default">Setelan default untuk semua game</string>
<string name="gesture_reset">Pulihkan setelan gestur awal</string>
<string name="gesture_cancel">Batal</string>
<string name="gesture_action">Pilih tindakan</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Roda mouse</string>
<string name="gesture_threshold">Ambang gestur: %1$d px</string>
<string name="gesture_debug">Tampilkan gestur yang dikenali</string>
<string name="gesture_editor_subtitle">Kontrol mouse dan keyboard menurut gestur</string>
<string name="gesture_tab_one">Satu jari</string>
<string name="gesture_tab_two">Dua jari</string>
<string name="gesture_tab_three">Tiga jari</string>
<string name="gesture_tab_options">Opsi</string>
<string name="gesture_one_hint">Pilih tindakan saat mengetuk, menyeret, atau menahan.</string>
<string name="gesture_two_hint">Atur pergeseran kamera, zoom, dan klik sekunder.</string>
<string name="gesture_three_hint">Jangkau lebih banyak pintasan dengan mudah.</string>
<string name="gesture_options_hint">Sesuaikan gerakan, pengenalan, dan umpan balik visual.</string>
<string name="gesture_defaults">Default</string>
<string name="gesture_game">Game ini</string>
<string name="gesture_use_defaults">Gunakan default</string>
<string name="gesture_inheriting">Menggunakan setelan default. Mengedit akan membuat setelan khusus game.</string>
<string name="gesture_save_changes">Simpan perubahan</string>
<string name="gesture_close">Tutup</string>
<string name="gesture_action_label">TINDAKAN</string>
<string name="gesture_action_for">Untuk %1$s</string>
<string name="gesture_search_actions">Cari tindakan mouse atau tombol keyboard</string>
<string name="gesture_clear_search">Hapus pencarian</string>
<string name="gesture_all_actions">Semua</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Keypad numerik</string>
<string name="gesture_group_symbols">Simbol</string>
<string name="gesture_movement">Gerakan mouse</string>
<string name="gesture_movement_hint">Seret langsung mengikuti posisi sentuhan. Seret relatif mengikuti gerakan jari, berguna saat game memusatkan mouse.</string>
<string name="gesture_middle_relative_hint">Pergeseran dengan tombol tengah mouse selalu mengikuti gerakan jari agar kursor tidak melompat.</string>
<string name="gesture_direct">Langsung</string>
<string name="gesture_relative">Relatif</string>
<string name="gesture_recognition">Pengenalan gestur</string>
<string name="gesture_threshold_hint">Gerakkan sejauh ini sebelum gestur dua atau tiga jari menjadi pergeseran atau zoom.</string>
<string name="gesture_feedback">Umpan balik visual</string>
<string name="gesture_mouse_behavior">Perilaku tombol mouse</string>
<string name="gesture_ms">%1$d md</string>
+28 -3
View File
@@ -502,7 +502,9 @@
<string name="comp_delete_original_title">Hapus yang asli ini?</string>
<string name="comp_delete_original_body">%1$s asli ini berasal dari build %2$s yang lebih lama. Asli build saat ini selalu dipertahankan.</string>
<string name="comp_nightlies_count">Di Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Segarkan untuk melihat daftar paket di Nightlies.</string>
<string name="comp_channel_stable">Stabil</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Segarkan untuk melihat daftar paket di Nightlies dan DroidDeck.</string>
<string name="comp_nothing_new">Tidak ada yang baru sejak pemeriksaan terakhir.</string>
<string name="comp_import_wcp">Impor .wcp</string>
<string name="comp_restore_original">Pulihkan yang asli dari Proton ini</string>
@@ -580,6 +582,16 @@
<string name="drawer_prev_page">Halaman sebelumnya</string>
<string name="drawer_next_page">Halaman berikutnya</string>
<string name="drawer_hud">HUD performa</string>
<string name="drawer_hud_fps">Laju bingkai</string>
<string name="drawer_hud_battery">Suhu baterai</string>
<string name="drawer_hud_graph">Grafik performa</string>
<string name="drawer_hud_color">Warna</string>
<string name="drawer_hud_color_mint">Mint</string>
<string name="drawer_hud_color_white">Putih</string>
<string name="drawer_hud_color_sky">Langit</string>
<string name="drawer_hud_color_amber">Ambar</string>
<string name="drawer_hud_color_violet">Ungu</string>
<string name="drawer_hud_opacity">Opasitas</string>
<string name="drawer_scaling">Mode penskalaan</string>
<string name="drawer_scaling_sharpness">Ketajaman penskalaan</string>
<string name="drawer_effects">Efek layar</string>
@@ -1749,7 +1761,8 @@
<string name="cmgr_original_kept">Yang asli dari build terinstal disimpan: itulah cara untuk kembali.</string>
<string name="cmgr_not_stored">Tidak tersimpan</string>
<string name="cmgr_deleted_original">Menghapus yang asli %1$s dari %2$s.</string>
<string name="cmgr_nightlies_only">Unduhan hanya berasal dari rilis Nightlies</string>
<string name="cmgr_nightlies_only">Unduhan hanya berasal dari rilis Nightlies dan DroidDeck</string>
<string name="cmgr_nightly_replaced">Unduhan gagal: build nightly ini mungkin sudah diganti dengan yang lebih baru. Segarkan daftar lalu coba lagi.</string>
<string name="cmgr_list_predates_checksums">Daftar paket ini dibuat sebelum adanya checksum - segarkan dan coba lagi</string>
<string name="cmgr_checksum_mismatch">Checksum tidak cocok</string>
@@ -2005,6 +2018,9 @@
<string name="cloud_last_sync">Sinkronisasi terakhir %1$s</string>
<string name="cloud_never">Belum disinkronkan</string>
<string name="cloud_done">%1$d file</string>
<string name="cloud_up_to_date">Sudah terbaru</string>
<string name="cloud_signed_out">Masuk ke toko untuk menyinkronkan simpanan</string>
<string name="cloud_not_synced">Simpanan tidak disinkronkan</string>
<string name="stores_eyebrow_installed">terinstal</string>
<string name="stores_eyebrow_library">dalam pustaka Anda</string>
<string name="stores_eyebrow_store">toko</string>
@@ -2306,7 +2322,7 @@
<string name="touch_done">Selesai</string>
<string name="touch_save_failed">Tata letak sentuh tidak dapat disimpan</string>
<string name="touch_saved">Tata letak sentuh disimpan ke Steam</string>
<string name="touch_app_id">App %1$d</string>
<string name="touch_app_id">App %1$s</string>
<string name="touch_label_hint">Label (opsional)</string>
<string name="touch_icons_missing">Ikon Steam tidak ditemukan</string>
<plurals name="touch_icons_found">
@@ -2395,6 +2411,15 @@
<string name="glasses_vr_fov">Bidang pandang SteamVR</string>
<string name="glasses_vr_fov_hint">Lebih rendah membawa SteamVR lebih dekat dan memenuhi kacamata; lebih tinggi menampilkan lebih banyak di sekitar Anda.</string>
<string name="glasses_playing">Bermain di %1$s</string>
<string name="glasses_phone_recenter">Pusatkan ulang</string>
<string name="glasses_phone_steamvr_menu">Menu SteamVR</string>
<string name="glasses_phone_switch_sticks">Stik: tangan ⇄ game</string>
<string name="glasses_phone_controllers">Kontroler: %1$s</string>
<string name="glasses_phone_keyboard">Keyboard</string>
<string name="glasses_phone_session_menu">Menu sesi</string>
<string name="glasses_phone_stop_steamvr">Hentikan SteamVR</string>
<string name="glasses_phone_brightness">Kecerahan %1$d / %2$d</string>
<string name="glasses_phone_battery">Baterai %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Kalibrasi pelacakan</string>
<string name="glasses_calibration_hint">Mengurangi drift dan menyelaraskan acuan horizontal.</string>
<string name="glasses_calibration_saved_hint">Kalibrasi tersimpan diterapkan ke kacamata ini.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Clic singolo</string>
<string name="gesture_hold_delay">Ritardo della pressione</string>
<string name="gesture_double_delay">Intervallo del doppio tocco</string>
<string name="gesture_scope_game">Si applica al gioco attuale</string>
<string name="gesture_scope_default">Impostazioni predefinite per tutti i giochi</string>
<string name="gesture_reset">Ripristina le impostazioni originali dei gesti</string>
<string name="gesture_cancel">Annulla</string>
<string name="gesture_action">Scegli azione</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Rotellina del mouse</string>
<string name="gesture_threshold">Soglia dei gesti: %1$d px</string>
<string name="gesture_debug">Mostra il gesto riconosciuto</string>
<string name="gesture_editor_subtitle">Comandi di mouse e tastiera organizzati per gesto</string>
<string name="gesture_tab_one">Un dito</string>
<string name="gesture_tab_two">Due dita</string>
<string name="gesture_tab_three">Tre dita</string>
<string name="gesture_tab_options">Opzioni</string>
<string name="gesture_one_hint">Scegli l\'azione di un tocco, trascinamento o pressione.</string>
<string name="gesture_two_hint">Configura lo spostamento della visuale, lo zoom e i clic secondari.</string>
<string name="gesture_three_hint">Tieni altre scorciatoie a portata di mano.</string>
<string name="gesture_options_hint">Regola movimento, riconoscimento e riscontro visivo.</string>
<string name="gesture_defaults">Predefiniti</string>
<string name="gesture_game">Questo gioco</string>
<string name="gesture_use_defaults">Usa impostazioni predefinite</string>
<string name="gesture_inheriting">Sono in uso le impostazioni predefinite. Una modifica crea impostazioni specifiche del gioco.</string>
<string name="gesture_save_changes">Salva modifiche</string>
<string name="gesture_close">Chiudi</string>
<string name="gesture_action_label">AZIONE</string>
<string name="gesture_action_for">Per %1$s</string>
<string name="gesture_search_actions">Cerca azioni del mouse o tasti della tastiera</string>
<string name="gesture_clear_search">Cancella ricerca</string>
<string name="gesture_all_actions">Tutte</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Tastierino numerico</string>
<string name="gesture_group_symbols">Simboli</string>
<string name="gesture_movement">Movimento del mouse</string>
<string name="gesture_movement_hint">Il trascinamento diretto segue la posizione del tocco. Quello relativo segue il movimento del dito ed è utile quando un gioco ricentra il mouse.</string>
<string name="gesture_middle_relative_hint">Lo spostamento con il pulsante centrale segue sempre il movimento del dito per evitare salti del cursore.</string>
<string name="gesture_direct">Diretto</string>
<string name="gesture_relative">Relativo</string>
<string name="gesture_recognition">Riconoscimento dei gesti</string>
<string name="gesture_threshold_hint">Percorri questa distanza prima che un gesto con due o tre dita diventi uno spostamento o uno zoom.</string>
<string name="gesture_feedback">Riscontro visivo</string>
<string name="gesture_mouse_behavior">Comportamento del pulsante del mouse</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -503,7 +503,9 @@
<string name="comp_delete_original_title">Eliminare questo originale?</string>
<string name="comp_delete_original_body">Questo originale di %1$s proviene da una build precedente di %2$s. L\'originale della build attuale viene sempre conservato.</string>
<string name="comp_nightlies_count">Nelle Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Aggiorna per elencare i pacchetti nelle Nightlies.</string>
<string name="comp_channel_stable">Stabile</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Aggiorna per elencare i pacchetti nelle Nightlies e in DroidDeck.</string>
<string name="comp_nothing_new">Niente di nuovo dall\'ultimo controllo.</string>
<string name="comp_import_wcp">Importa .wcp</string>
<string name="comp_restore_original">Ripristina l\'originale di questo Proton</string>
@@ -581,6 +583,16 @@
<string name="drawer_prev_page">Pagina precedente</string>
<string name="drawer_next_page">Pagina successiva</string>
<string name="drawer_hud">HUD prestazioni</string>
<string name="drawer_hud_fps">Frequenza fotogrammi</string>
<string name="drawer_hud_battery">Temperatura batteria</string>
<string name="drawer_hud_graph">Grafico prestazioni</string>
<string name="drawer_hud_color">Colore</string>
<string name="drawer_hud_color_mint">Menta</string>
<string name="drawer_hud_color_white">Bianco</string>
<string name="drawer_hud_color_sky">Cielo</string>
<string name="drawer_hud_color_amber">Ambra</string>
<string name="drawer_hud_color_violet">Viola</string>
<string name="drawer_hud_opacity">Opacità</string>
<string name="drawer_scaling">Modalità di ridimensionamento</string>
<string name="drawer_scaling_sharpness">Nitidezza del ridimensionamento</string>
<string name="drawer_effects">Effetti schermo</string>
@@ -1780,7 +1792,8 @@
<string name="cmgr_original_kept">L\'originale della build installata viene conservato: serve per tornare indietro.</string>
<string name="cmgr_not_stored">Non salvato</string>
<string name="cmgr_deleted_original">Originale %1$s di %2$s eliminato.</string>
<string name="cmgr_nightlies_only">I download provengono solo dalle release Nightly</string>
<string name="cmgr_nightlies_only">I download provengono solo dalle release Nightly e DroidDeck</string>
<string name="cmgr_nightly_replaced">Download non riuscito: questa build nightly potrebbe essere stata sostituita da una più recente. Aggiorna l’elenco e riprova.</string>
<string name="cmgr_list_predates_checksums">Questo elenco di pacchetti è anteriore ai checksum - aggiornalo e riprova</string>
<string name="cmgr_checksum_mismatch">Checksum non corrispondente</string>
@@ -2036,6 +2049,9 @@
<string name="cloud_last_sync">Ultima sincronizzazione %1$s</string>
<string name="cloud_never">Non ancora sincronizzato</string>
<string name="cloud_done">%1$d file</string>
<string name="cloud_up_to_date">Già aggiornato</string>
<string name="cloud_signed_out">Accedi allo store per sincronizzare i salvataggi</string>
<string name="cloud_not_synced">I salvataggi non sono stati sincronizzati</string>
<string name="stores_eyebrow_installed">installato</string>
<string name="stores_eyebrow_library">nella tua libreria</string>
<string name="stores_eyebrow_store">negozio</string>
@@ -2338,7 +2354,7 @@
<string name="touch_done">Fine</string>
<string name="touch_save_failed">Impossibile salvare il layout touch</string>
<string name="touch_saved">Layout touch salvato su Steam</string>
<string name="touch_app_id">App %1$d</string>
<string name="touch_app_id">App %1$s</string>
<string name="touch_label_hint">Etichetta (opzionale)</string>
<string name="touch_icons_missing">Le icone di Steam non sono state trovate</string>
<plurals name="touch_icons_found">
@@ -2431,6 +2447,15 @@
<string name="glasses_vr_fov">Campo visivo di SteamVR</string>
<string name="glasses_vr_fov_hint">Più basso avvicina SteamVR e riempie gli occhiali; più alto mostra di più intorno a te.</string>
<string name="glasses_playing">Gioco in corso su %1$s</string>
<string name="glasses_phone_recenter">Ricentra</string>
<string name="glasses_phone_steamvr_menu">Menu di SteamVR</string>
<string name="glasses_phone_switch_sticks">Levette: mani ⇄ gioco</string>
<string name="glasses_phone_controllers">Controller: %1$s</string>
<string name="glasses_phone_keyboard">Tastiera</string>
<string name="glasses_phone_session_menu">Menu della sessione</string>
<string name="glasses_phone_stop_steamvr">Arresta SteamVR</string>
<string name="glasses_phone_brightness">Luminosità %1$d / %2$d</string>
<string name="glasses_phone_battery">Batteria %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Calibrazione del tracciamento</string>
<string name="glasses_calibration_hint">Riduce la deriva e allinea il riferimento orizzontale.</string>
<string name="glasses_calibration_saved_hint">La calibrazione salvata è applicata a questi occhiali.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">1回クリック</string>
<string name="gesture_hold_delay">長押しの待ち時間</string>
<string name="gesture_double_delay">ダブルタップの間隔</string>
<string name="gesture_scope_game">現在のゲームに適用</string>
<string name="gesture_scope_default">すべてのゲームの既定設定</string>
<string name="gesture_reset">ジェスチャーの設定を初期状態に戻す</string>
<string name="gesture_cancel">キャンセル</string>
<string name="gesture_action">操作を選択</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">マウスホイール</string>
<string name="gesture_threshold">ジェスチャーのしきい値:%1$d px</string>
<string name="gesture_debug">認識したジェスチャーを表示</string>
<string name="gesture_editor_subtitle">ジェスチャー別のマウスとキーボード操作</string>
<string name="gesture_tab_one">1本指</string>
<string name="gesture_tab_two">2本指</string>
<string name="gesture_tab_three">3本指</string>
<string name="gesture_tab_options">オプション</string>
<string name="gesture_one_hint">タップ、ドラッグ、長押しの動作を選択します。</string>
<string name="gesture_two_hint">カメラ移動、ズーム、補助クリックを設定します。</string>
<string name="gesture_three_hint">追加のショートカットを手元に配置します。</string>
<string name="gesture_options_hint">移動、認識、視覚的フィードバックを調整します。</string>
<string name="gesture_defaults">デフォルト</string>
<string name="gesture_game">このゲーム</string>
<string name="gesture_use_defaults">既定値を使用</string>
<string name="gesture_inheriting">既定設定を使用しています。編集するとゲーム固有の設定が作成されます。</string>
<string name="gesture_save_changes">変更を保存</string>
<string name="gesture_close">閉じる</string>
<string name="gesture_action_label">操作</string>
<string name="gesture_action_for">%1$sの操作</string>
<string name="gesture_search_actions">マウス操作やキーボードのキーを検索</string>
<string name="gesture_clear_search">検索をクリア</string>
<string name="gesture_all_actions">すべて</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">テンキー</string>
<string name="gesture_group_symbols">記号</string>
<string name="gesture_movement">マウスの移動</string>
<string name="gesture_movement_hint">直接ドラッグはタッチ位置に従います。相対ドラッグは指の動きに従い、ゲームがマウスを中央に戻す場合に適しています。</string>
<string name="gesture_middle_relative_hint">カーソルの飛びを防ぐため、中ボタンによる視点移動は常に指の動きに従います。</string>
<string name="gesture_direct">ダイレクト</string>
<string name="gesture_relative">相対</string>
<string name="gesture_recognition">ジェスチャー認識</string>
<string name="gesture_threshold_hint">2本指または3本指のジェスチャーが視点移動やズームになるまでに必要な移動距離です。</string>
<string name="gesture_feedback">視覚的フィードバック</string>
<string name="gesture_mouse_behavior">マウスボタンの動作</string>
<string name="gesture_ms">%1$dミリ秒</string>
+28 -3
View File
@@ -502,7 +502,9 @@
<string name="comp_delete_original_title">この元のバージョンを削除しますか?</string>
<string name="comp_delete_original_body">この%1$sの元のバージョンは、%2$sの以前のビルドのものです。現在のビルドの元のバージョンは常に保持されます。</string>
<string name="comp_nightlies_count">Nightlies内 · %1$d</string>
<string name="comp_refresh_to_list">更新してNightliesのパッケージを一覧表示します。</string>
<string name="comp_channel_stable">安定版</string>
<string name="comp_channel_nightly">ナイトリー</string>
<string name="comp_refresh_to_list">更新してNightliesとDroidDeckのパッケージを一覧表示します。</string>
<string name="comp_nothing_new">前回の確認以降、新しいものはありません。</string>
<string name="comp_import_wcp">.wcpをインポート</string>
<string name="comp_restore_original">このProtonの元のファイルを復元</string>
@@ -580,6 +582,16 @@
<string name="drawer_prev_page">前のページ</string>
<string name="drawer_next_page">次のページ</string>
<string name="drawer_hud">パフォーマンスHUD</string>
<string name="drawer_hud_fps">フレームレート</string>
<string name="drawer_hud_battery">バッテリー温度</string>
<string name="drawer_hud_graph">パフォーマンスグラフ</string>
<string name="drawer_hud_color">色</string>
<string name="drawer_hud_color_mint">ミント</string>
<string name="drawer_hud_color_white">ホワイト</string>
<string name="drawer_hud_color_sky">スカイ</string>
<string name="drawer_hud_color_amber">アンバー</string>
<string name="drawer_hud_color_violet">バイオレット</string>
<string name="drawer_hud_opacity">不透明度</string>
<string name="drawer_scaling">スケーリングモード</string>
<string name="drawer_scaling_sharpness">スケーリングのシャープネス</string>
<string name="drawer_effects">画面エフェクト</string>
@@ -1749,7 +1761,8 @@
<string name="cmgr_original_kept">インストール済みビルドの元のファイルは、元に戻すために保持されます。</string>
<string name="cmgr_not_stored">保存されていません</string>
<string name="cmgr_deleted_original">%2$sの%1$s版の元のファイルを削除しました。</string>
<string name="cmgr_nightlies_only">ダウンロードはNightliesのリリースからのみ行われます</string>
<string name="cmgr_nightlies_only">ダウンロードはNightliesとDroidDeckのリリースからのみ行われます</string>
<string name="cmgr_nightly_replaced">ダウンロードに失敗しました:このナイトリービルドは新しいビルドに置き換えられた可能性があります。一覧を更新してもう一度お試しください。</string>
<string name="cmgr_list_predates_checksums">このパッケージ一覧はチェックサム導入前のものです。更新してからもう一度お試しください</string>
<string name="cmgr_checksum_mismatch">チェックサムが一致しません</string>
@@ -2005,6 +2018,9 @@
<string name="cloud_last_sync">最終同期 %1$s</string>
<string name="cloud_never">未同期</string>
<string name="cloud_done">%1$d個のファイル</string>
<string name="cloud_up_to_date">すでに最新です</string>
<string name="cloud_signed_out">セーブを同期するにはストアにサインインしてください</string>
<string name="cloud_not_synced">セーブは同期されませんでした</string>
<string name="stores_eyebrow_installed">インストール済み</string>
<string name="stores_eyebrow_library">ライブラリ内</string>
<string name="stores_eyebrow_store">ストア</string>
@@ -2306,7 +2322,7 @@
<string name="touch_done">完了</string>
<string name="touch_save_failed">タッチレイアウトを保存できませんでした</string>
<string name="touch_saved">タッチレイアウトをSteamに保存しました</string>
<string name="touch_app_id">アプリ%1$d</string>
<string name="touch_app_id">アプリ%1$s</string>
<string name="touch_label_hint">ラベル(任意)</string>
<string name="touch_icons_missing">Steamのアイコンが見つかりませんでした</string>
<plurals name="touch_icons_found">
@@ -2395,6 +2411,15 @@
<string name="glasses_vr_fov">SteamVR の視野角</string>
<string name="glasses_vr_fov_hint">小さくすると SteamVR が近くなりグラスいっぱいに広がり、大きくすると周囲が広く見えます。</string>
<string name="glasses_playing">%1$s でプレイ中</string>
<string name="glasses_phone_recenter">中心をリセット</string>
<string name="glasses_phone_steamvr_menu">SteamVR メニュー</string>
<string name="glasses_phone_switch_sticks">スティック: 手 ⇄ ゲーム</string>
<string name="glasses_phone_controllers">コントローラー: %1$s</string>
<string name="glasses_phone_keyboard">キーボード</string>
<string name="glasses_phone_session_menu">セッションメニュー</string>
<string name="glasses_phone_stop_steamvr">SteamVR を停止</string>
<string name="glasses_phone_brightness">明るさ %1$d / %2$d</string>
<string name="glasses_phone_battery">バッテリー %1$d%% · %2$d °C</string>
<string name="glasses_calibration">トラッキングのキャリブレーション</string>
<string name="glasses_calibration_hint">ドリフトを減らし、水平の基準を合わせます。</string>
<string name="glasses_calibration_saved_hint">保存したキャリブレーションをこのグラスに適用しています。</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">한 번 클릭</string>
<string name="gesture_hold_delay">길게 누르기 대기 시간</string>
<string name="gesture_double_delay">두 번 탭 간격</string>
<string name="gesture_scope_game">현재 게임에 적용</string>
<string name="gesture_scope_default">모든 게임의 기본 설정</string>
<string name="gesture_reset">제스처 설정을 초기 상태로 재설정</string>
<string name="gesture_cancel">취소</string>
<string name="gesture_action">동작 선택</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">마우스 휠</string>
<string name="gesture_threshold">제스처 임계값: %1$d px</string>
<string name="gesture_debug">인식된 제스처 표시</string>
<string name="gesture_editor_subtitle">제스처별 마우스 및 키보드 조작</string>
<string name="gesture_tab_one">한 손가락</string>
<string name="gesture_tab_two">두 손가락</string>
<string name="gesture_tab_three">세 손가락</string>
<string name="gesture_tab_options">옵션</string>
<string name="gesture_one_hint">탭, 드래그, 길게 누르기의 동작을 선택하세요.</string>
<string name="gesture_two_hint">카메라 이동, 확대/축소, 보조 클릭을 설정하세요.</string>
<string name="gesture_three_hint">추가 단축 동작을 손쉽게 사용하세요.</string>
<string name="gesture_options_hint">이동, 인식, 시각적 피드백을 조정하세요.</string>
<string name="gesture_defaults">기본값</string>
<string name="gesture_game">이 게임</string>
<string name="gesture_use_defaults">기본값 사용</string>
<string name="gesture_inheriting">기본 설정을 사용 중입니다. 수정하면 게임별 설정이 생성됩니다.</string>
<string name="gesture_save_changes">변경 사항 저장</string>
<string name="gesture_close">닫기</string>
<string name="gesture_action_label">동작</string>
<string name="gesture_action_for">%1$s 동작</string>
<string name="gesture_search_actions">마우스 동작 또는 키보드 키 검색</string>
<string name="gesture_clear_search">검색 지우기</string>
<string name="gesture_all_actions">전체</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">숫자 키패드</string>
<string name="gesture_group_symbols">기호</string>
<string name="gesture_movement">마우스 이동</string>
<string name="gesture_movement_hint">직접 드래그는 터치 위치를 따릅니다. 상대 드래그는 손가락 움직임을 따르며, 게임에서 마우스를 중앙으로 돌려놓을 때 유용합니다.</string>
<string name="gesture_middle_relative_hint">커서가 튀지 않도록 가운데 버튼 이동은 항상 손가락 움직임을 따릅니다.</string>
<string name="gesture_direct">직접 터치</string>
<string name="gesture_relative">상대</string>
<string name="gesture_recognition">제스처 인식</string>
<string name="gesture_threshold_hint">두 손가락 또는 세 손가락 제스처가 카메라 이동이나 확대/축소로 인식되기 위한 이동 거리입니다.</string>
<string name="gesture_feedback">시각적 피드백</string>
<string name="gesture_mouse_behavior">마우스 버튼 동작</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -502,7 +502,9 @@
<string name="comp_delete_original_title">이 원본 버전을 삭제하시겠습니까?</string>
<string name="comp_delete_original_body">이 %1$s 원본 버전은 %2$s의 이전 빌드에서 가져온 것입니다. 현재 빌드의 원본 버전은 항상 유지됩니다.</string>
<string name="comp_nightlies_count">Nightlies 내 · %1$d</string>
<string name="comp_refresh_to_list">새로 고쳐 Nightlies의 패키지를 나열합니다.</string>
<string name="comp_channel_stable">안정판</string>
<string name="comp_channel_nightly">나이틀리</string>
<string name="comp_refresh_to_list">새로 고쳐 Nightlies 및 DroidDeck의 패키지를 나열합니다.</string>
<string name="comp_nothing_new">마지막 확인 이후 새로운 내용이 없습니다.</string>
<string name="comp_import_wcp">.wcp 가져오기</string>
<string name="comp_restore_original">이 Proton의 원본 파일 복원</string>
@@ -580,6 +582,16 @@
<string name="drawer_prev_page">이전 페이지</string>
<string name="drawer_next_page">다음 페이지</string>
<string name="drawer_hud">성능 HUD</string>
<string name="drawer_hud_fps">프레임 속도</string>
<string name="drawer_hud_battery">배터리 온도</string>
<string name="drawer_hud_graph">성능 그래프</string>
<string name="drawer_hud_color">색상</string>
<string name="drawer_hud_color_mint">민트</string>
<string name="drawer_hud_color_white">흰색</string>
<string name="drawer_hud_color_sky">하늘색</string>
<string name="drawer_hud_color_amber">호박색</string>
<string name="drawer_hud_color_violet">보라색</string>
<string name="drawer_hud_opacity">불투명도</string>
<string name="drawer_scaling">스케일링 모드</string>
<string name="drawer_scaling_sharpness">스케일링 선명도</string>
<string name="drawer_effects">화면 효과</string>
@@ -1749,7 +1761,8 @@
<string name="cmgr_original_kept">설치된 빌드의 원본은 되돌리기 위해 유지됩니다.</string>
<string name="cmgr_not_stored">저장되지 않음</string>
<string name="cmgr_deleted_original">%2$s의 %1$s 원본을 삭제했습니다.</string>
<string name="cmgr_nightlies_only">Nightlies 릴리스에서만 다운로드할 수 있습니다</string>
<string name="cmgr_nightlies_only">Nightlies 및 DroidDeck 릴리스에서만 다운로드할 수 있습니다</string>
<string name="cmgr_nightly_replaced">다운로드 실패: 이 나이틀리 빌드가 더 새로운 빌드로 교체되었을 수 있습니다. 목록을 새로 고친 후 다시 시도하세요.</string>
<string name="cmgr_list_predates_checksums">이 패키지 목록은 체크섬 도입 이전의 것입니다. 새로 고친 후 다시 시도하세요</string>
<string name="cmgr_checksum_mismatch">체크섬 불일치</string>
@@ -2005,6 +2018,9 @@
<string name="cloud_last_sync">마지막 동기화 %1$s</string>
<string name="cloud_never">아직 동기화 안 됨</string>
<string name="cloud_done">파일 %1$d개</string>
<string name="cloud_up_to_date">이미 최신 상태입니다</string>
<string name="cloud_signed_out">저장 파일을 동기화하려면 스토어에 로그인하세요</string>
<string name="cloud_not_synced">저장 파일이 동기화되지 않았습니다</string>
<string name="stores_eyebrow_installed">설치됨</string>
<string name="stores_eyebrow_library">내 라이브러리</string>
<string name="stores_eyebrow_store">스토어</string>
@@ -2306,7 +2322,7 @@
<string name="touch_done">완료</string>
<string name="touch_save_failed">터치 레이아웃을 저장할 수 없습니다</string>
<string name="touch_saved">터치 레이아웃이 Steam에 저장되었습니다</string>
<string name="touch_app_id">앱 %1$d</string>
<string name="touch_app_id">앱 %1$s</string>
<string name="touch_label_hint">라벨(선택 사항)</string>
<string name="touch_icons_missing">Steam 아이콘을 찾을 수 없습니다</string>
<plurals name="touch_icons_found">
@@ -2395,6 +2411,15 @@
<string name="glasses_vr_fov">SteamVR 시야각</string>
<string name="glasses_vr_fov_hint">낮추면 SteamVR이 가까워져 안경을 가득 채우고, 높이면 주변이 더 넓게 보입니다.</string>
<string name="glasses_playing">%1$s에서 플레이 중</string>
<string name="glasses_phone_recenter">중앙 재설정</string>
<string name="glasses_phone_steamvr_menu">SteamVR 메뉴</string>
<string name="glasses_phone_switch_sticks">스틱: 손 ⇄ 게임</string>
<string name="glasses_phone_controllers">컨트롤러: %1$s</string>
<string name="glasses_phone_keyboard">키보드</string>
<string name="glasses_phone_session_menu">세션 메뉴</string>
<string name="glasses_phone_stop_steamvr">SteamVR 중지</string>
<string name="glasses_phone_brightness">밝기 %1$d / %2$d</string>
<string name="glasses_phone_battery">배터리 %1$d%% · %2$d °C</string>
<string name="glasses_calibration">트래킹 보정</string>
<string name="glasses_calibration_hint">드리프트를 줄이고 수평 기준을 맞춥니다.</string>
<string name="glasses_calibration_saved_hint">저장된 보정이 이 안경에 적용되어 있습니다.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Klik sekali</string>
<string name="gesture_hold_delay">Lengah sebelum menahan</string>
<string name="gesture_double_delay">Sela ketikan dua kali</string>
<string name="gesture_scope_game">Digunakan untuk permainan semasa</string>
<string name="gesture_scope_default">Tetapan lalai untuk semua permainan</string>
<string name="gesture_reset">Pulihkan tetapan gerak isyarat asal</string>
<string name="gesture_cancel">Batal</string>
<string name="gesture_action">Pilih tindakan</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Roda tetikus</string>
<string name="gesture_threshold">Ambang gerak isyarat: %1$d px</string>
<string name="gesture_debug">Tunjukkan gerak isyarat yang dikenal pasti</string>
<string name="gesture_editor_subtitle">Kawalan tetikus dan papan kekunci mengikut gerak isyarat</string>
<string name="gesture_tab_one">Satu jari</string>
<string name="gesture_tab_two">Dua jari</string>
<string name="gesture_tab_three">Tiga jari</string>
<string name="gesture_tab_options">Pilihan</string>
<string name="gesture_one_hint">Pilih tindakan apabila mengetik, menyeret atau menahan.</string>
<string name="gesture_two_hint">Tetapkan sorotan kamera, zum dan klik sekunder.</string>
<string name="gesture_three_hint">Pastikan pintasan tambahan mudah dicapai.</string>
<string name="gesture_options_hint">Laraskan pergerakan, pengecaman dan maklum balas visual.</string>
<string name="gesture_defaults">Lalai</string>
<string name="gesture_game">Permainan ini</string>
<string name="gesture_use_defaults">Gunakan lalai</string>
<string name="gesture_inheriting">Menggunakan tetapan lalai. Penyuntingan mencipta tetapan khusus permainan.</string>
<string name="gesture_save_changes">Simpan perubahan</string>
<string name="gesture_close">Tutup</string>
<string name="gesture_action_label">TINDAKAN</string>
<string name="gesture_action_for">Untuk %1$s</string>
<string name="gesture_search_actions">Cari tindakan tetikus atau kekunci papan kekunci</string>
<string name="gesture_clear_search">Kosongkan carian</string>
<string name="gesture_all_actions">Semua</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Pad nombor</string>
<string name="gesture_group_symbols">Simbol</string>
<string name="gesture_movement">Pergerakan tetikus</string>
<string name="gesture_movement_hint">Seretan langsung mengikut kedudukan sentuhan. Seretan relatif mengikut pergerakan jari dan berguna apabila permainan memusatkan tetikus.</string>
<string name="gesture_middle_relative_hint">Sorotan dengan butang tengah tetikus sentiasa mengikut pergerakan jari untuk mengelakkan lompatan kursor.</string>
<string name="gesture_direct">Terus</string>
<string name="gesture_relative">Relatif</string>
<string name="gesture_recognition">Pengecaman gerak isyarat</string>
<string name="gesture_threshold_hint">Gerakkan sejauh ini sebelum gerak isyarat dua atau tiga jari menjadi sorotan atau zum.</string>
<string name="gesture_feedback">Maklum balas visual</string>
<string name="gesture_mouse_behavior">Kelakuan butang tetikus</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -502,7 +502,9 @@
<string name="comp_delete_original_title">Padam yang asal ini?</string>
<string name="comp_delete_original_body">%1$s asal ini daripada binaan terdahulu %2$s. Yang asal bagi binaan semasa sentiasa dikekalkan.</string>
<string name="comp_nightlies_count">Pada Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Segarkan semula untuk menyenaraikan pakej pada Nightlies.</string>
<string name="comp_channel_stable">Stabil</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Segarkan semula untuk menyenaraikan pakej pada Nightlies dan DroidDeck.</string>
<string name="comp_nothing_new">Tiada apa-apa yang baharu sejak semakan terakhir.</string>
<string name="comp_import_wcp">Import .wcp</string>
<string name="comp_restore_original">Pulihkan yang asal bagi Proton ini</string>
@@ -580,6 +582,16 @@
<string name="drawer_prev_page">Halaman sebelumnya</string>
<string name="drawer_next_page">Halaman seterusnya</string>
<string name="drawer_hud">HUD prestasi</string>
<string name="drawer_hud_fps">Kadar bingkai</string>
<string name="drawer_hud_battery">Suhu bateri</string>
<string name="drawer_hud_graph">Graf prestasi</string>
<string name="drawer_hud_color">Warna</string>
<string name="drawer_hud_color_mint">Pudina</string>
<string name="drawer_hud_color_white">Putih</string>
<string name="drawer_hud_color_sky">Langit</string>
<string name="drawer_hud_color_amber">Ambar</string>
<string name="drawer_hud_color_violet">Ungu</string>
<string name="drawer_hud_opacity">Kelegapan</string>
<string name="drawer_scaling">Mod penskalaan</string>
<string name="drawer_scaling_sharpness">Ketajaman penskalaan</string>
<string name="drawer_effects">Kesan skrin</string>
@@ -1749,7 +1761,8 @@
<string name="cmgr_original_kept">Asal binaan yang dipasang dikekalkan: itulah jalan kembali.</string>
<string name="cmgr_not_stored">Tidak disimpan</string>
<string name="cmgr_deleted_original">Asal %1$s bagi %2$s telah dipadam.</string>
<string name="cmgr_nightlies_only">Muat turun hanya datang daripada keluaran Nightlies</string>
<string name="cmgr_nightlies_only">Muat turun hanya datang daripada keluaran Nightlies dan DroidDeck</string>
<string name="cmgr_nightly_replaced">Muat turun gagal: binaan nightly ini mungkin telah diganti dengan yang lebih baharu. Segarkan semula senarai dan cuba lagi.</string>
<string name="cmgr_list_predates_checksums">Senarai pakej ini mendahului checksum - segarkan dan cuba lagi</string>
<string name="cmgr_checksum_mismatch">Checksum tidak sepadan</string>
@@ -2005,6 +2018,9 @@
<string name="cloud_last_sync">Segerak terakhir %1$s</string>
<string name="cloud_never">Belum disegerakkan</string>
<string name="cloud_done">%1$d fail</string>
<string name="cloud_up_to_date">Sudah terkini</string>
<string name="cloud_signed_out">Log masuk ke kedai untuk menyegerakkan simpanan</string>
<string name="cloud_not_synced">Simpanan tidak disegerakkan</string>
<string name="stores_eyebrow_installed">dipasang</string>
<string name="stores_eyebrow_library">dalam pustaka anda</string>
<string name="stores_eyebrow_store">kedai</string>
@@ -2306,7 +2322,7 @@
<string name="touch_done">Selesai</string>
<string name="touch_save_failed">Susun atur sentuh tidak dapat disimpan</string>
<string name="touch_saved">Susun atur sentuh disimpan ke Steam</string>
<string name="touch_app_id">Apl %1$d</string>
<string name="touch_app_id">Apl %1$s</string>
<string name="touch_label_hint">Label (pilihan)</string>
<string name="touch_icons_missing">Ikon Steam tidak dijumpai</string>
<plurals name="touch_icons_found">
@@ -2395,6 +2411,15 @@
<string name="glasses_vr_fov">Medan pandangan SteamVR</string>
<string name="glasses_vr_fov_hint">Lebih rendah mendekatkan SteamVR dan memenuhi cermin mata; lebih tinggi menunjukkan lebih banyak di sekeliling anda.</string>
<string name="glasses_playing">Bermain pada %1$s</string>
<string name="glasses_phone_recenter">Pusatkan semula</string>
<string name="glasses_phone_steamvr_menu">Menu SteamVR</string>
<string name="glasses_phone_switch_sticks">Kayu bedik: tangan ⇄ permainan</string>
<string name="glasses_phone_controllers">Pengawal: %1$s</string>
<string name="glasses_phone_keyboard">Papan kekunci</string>
<string name="glasses_phone_session_menu">Menu sesi</string>
<string name="glasses_phone_stop_steamvr">Hentikan SteamVR</string>
<string name="glasses_phone_brightness">Kecerahan %1$d / %2$d</string>
<string name="glasses_phone_battery">Bateri %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Penentukuran penjejakan</string>
<string name="glasses_calibration_hint">Mengurangkan hanyutan dan menjajarkan rujukan mendatar.</string>
<string name="glasses_calibration_saved_hint">Penentukuran yang disimpan digunakan pada cermin mata ini.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Klikk én gang</string>
<string name="gesture_hold_delay">Forsinkelse før hold</string>
<string name="gesture_double_delay">Intervall for dobbelttrykk</string>
<string name="gesture_scope_game">Gjelder det gjeldende spillet</string>
<string name="gesture_scope_default">Standardinnstillinger for alle spill</string>
<string name="gesture_reset">Gjenopprett de opprinnelige bevegelsesinnstillingene</string>
<string name="gesture_cancel">Avbryt</string>
<string name="gesture_action">Velg handling</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Musehjul</string>
<string name="gesture_threshold">Bevegelsesterskel: %1$d px</string>
<string name="gesture_debug">Vis gjenkjent bevegelse</string>
<string name="gesture_editor_subtitle">Muse- og tastaturstyring organisert etter bevegelse</string>
<string name="gesture_tab_one">Én finger</string>
<string name="gesture_tab_two">To fingre</string>
<string name="gesture_tab_three">Tre fingre</string>
<string name="gesture_tab_options">Alternativer</string>
<string name="gesture_one_hint">Velg hva et trykk, drag eller hold skal gjøre.</string>
<string name="gesture_two_hint">Still inn kamerapanorering, zoom og sekundære klikk.</string>
<string name="gesture_three_hint">Ha flere snarveier innen rekkevidde.</string>
<string name="gesture_options_hint">Juster bevegelse, gjenkjenning og visuell tilbakemelding.</string>
<string name="gesture_defaults">Standardverdier</string>
<string name="gesture_game">Dette spillet</string>
<string name="gesture_use_defaults">Bruk standardinnstillinger</string>
<string name="gesture_inheriting">Standardinnstillinger brukes. Redigering oppretter egne innstillinger for spillet.</string>
<string name="gesture_save_changes">Lagre endringer</string>
<string name="gesture_close">Lukk</string>
<string name="gesture_action_label">HANDLING</string>
<string name="gesture_action_for">For %1$s</string>
<string name="gesture_search_actions">Søk etter musehandlinger eller tastaturtaster</string>
<string name="gesture_clear_search">Tøm søket</string>
<string name="gesture_all_actions">Alle</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Numerisk tastatur</string>
<string name="gesture_group_symbols">Symboler</string>
<string name="gesture_movement">Musebevegelse</string>
<string name="gesture_movement_hint">Direkte draing følger berøringsposisjonen. Relativ draing følger fingerbevegelsen og er nyttig når et spill sentrerer musen.</string>
<string name="gesture_middle_relative_hint">Panorering med midtre museknapp følger alltid fingerbevegelsen for å unngå markørhopp.</string>
<string name="gesture_direct">Direkte</string>
<string name="gesture_relative">Relativ</string>
<string name="gesture_recognition">Gjenkjenning av bevegelser</string>
<string name="gesture_threshold_hint">Beveg fingrene så langt før en bevegelse med to eller tre fingre blir til panorering eller zoom.</string>
<string name="gesture_feedback">Visuell tilbakemelding</string>
<string name="gesture_mouse_behavior">Museknappens funksjon</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -504,7 +504,9 @@
<string name="comp_delete_original_title">Slette denne originalen?</string>
<string name="comp_delete_original_body">Denne %1$s-originalen er fra en tidligere build av %2$s. Den gjeldende buildens original beholdes alltid.</string>
<string name="comp_nightlies_count">På Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Oppdater for å liste pakker på Nightlies.</string>
<string name="comp_channel_stable">Stabil</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Oppdater for å liste pakker på Nightlies og DroidDeck.</string>
<string name="comp_nothing_new">Ingenting nytt siden siste sjekk.</string>
<string name="comp_import_wcp">Importer .wcp</string>
<string name="comp_restore_original">Gjenopprett denne Protonens original</string>
@@ -582,6 +584,16 @@
<string name="drawer_prev_page">Forrige side</string>
<string name="drawer_next_page">Neste side</string>
<string name="drawer_hud">Ytelses-HUD</string>
<string name="drawer_hud_fps">Bildefrekvens</string>
<string name="drawer_hud_battery">Batteritemperatur</string>
<string name="drawer_hud_graph">Ytelsesgraf</string>
<string name="drawer_hud_color">Farge</string>
<string name="drawer_hud_color_mint">Mint</string>
<string name="drawer_hud_color_white">Hvit</string>
<string name="drawer_hud_color_sky">Himmel</string>
<string name="drawer_hud_color_amber">Amber</string>
<string name="drawer_hud_color_violet">Fiolett</string>
<string name="drawer_hud_opacity">Opasitet</string>
<string name="drawer_scaling">Skaleringsmodus</string>
<string name="drawer_scaling_sharpness">Skaleringsskarphet</string>
<string name="drawer_effects">Skjermeffekter</string>
@@ -1770,7 +1782,8 @@
<string name="cmgr_original_kept">Originalen til den installerte builden beholdes: det er veien tilbake.</string>
<string name="cmgr_not_stored">Ikke lagret</string>
<string name="cmgr_deleted_original">Slettet %1$s-originalen av %2$s.</string>
<string name="cmgr_nightlies_only">Nedlastinger kommer bare fra Nightlies-utgivelsene</string>
<string name="cmgr_nightlies_only">Nedlastinger kommer bare fra Nightlies- og DroidDeck-utgivelsene</string>
<string name="cmgr_nightly_replaced">Nedlastingen mislyktes: denne nightly-versjonen kan være erstattet av en nyere. Oppdater listen og prøv igjen.</string>
<string name="cmgr_list_predates_checksums">Denne pakkelisten er eldre enn sjekksummene – oppdater den og prøv igjen</string>
<string name="cmgr_checksum_mismatch">Sjekksummen stemmer ikke</string>
@@ -2026,6 +2039,9 @@
<string name="cloud_last_sync">Siste synkronisering %1$s</string>
<string name="cloud_never">Ikke synkronisert ennå</string>
<string name="cloud_done">%1$d filer</string>
<string name="cloud_up_to_date">Allerede oppdatert</string>
<string name="cloud_signed_out">Logg inn i butikken for å synkronisere lagrede spill</string>
<string name="cloud_not_synced">Lagrede spill ble ikke synkronisert</string>
<string name="stores_eyebrow_installed">installert</string>
<string name="stores_eyebrow_library">i biblioteket ditt</string>
<string name="stores_eyebrow_store">butikk</string>
@@ -2329,7 +2345,7 @@
<string name="touch_done">Fullført</string>
<string name="touch_save_failed">Kunne ikke lagre berøringsoppsettet</string>
<string name="touch_saved">Berøringsoppsett lagret til Steam</string>
<string name="touch_app_id">App %1$d</string>
<string name="touch_app_id">App %1$s</string>
<string name="touch_label_hint">Etikett (valgfritt)</string>
<string name="touch_icons_missing">Steams ikoner ble ikke funnet</string>
<plurals name="touch_icons_found">
@@ -2420,6 +2436,15 @@
<string name="glasses_vr_fov">SteamVR-synsfelt</string>
<string name="glasses_vr_fov_hint">Lavere bringer SteamVR nærmere og fyller brillene; høyere viser mer rundt deg.</string>
<string name="glasses_playing">Spiller på %1$s</string>
<string name="glasses_phone_recenter">Sentrer på nytt</string>
<string name="glasses_phone_steamvr_menu">SteamVR-meny</string>
<string name="glasses_phone_switch_sticks">Spaker: hender ⇄ spill</string>
<string name="glasses_phone_controllers">Kontrollere: %1$s</string>
<string name="glasses_phone_keyboard">Tastatur</string>
<string name="glasses_phone_session_menu">Øktmeny</string>
<string name="glasses_phone_stop_steamvr">Stopp SteamVR</string>
<string name="glasses_phone_brightness">Lysstyrke %1$d / %2$d</string>
<string name="glasses_phone_battery">Batteri %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Sporingskalibrering</string>
<string name="glasses_calibration_hint">Reduserer avdrift og retter inn horisontreferansen.</string>
<string name="glasses_calibration_saved_hint">Lagret kalibrering brukes for disse brillene.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Eenmaal klikken</string>
<string name="gesture_hold_delay">Wachttijd voor vasthouden</string>
<string name="gesture_double_delay">Interval voor dubbeltikken</string>
<string name="gesture_scope_game">Geldt voor het huidige spel</string>
<string name="gesture_scope_default">Standaardinstellingen voor alle spellen</string>
<string name="gesture_reset">Oorspronkelijke gebareninstellingen herstellen</string>
<string name="gesture_cancel">Annuleren</string>
<string name="gesture_action">Actie kiezen</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Muiswiel</string>
<string name="gesture_threshold">Gebaardrempel: %1$d px</string>
<string name="gesture_debug">Herkend gebaar tonen</string>
<string name="gesture_editor_subtitle">Muis- en toetsenbordbediening per gebaar</string>
<string name="gesture_tab_one">Eén vinger</string>
<string name="gesture_tab_two">Twee vingers</string>
<string name="gesture_tab_three">Drie vingers</string>
<string name="gesture_tab_options">Opties</string>
<string name="gesture_one_hint">Kies wat tikken, slepen of vasthouden doet.</string>
<string name="gesture_two_hint">Stel camerabewegingen, zoomen en secundaire klikken in.</string>
<string name="gesture_three_hint">Houd extra sneltoetsen binnen handbereik.</string>
<string name="gesture_options_hint">Pas beweging, herkenning en visuele feedback aan.</string>
<string name="gesture_defaults">Standaardinstellingen</string>
<string name="gesture_game">Dit spel</string>
<string name="gesture_use_defaults">Standaardinstellingen gebruiken</string>
<string name="gesture_inheriting">Standaardinstellingen zijn actief. Bewerken maakt instellingen voor dit spel.</string>
<string name="gesture_save_changes">Wijzigingen opslaan</string>
<string name="gesture_close">Sluiten</string>
<string name="gesture_action_label">ACTIE</string>
<string name="gesture_action_for">Voor %1$s</string>
<string name="gesture_search_actions">Zoek muisacties of toetsen</string>
<string name="gesture_clear_search">Zoekopdracht wissen</string>
<string name="gesture_all_actions">Alle</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Numeriek toetsenblok</string>
<string name="gesture_group_symbols">Symbolen</string>
<string name="gesture_movement">Muisbeweging</string>
<string name="gesture_movement_hint">Direct slepen volgt de aanraakpositie. Relatief slepen volgt de vingerbeweging en is handig als een spel de muis opnieuw centreert.</string>
<string name="gesture_middle_relative_hint">Pannen met de middelste muisknop volgt altijd de vingerbeweging om cursorsprongen te voorkomen.</string>
<string name="gesture_direct">Direct</string>
<string name="gesture_relative">Relatief</string>
<string name="gesture_recognition">Gebarenherkenning</string>
<string name="gesture_threshold_hint">Beweeg deze afstand voordat een gebaar met twee of drie vingers overgaat in pannen of zoomen.</string>
<string name="gesture_feedback">Visuele feedback</string>
<string name="gesture_mouse_behavior">Gedrag van de muisknop</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -504,7 +504,9 @@
<string name="comp_delete_original_title">Dit origineel verwijderen?</string>
<string name="comp_delete_original_body">Dit origineel van %1$s komt uit een eerdere build van %2$s. Het origineel van de huidige build wordt altijd bewaard.</string>
<string name="comp_nightlies_count">In de Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Vernieuw om de pakketten in de Nightlies te tonen.</string>
<string name="comp_channel_stable">Stabiel</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Vernieuw om de pakketten in de Nightlies en bij DroidDeck te tonen.</string>
<string name="comp_nothing_new">Niets nieuws sinds de laatste controle.</string>
<string name="comp_import_wcp">.wcp importeren</string>
<string name="comp_restore_original">Origineel van deze Proton herstellen</string>
@@ -582,6 +584,16 @@
<string name="drawer_prev_page">Vorige pagina</string>
<string name="drawer_next_page">Volgende pagina</string>
<string name="drawer_hud">Prestatie-HUD</string>
<string name="drawer_hud_fps">Beeldsnelheid</string>
<string name="drawer_hud_battery">Accutemperatuur</string>
<string name="drawer_hud_graph">Prestatiegrafiek</string>
<string name="drawer_hud_color">Kleur</string>
<string name="drawer_hud_color_mint">Mint</string>
<string name="drawer_hud_color_white">Wit</string>
<string name="drawer_hud_color_sky">Hemelsblauw</string>
<string name="drawer_hud_color_amber">Amber</string>
<string name="drawer_hud_color_violet">Violet</string>
<string name="drawer_hud_opacity">Transparantie</string>
<string name="drawer_scaling">Schaalmodus</string>
<string name="drawer_scaling_sharpness">Schaalscherpte</string>
<string name="drawer_effects">Schermeffecten</string>
@@ -1770,7 +1782,8 @@
<string name="cmgr_original_kept">Het origineel van de geïnstalleerde build wordt bewaard: dat is de weg terug.</string>
<string name="cmgr_not_stored">Niet opgeslagen</string>
<string name="cmgr_deleted_original">Het %1$s-origineel van %2$s is verwijderd.</string>
<string name="cmgr_nightlies_only">Downloads komen alleen van de Nightlies-releases</string>
<string name="cmgr_nightlies_only">Downloads komen alleen van de Nightlies- en DroidDeck-releases</string>
<string name="cmgr_nightly_replaced">Download mislukt: deze nightly is mogelijk vervangen door een nieuwere build. Vernieuw de lijst en probeer het opnieuw.</string>
<string name="cmgr_list_predates_checksums">Deze pakketlijst is ouder dan de checksums - vernieuw de lijst en probeer het opnieuw</string>
<string name="cmgr_checksum_mismatch">Checksum komt niet overeen</string>
@@ -2026,6 +2039,9 @@
<string name="cloud_last_sync">Laatste synchronisatie %1$s</string>
<string name="cloud_never">Nog niet gesynchroniseerd</string>
<string name="cloud_done">%1$d bestanden</string>
<string name="cloud_up_to_date">Al up-to-date</string>
<string name="cloud_signed_out">Log in bij de winkel om opslagbestanden te synchroniseren</string>
<string name="cloud_not_synced">Opslagbestanden zijn niet gesynchroniseerd</string>
<string name="stores_eyebrow_installed">geïnstalleerd</string>
<string name="stores_eyebrow_library">in je bibliotheek</string>
<string name="stores_eyebrow_store">winkel</string>
@@ -2329,7 +2345,7 @@
<string name="touch_done">Klaar</string>
<string name="touch_save_failed">De aanraakindeling kon niet worden opgeslagen</string>
<string name="touch_saved">Aanraakindeling opgeslagen in Steam</string>
<string name="touch_app_id">App %1$d</string>
<string name="touch_app_id">App %1$s</string>
<string name="touch_label_hint">Label (optioneel)</string>
<string name="touch_icons_missing">Steams pictogrammen zijn niet gevonden</string>
<plurals name="touch_icons_found">
@@ -2420,6 +2436,15 @@
<string name="glasses_vr_fov">SteamVR-gezichtsveld</string>
<string name="glasses_vr_fov_hint">Lager brengt SteamVR dichterbij en vult de bril; hoger toont meer om je heen.</string>
<string name="glasses_playing">Je speelt op %1$s</string>
<string name="glasses_phone_recenter">Opnieuw centreren</string>
<string name="glasses_phone_steamvr_menu">SteamVR-menu</string>
<string name="glasses_phone_switch_sticks">Sticks: handen ⇄ spel</string>
<string name="glasses_phone_controllers">Controllers: %1$s</string>
<string name="glasses_phone_keyboard">Toetsenbord</string>
<string name="glasses_phone_session_menu">Sessiemenu</string>
<string name="glasses_phone_stop_steamvr">SteamVR stoppen</string>
<string name="glasses_phone_brightness">Helderheid %1$d / %2$d</string>
<string name="glasses_phone_battery">Batterij %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Trackingkalibratie</string>
<string name="glasses_calibration_hint">Vermindert drift en lijnt de horizontale referentie uit.</string>
<string name="glasses_calibration_saved_hint">De opgeslagen kalibratie wordt op deze bril toegepast.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Kliknij raz</string>
<string name="gesture_hold_delay">Czas przytrzymania</string>
<string name="gesture_double_delay">Odstęp podwójnego stuknięcia</string>
<string name="gesture_scope_game">Dotyczy bieżącej gry</string>
<string name="gesture_scope_default">Ustawienia domyślne dla wszystkich gier</string>
<string name="gesture_reset">Przywróć pierwotne ustawienia gestów</string>
<string name="gesture_cancel">Anuluj</string>
<string name="gesture_action">Wybierz akcję</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Kółko myszy</string>
<string name="gesture_threshold">Próg gestów: %1$d px</string>
<string name="gesture_debug">Pokaż rozpoznany gest</string>
<string name="gesture_editor_subtitle">Sterowanie myszą i klawiaturą pogrupowane według gestów</string>
<string name="gesture_tab_one">Jeden palec</string>
<string name="gesture_tab_two">Dwa palce</string>
<string name="gesture_tab_three">Trzy palce</string>
<string name="gesture_tab_options">Opcje</string>
<string name="gesture_one_hint">Wybierz działanie stuknięcia, przeciągania lub przytrzymania.</string>
<string name="gesture_two_hint">Skonfiguruj przesuwanie kamery, przybliżanie i kliknięcia pomocnicze.</string>
<string name="gesture_three_hint">Miej dodatkowe skróty pod ręką.</string>
<string name="gesture_options_hint">Dostosuj ruch, rozpoznawanie i wizualne potwierdzenia.</string>
<string name="gesture_defaults">Domyślne</string>
<string name="gesture_game">Ta gra</string>
<string name="gesture_use_defaults">Użyj domyślnych</string>
<string name="gesture_inheriting">Używane są ustawienia domyślne. Edycja tworzy ustawienia dla tej gry.</string>
<string name="gesture_save_changes">Zapisz zmiany</string>
<string name="gesture_close">Zamknij</string>
<string name="gesture_action_label">AKCJA</string>
<string name="gesture_action_for">Dla %1$s</string>
<string name="gesture_search_actions">Szukaj akcji myszy lub klawiszy klawiatury</string>
<string name="gesture_clear_search">Wyczyść wyszukiwanie</string>
<string name="gesture_all_actions">Wszystkie</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Klawiatura numeryczna</string>
<string name="gesture_group_symbols">Symbole</string>
<string name="gesture_movement">Ruch myszy</string>
<string name="gesture_movement_hint">Przeciąganie bezpośrednie podąża za pozycją dotyku. Względne podąża za ruchem palca i przydaje się, gdy gra centruje mysz.</string>
<string name="gesture_middle_relative_hint">Przesuwanie środkowym przyciskiem myszy zawsze podąża za ruchem palca, aby uniknąć skoków kursora.</string>
<string name="gesture_direct">Bezpośredni</string>
<string name="gesture_relative">Względny</string>
<string name="gesture_recognition">Rozpoznawanie gestów</string>
<string name="gesture_threshold_hint">Przesuń palce o tę odległość, zanim gest dwoma lub trzema palcami stanie się przesuwaniem lub przybliżaniem.</string>
<string name="gesture_feedback">Wizualne potwierdzenia</string>
<string name="gesture_mouse_behavior">Działanie przycisku myszy</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -508,7 +508,9 @@
<string name="comp_delete_original_title">Usunąć ten oryginał?</string>
<string name="comp_delete_original_body">Ten oryginał %1$s pochodzi z wcześniejszej wersji %2$s. Oryginał bieżącej wersji jest zawsze zachowywany.</string>
<string name="comp_nightlies_count">W wersjach nightly · %1$d</string>
<string name="comp_refresh_to_list">Odśwież, aby wyświetlić pakiety w wersjach nightly.</string>
<string name="comp_channel_stable">Stabilna</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Odśwież, aby wyświetlić pakiety w Nightlies i DroidDeck.</string>
<string name="comp_nothing_new">Nic nowego od ostatniego sprawdzenia.</string>
<string name="comp_import_wcp">Importuj .wcp</string>
<string name="comp_restore_original">Przywróć oryginał tego Proton</string>
@@ -586,6 +588,16 @@
<string name="drawer_prev_page">Poprzednia strona</string>
<string name="drawer_next_page">Następna strona</string>
<string name="drawer_hud">HUD wydajności</string>
<string name="drawer_hud_fps">Liczba klatek</string>
<string name="drawer_hud_battery">Temperatura baterii</string>
<string name="drawer_hud_graph">Wykres wydajności</string>
<string name="drawer_hud_color">Kolor</string>
<string name="drawer_hud_color_mint">Mięta</string>
<string name="drawer_hud_color_white">Biały</string>
<string name="drawer_hud_color_sky">Błękitny</string>
<string name="drawer_hud_color_amber">Bursztynowy</string>
<string name="drawer_hud_color_violet">Fioletowy</string>
<string name="drawer_hud_opacity">Przezroczystość</string>
<string name="drawer_scaling">Tryb skalowania</string>
<string name="drawer_scaling_sharpness">Ostrość skalowania</string>
<string name="drawer_effects">Efekty ekranowe</string>
@@ -1812,7 +1824,8 @@
<string name="cmgr_original_kept">Oryginał zainstalowanej wersji zostaje zachowany: to droga powrotu.</string>
<string name="cmgr_not_stored">Nie przechowywano</string>
<string name="cmgr_deleted_original">Usunięto oryginał %2$s z %1$s.</string>
<string name="cmgr_nightlies_only">Pobieranie odbywa się tylko z wydań Nightlies</string>
<string name="cmgr_nightlies_only">Pobieranie odbywa się tylko z wydań Nightlies i DroidDeck</string>
<string name="cmgr_nightly_replaced">Pobieranie nie powiodło się: ta wersja nightly mogła zostać zastąpiona nowszą. Odśwież listę i spróbuj ponownie.</string>
<string name="cmgr_list_predates_checksums">Ta lista pakietów jest starsza niż sumy kontrolne – odśwież ją i spróbuj ponownie</string>
<string name="cmgr_checksum_mismatch">Niezgodna suma kontrolna</string>
@@ -2068,6 +2081,9 @@
<string name="cloud_last_sync">Ostatnia synchronizacja %1$s</string>
<string name="cloud_never">Jeszcze nie zsynchronizowano</string>
<string name="cloud_done">%1$d plików</string>
<string name="cloud_up_to_date">Już aktualne</string>
<string name="cloud_signed_out">Zaloguj się do sklepu, aby synchronizować zapisy</string>
<string name="cloud_not_synced">Zapisy nie zostały zsynchronizowane</string>
<string name="stores_eyebrow_installed">zainstalowana</string>
<string name="stores_eyebrow_library">w Twojej bibliotece</string>
<string name="stores_eyebrow_store">sklep</string>
@@ -2375,7 +2391,7 @@
<string name="touch_done">Gotowe</string>
<string name="touch_save_failed">Nie udało się zapisać układu dotykowego</string>
<string name="touch_saved">Układ dotykowy zapisany w Steam</string>
<string name="touch_app_id">Aplikacja %1$d</string>
<string name="touch_app_id">Aplikacja %1$s</string>
<string name="touch_label_hint">Etykieta (opcjonalnie)</string>
<string name="touch_icons_missing">Nie znaleziono ikon Steam</string>
<plurals name="touch_icons_found">
@@ -2470,6 +2486,15 @@
<string name="glasses_vr_fov">Pole widzenia SteamVR</string>
<string name="glasses_vr_fov_hint">Mniejsze przybliża SteamVR i wypełnia okulary; większe pokazuje więcej dookoła.</string>
<string name="glasses_playing">Grasz na: %1$s</string>
<string name="glasses_phone_recenter">Wyśrodkuj ponownie</string>
<string name="glasses_phone_steamvr_menu">Menu SteamVR</string>
<string name="glasses_phone_switch_sticks">Gałki: dłonie ⇄ gra</string>
<string name="glasses_phone_controllers">Kontrolery: %1$s</string>
<string name="glasses_phone_keyboard">Klawiatura</string>
<string name="glasses_phone_session_menu">Menu sesji</string>
<string name="glasses_phone_stop_steamvr">Zatrzymaj SteamVR</string>
<string name="glasses_phone_brightness">Jasność %1$d / %2$d</string>
<string name="glasses_phone_battery">Bateria %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Kalibracja śledzenia</string>
<string name="glasses_calibration_hint">Ogranicza dryf i wyrównuje poziom odniesienia.</string>
<string name="glasses_calibration_saved_hint">Dla tych okularów używana jest zapisana kalibracja.</string>
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Clicar uma vez</string>
<string name="gesture_hold_delay">Tempo para manter premido</string>
<string name="gesture_double_delay">Intervalo de toque duplo</string>
<string name="gesture_scope_game">Aplica-se ao jogo atual</string>
<string name="gesture_scope_default">Configurações padrão para todos os jogos</string>
<string name="gesture_reset">Restaurar as configurações originais de gestos</string>
<string name="gesture_cancel">Cancelar</string>
<string name="gesture_action">Escolher ação</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Roda do rato</string>
<string name="gesture_threshold">Limiar dos gestos: %1$d px</string>
<string name="gesture_debug">Mostrar gesto reconhecido</string>
<string name="gesture_editor_subtitle">Controlos de rato e teclado organizados por gesto</string>
<string name="gesture_tab_one">Um dedo</string>
<string name="gesture_tab_two">Dois dedos</string>
<string name="gesture_tab_three">Três dedos</string>
<string name="gesture_tab_options">Opções</string>
<string name="gesture_one_hint">Escolha o que um toque, arraste ou toque mantido deve fazer.</string>
<string name="gesture_two_hint">Configure o movimento da câmera, o zoom e os cliques secundários.</string>
<string name="gesture_three_hint">Mantenha mais atalhos ao alcance dos dedos.</string>
<string name="gesture_options_hint">Ajuste o movimento, o reconhecimento e a resposta visual.</string>
<string name="gesture_defaults">Valores padrão</string>
<string name="gesture_game">Este jogo</string>
<string name="gesture_use_defaults">Usar padrões</string>
<string name="gesture_inheriting">Usando as configurações padrão. A edição cria configurações específicas do jogo.</string>
<string name="gesture_save_changes">Salvar alterações</string>
<string name="gesture_close">Fechar</string>
<string name="gesture_action_label">AÇÃO</string>
<string name="gesture_action_for">Para %1$s</string>
<string name="gesture_search_actions">Pesquisar ações de rato ou teclas do teclado</string>
<string name="gesture_clear_search">Limpar pesquisa</string>
<string name="gesture_all_actions">Todas</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Teclado numérico</string>
<string name="gesture_group_symbols">Símbolos</string>
<string name="gesture_movement">Movimento do rato</string>
<string name="gesture_movement_hint">O arraste direto segue a posição do toque. O relativo segue o movimento do dedo e é útil quando um jogo centra o rato.</string>
<string name="gesture_middle_relative_hint">O movimento com o botão do meio sempre segue o movimento do dedo para evitar saltos do cursor.</string>
<string name="gesture_direct">Direto</string>
<string name="gesture_relative">Relativo</string>
<string name="gesture_recognition">Reconhecimento de gestos</string>
<string name="gesture_threshold_hint">Percorra esta distância antes que um gesto de dois ou três dedos se torne movimento de câmera ou zoom.</string>
<string name="gesture_feedback">Resposta visual</string>
<string name="gesture_mouse_behavior">Comportamento do botão do rato</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -503,7 +503,9 @@
<string name="comp_delete_original_title">Eliminar este original?</string>
<string name="comp_delete_original_body">Este original de %1$s é de uma versão anterior de %2$s. O original da versão atual é sempre mantido.</string>
<string name="comp_nightlies_count">Nas Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Atualize para listar os pacotes nas Nightlies.</string>
<string name="comp_channel_stable">Estável</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Atualize para listar os pacotes nas Nightlies e no DroidDeck.</string>
<string name="comp_nothing_new">Nada de novo desde a última verificação.</string>
<string name="comp_import_wcp">Importar .wcp</string>
<string name="comp_restore_original">Restaurar o original deste Proton</string>
@@ -581,6 +583,16 @@
<string name="drawer_prev_page">Página anterior</string>
<string name="drawer_next_page">Página seguinte</string>
<string name="drawer_hud">HUD de desempenho</string>
<string name="drawer_hud_fps">Taxa de fotogramas</string>
<string name="drawer_hud_battery">Temperatura da bateria</string>
<string name="drawer_hud_graph">Gráfico de desempenho</string>
<string name="drawer_hud_color">Cor</string>
<string name="drawer_hud_color_mint">Menta</string>
<string name="drawer_hud_color_white">Branco</string>
<string name="drawer_hud_color_sky">Céu</string>
<string name="drawer_hud_color_amber">Âmbar</string>
<string name="drawer_hud_color_violet">Violeta</string>
<string name="drawer_hud_opacity">Opacidade</string>
<string name="drawer_scaling">Modo de escala</string>
<string name="drawer_scaling_sharpness">Nitidez da escala</string>
<string name="drawer_effects">Efeitos de ecrã</string>
@@ -1780,7 +1792,8 @@
<string name="cmgr_original_kept">O original da versão instalada é mantido: é o caminho de volta.</string>
<string name="cmgr_not_stored">Não guardado</string>
<string name="cmgr_deleted_original">Original de %1$s de %2$s eliminado.</string>
<string name="cmgr_nightlies_only">As transferências vêm apenas das versões Nightlies</string>
<string name="cmgr_nightlies_only">As transferências vêm apenas das versões Nightlies e DroidDeck</string>
<string name="cmgr_nightly_replaced">A transferência falhou: esta versão nightly pode ter sido substituída por uma mais recente. Atualize a lista e tente novamente.</string>
<string name="cmgr_list_predates_checksums">Esta lista de pacotes é anterior às somas de verificação - atualize-a e tente novamente</string>
<string name="cmgr_checksum_mismatch">A soma de verificação não corresponde</string>
@@ -2036,6 +2049,9 @@
<string name="cloud_last_sync">Última sincronização: %1$s</string>
<string name="cloud_never">Ainda não sincronizado</string>
<string name="cloud_done">%1$d ficheiros</string>
<string name="cloud_up_to_date">Já está atualizado</string>
<string name="cloud_signed_out">Inicie sessão na loja para sincronizar os jogos guardados</string>
<string name="cloud_not_synced">Os jogos guardados não foram sincronizados</string>
<string name="stores_eyebrow_installed">instalado</string>
<string name="stores_eyebrow_library">na sua biblioteca</string>
<string name="stores_eyebrow_store">loja</string>
@@ -2338,7 +2354,7 @@
<string name="touch_done">Concluído</string>
<string name="touch_save_failed">Não foi possível guardar o esquema tátil</string>
<string name="touch_saved">Esquema tátil guardado na Steam</string>
<string name="touch_app_id">Aplicação %1$d</string>
<string name="touch_app_id">Aplicação %1$s</string>
<string name="touch_label_hint">Etiqueta (opcional)</string>
<string name="touch_icons_missing">Os ícones da Steam não foram encontrados</string>
<plurals name="touch_icons_found">
@@ -2431,6 +2447,15 @@
<string name="glasses_vr_fov">Campo de visão do SteamVR</string>
<string name="glasses_vr_fov_hint">Mais baixo aproxima o SteamVR e preenche os óculos; mais alto mostra mais à sua volta.</string>
<string name="glasses_playing">A jogar em %1$s</string>
<string name="glasses_phone_recenter">Recentrar</string>
<string name="glasses_phone_steamvr_menu">Menu do SteamVR</string>
<string name="glasses_phone_switch_sticks">Manípulos: mãos ⇄ jogo</string>
<string name="glasses_phone_controllers">Comandos: %1$s</string>
<string name="glasses_phone_keyboard">Teclado</string>
<string name="glasses_phone_session_menu">Menu da sessão</string>
<string name="glasses_phone_stop_steamvr">Parar o SteamVR</string>
<string name="glasses_phone_brightness">Brilho %1$d / %2$d</string>
<string name="glasses_phone_battery">Bateria %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Calibração do seguimento</string>
<string name="glasses_calibration_hint">Reduz a deriva e alinha a referência de nível.</string>
<string name="glasses_calibration_saved_hint">A calibração guardada é aplicada a estes óculos.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Clicar uma vez</string>
<string name="gesture_hold_delay">Tempo para manter pressionado</string>
<string name="gesture_double_delay">Intervalo de toque duplo</string>
<string name="gesture_scope_game">Aplica-se ao jogo atual</string>
<string name="gesture_scope_default">Configurações padrão para todos os jogos</string>
<string name="gesture_reset">Restaurar as configurações originais de gestos</string>
<string name="gesture_cancel">Cancelar</string>
<string name="gesture_action">Escolher ação</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Roda do mouse</string>
<string name="gesture_threshold">Limiar dos gestos: %1$d px</string>
<string name="gesture_debug">Mostrar gesto reconhecido</string>
<string name="gesture_editor_subtitle">Controles de mouse e teclado organizados por gesto</string>
<string name="gesture_tab_one">Um dedo</string>
<string name="gesture_tab_two">Dois dedos</string>
<string name="gesture_tab_three">Três dedos</string>
<string name="gesture_tab_options">Opções</string>
<string name="gesture_one_hint">Escolha o que um toque, arraste ou toque mantido deve fazer.</string>
<string name="gesture_two_hint">Configure o movimento da câmera, o zoom e os cliques secundários.</string>
<string name="gesture_three_hint">Mantenha mais atalhos ao alcance dos dedos.</string>
<string name="gesture_options_hint">Ajuste o movimento, o reconhecimento e a resposta visual.</string>
<string name="gesture_defaults">Padrões</string>
<string name="gesture_game">Este jogo</string>
<string name="gesture_use_defaults">Usar padrões</string>
<string name="gesture_inheriting">Usando as configurações padrão. A edição cria configurações específicas do jogo.</string>
<string name="gesture_save_changes">Salvar alterações</string>
<string name="gesture_close">Fechar</string>
<string name="gesture_action_label">AÇÃO</string>
<string name="gesture_action_for">Para %1$s</string>
<string name="gesture_search_actions">Pesquisar ações de mouse ou teclas do teclado</string>
<string name="gesture_clear_search">Limpar pesquisa</string>
<string name="gesture_all_actions">Todos</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Teclado numérico</string>
<string name="gesture_group_symbols">Símbolos</string>
<string name="gesture_movement">Movimento do mouse</string>
<string name="gesture_movement_hint">O arraste direto segue a posição do toque. O relativo segue o movimento do dedo e é útil quando um jogo centraliza o mouse.</string>
<string name="gesture_middle_relative_hint">O movimento com o botão do meio sempre segue o movimento do dedo para evitar saltos do cursor.</string>
<string name="gesture_direct">Direto</string>
<string name="gesture_relative">Relativo</string>
<string name="gesture_recognition">Reconhecimento de gestos</string>
<string name="gesture_threshold_hint">Percorra esta distância antes que um gesto de dois ou três dedos se torne movimento de câmera ou zoom.</string>
<string name="gesture_feedback">Resposta visual</string>
<string name="gesture_mouse_behavior">Comportamento do botão do mouse</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -503,7 +503,9 @@
<string name="comp_delete_original_title">Excluir este original?</string>
<string name="comp_delete_original_body">Este %1$s original é de uma versão anterior de %2$s. O original da versão atual é sempre mantido.</string>
<string name="comp_nightlies_count">Nas Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Atualize para listar os pacotes nas Nightlies.</string>
<string name="comp_channel_stable">Estável</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Atualize para listar os pacotes nas Nightlies e no DroidDeck.</string>
<string name="comp_nothing_new">Nada novo desde a última verificação.</string>
<string name="comp_import_wcp">Importar .wcp</string>
<string name="comp_restore_original">Restaurar o original deste Proton</string>
@@ -581,6 +583,16 @@
<string name="drawer_prev_page">Página anterior</string>
<string name="drawer_next_page">Próxima página</string>
<string name="drawer_hud">HUD de desempenho</string>
<string name="drawer_hud_fps">Taxa de quadros</string>
<string name="drawer_hud_battery">Temperatura da bateria</string>
<string name="drawer_hud_graph">Gráfico de desempenho</string>
<string name="drawer_hud_color">Cor</string>
<string name="drawer_hud_color_mint">Menta</string>
<string name="drawer_hud_color_white">Branco</string>
<string name="drawer_hud_color_sky">Céu</string>
<string name="drawer_hud_color_amber">Âmbar</string>
<string name="drawer_hud_color_violet">Violeta</string>
<string name="drawer_hud_opacity">Opacidade</string>
<string name="drawer_scaling">Modo de escala</string>
<string name="drawer_scaling_sharpness">Nitidez da escala</string>
<string name="drawer_effects">Efeitos de tela</string>
@@ -1780,7 +1792,8 @@
<string name="cmgr_original_kept">O original da versão instalada é mantido: é o caminho de volta.</string>
<string name="cmgr_not_stored">Não armazenado</string>
<string name="cmgr_deleted_original">Original do %1$s de %2$s excluído.</string>
<string name="cmgr_nightlies_only">Os downloads vêm só das versões Nightlies</string>
<string name="cmgr_nightlies_only">Os downloads vêm só das versões Nightlies e DroidDeck</string>
<string name="cmgr_nightly_replaced">Falha no download: esta versão nightly pode ter sido substituída por uma mais nova. Atualize a lista e tente de novo.</string>
<string name="cmgr_list_predates_checksums">Esta lista de pacotes é anterior às somas de verificação - atualize-a e tente de novo</string>
<string name="cmgr_checksum_mismatch">A soma de verificação não confere</string>
@@ -2036,6 +2049,9 @@
<string name="cloud_last_sync">Última sincronização: %1$s</string>
<string name="cloud_never">Ainda não sincronizado</string>
<string name="cloud_done">%1$d arquivos</string>
<string name="cloud_up_to_date">Já está atualizado</string>
<string name="cloud_signed_out">Entre na loja para sincronizar os saves</string>
<string name="cloud_not_synced">Os saves não foram sincronizados</string>
<string name="stores_eyebrow_installed">instalado</string>
<string name="stores_eyebrow_library">na sua biblioteca</string>
<string name="stores_eyebrow_store">loja</string>
@@ -2338,7 +2354,7 @@
<string name="touch_done">Concluído</string>
<string name="touch_save_failed">Não foi possível salvar o layout de toque</string>
<string name="touch_saved">Layout de toque salvo na Steam</string>
<string name="touch_app_id">App %1$d</string>
<string name="touch_app_id">App %1$s</string>
<string name="touch_label_hint">Rótulo (opcional)</string>
<string name="touch_icons_missing">Os ícones da Steam não foram encontrados</string>
<plurals name="touch_icons_found">
@@ -2431,6 +2447,15 @@
<string name="glasses_vr_fov">Campo de visão do SteamVR</string>
<string name="glasses_vr_fov_hint">Menor aproxima o SteamVR e preenche os óculos; maior mostra mais ao seu redor.</string>
<string name="glasses_playing">Jogando em %1$s</string>
<string name="glasses_phone_recenter">Recentralizar</string>
<string name="glasses_phone_steamvr_menu">Menu do SteamVR</string>
<string name="glasses_phone_switch_sticks">Analógicos: mãos ⇄ jogo</string>
<string name="glasses_phone_controllers">Controles: %1$s</string>
<string name="glasses_phone_keyboard">Teclado</string>
<string name="glasses_phone_session_menu">Menu da sessão</string>
<string name="glasses_phone_stop_steamvr">Parar o SteamVR</string>
<string name="glasses_phone_brightness">Brilho %1$d / %2$d</string>
<string name="glasses_phone_battery">Bateria %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Calibração do rastreamento</string>
<string name="glasses_calibration_hint">Reduz a deriva e alinha a referência de nível.</string>
<string name="glasses_calibration_saved_hint">A calibração salva é aplicada a estes óculos.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Un singur clic</string>
<string name="gesture_hold_delay">Durata până la menținere</string>
<string name="gesture_double_delay">Intervalul atingerii duble</string>
<string name="gesture_scope_game">Se aplică jocului curent</string>
<string name="gesture_scope_default">Setări implicite pentru toate jocurile</string>
<string name="gesture_reset">Restabilește setările originale ale gesturilor</string>
<string name="gesture_cancel">Anulează</string>
<string name="gesture_action">Alege acțiunea</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Rotița mouse-ului</string>
<string name="gesture_threshold">Pragul gesturilor: %1$d px</string>
<string name="gesture_debug">Arată gestul recunoscut</string>
<string name="gesture_editor_subtitle">Comenzi de mouse și tastatură organizate după gest</string>
<string name="gesture_tab_one">Un deget</string>
<string name="gesture_tab_two">Două degete</string>
<string name="gesture_tab_three">Trei degete</string>
<string name="gesture_tab_options">Opțiuni</string>
<string name="gesture_one_hint">Alege acțiunea unei atingeri, trageri sau mențineri.</string>
<string name="gesture_two_hint">Configurează deplasarea camerei, zoomul și clicurile secundare.</string>
<string name="gesture_three_hint">Păstrează scurtături suplimentare la îndemână.</string>
<string name="gesture_options_hint">Ajustează mișcarea, recunoașterea și feedbackul vizual.</string>
<string name="gesture_defaults">Valori implicite</string>
<string name="gesture_game">Acest joc</string>
<string name="gesture_use_defaults">Folosește valorile implicite</string>
<string name="gesture_inheriting">Se folosesc setările implicite. Editarea creează setări specifice jocului.</string>
<string name="gesture_save_changes">Salvează modificările</string>
<string name="gesture_close">Închide</string>
<string name="gesture_action_label">ACȚIUNE</string>
<string name="gesture_action_for">Pentru %1$s</string>
<string name="gesture_search_actions">Caută acțiuni de mouse sau taste</string>
<string name="gesture_clear_search">Șterge căutarea</string>
<string name="gesture_all_actions">Toate</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Tastatură numerică</string>
<string name="gesture_group_symbols">Simboluri</string>
<string name="gesture_movement">Mișcarea mouse-ului</string>
<string name="gesture_movement_hint">Tragerea directă urmărește poziția atingerii. Cea relativă urmărește mișcarea degetului și este utilă când jocul recentrează mouse-ul.</string>
<string name="gesture_middle_relative_hint">Deplasarea cu butonul din mijloc urmărește întotdeauna mișcarea degetului pentru a evita salturile cursorului.</string>
<string name="gesture_direct">Direct</string>
<string name="gesture_relative">Relativă</string>
<string name="gesture_recognition">Recunoașterea gesturilor</string>
<string name="gesture_threshold_hint">Parcurge această distanță înainte ca un gest cu două sau trei degete să devină deplasare sau zoom.</string>
<string name="gesture_feedback">Feedback vizual</string>
<string name="gesture_mouse_behavior">Comportamentul butonului de mouse</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -506,7 +506,9 @@
<string name="comp_delete_original_title">Ștergi acest original?</string>
<string name="comp_delete_original_body">Acest original %1$s este dintr-o versiune anterioară a %2$s. Originalul versiunii curente este păstrat mereu.</string>
<string name="comp_nightlies_count">Pe versiunile nightly · %1$d</string>
<string name="comp_refresh_to_list">Reîmprospătează pentru a lista pachetele de pe versiunile nightly.</string>
<string name="comp_channel_stable">Stabilă</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Reîmprospătează pentru a lista pachetele din Nightlies și DroidDeck.</string>
<string name="comp_nothing_new">Nimic nou de la ultima verificare.</string>
<string name="comp_import_wcp">Importă .wcp</string>
<string name="comp_restore_original">Restaurează originalul acestui Proton</string>
@@ -584,6 +586,16 @@
<string name="drawer_prev_page">Pagina anterioară</string>
<string name="drawer_next_page">Pagina următoare</string>
<string name="drawer_hud">HUD de performanță</string>
<string name="drawer_hud_fps">Rată de cadre</string>
<string name="drawer_hud_battery">Temperatură baterie</string>
<string name="drawer_hud_graph">Grafic de performanță</string>
<string name="drawer_hud_color">Culoare</string>
<string name="drawer_hud_color_mint">Mentă</string>
<string name="drawer_hud_color_white">Alb</string>
<string name="drawer_hud_color_sky">Cer</string>
<string name="drawer_hud_color_amber">Chihlimbariu</string>
<string name="drawer_hud_color_violet">Violet</string>
<string name="drawer_hud_opacity">Opacitate</string>
<string name="drawer_scaling">Mod de scalare</string>
<string name="drawer_scaling_sharpness">Claritatea scalării</string>
<string name="drawer_effects">Efecte de ecran</string>
@@ -1791,7 +1803,8 @@
<string name="cmgr_original_kept">Originalul versiunii instalate este păstrat: este calea de revenire.</string>
<string name="cmgr_not_stored">Nesalvat</string>
<string name="cmgr_deleted_original">S-a șters originalul %1$s al %2$s.</string>
<string name="cmgr_nightlies_only">Descărcările vin doar din versiunile Nightlies</string>
<string name="cmgr_nightlies_only">Descărcările vin doar din versiunile Nightlies și DroidDeck</string>
<string name="cmgr_nightly_replaced">Descărcarea a eșuat: această versiune nightly poate fi fost înlocuită cu una mai nouă. Reîmprospătează lista și încearcă din nou.</string>
<string name="cmgr_list_predates_checksums">Această listă de pachete e anterioară sumelor de control - reîmprospătează-o și încearcă din nou</string>
<string name="cmgr_checksum_mismatch">Sumă de control incorectă</string>
@@ -2047,6 +2060,9 @@
<string name="cloud_last_sync">Ultima sincronizare %1$s</string>
<string name="cloud_never">Nesincronizat încă</string>
<string name="cloud_done">%1$d fișiere</string>
<string name="cloud_up_to_date">Deja actualizat</string>
<string name="cloud_signed_out">Conectează-te la magazin pentru a sincroniza salvările</string>
<string name="cloud_not_synced">Salvările nu au fost sincronizate</string>
<string name="stores_eyebrow_installed">instalat</string>
<string name="stores_eyebrow_library">în biblioteca ta</string>
<string name="stores_eyebrow_store">magazin</string>
@@ -2352,7 +2368,7 @@
<string name="touch_done">Terminat</string>
<string name="touch_save_failed">Aranjamentul tactil nu a putut fi salvat</string>
<string name="touch_saved">Aranjamentul tactil a fost salvat în Steam</string>
<string name="touch_app_id">Aplicația %1$d</string>
<string name="touch_app_id">Aplicația %1$s</string>
<string name="touch_label_hint">Etichetă (opțional)</string>
<string name="touch_icons_missing">Pictogramele Steam nu au fost găsite</string>
<plurals name="touch_icons_found">
@@ -2445,6 +2461,15 @@
<string name="glasses_vr_fov">Câmp vizual SteamVR</string>
<string name="glasses_vr_fov_hint">Mai mic aduce SteamVR mai aproape și umple ochelarii; mai mare arată mai mult din jurul tău.</string>
<string name="glasses_playing">Se joacă pe %1$s</string>
<string name="glasses_phone_recenter">Recentrează</string>
<string name="glasses_phone_steamvr_menu">Meniu SteamVR</string>
<string name="glasses_phone_switch_sticks">Stickuri: mâini ⇄ joc</string>
<string name="glasses_phone_controllers">Controlere: %1$s</string>
<string name="glasses_phone_keyboard">Tastatură</string>
<string name="glasses_phone_session_menu">Meniul sesiunii</string>
<string name="glasses_phone_stop_steamvr">Oprește SteamVR</string>
<string name="glasses_phone_brightness">Luminozitate %1$d / %2$d</string>
<string name="glasses_phone_battery">Baterie %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Calibrarea urmăririi</string>
<string name="glasses_calibration_hint">Reduce deriva și aliniază referința de nivel.</string>
<string name="glasses_calibration_saved_hint">Calibrarea salvată se aplică acestor ochelari.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Один щелчок</string>
<string name="gesture_hold_delay">Задержка удержания</string>
<string name="gesture_double_delay">Интервал двойного касания</string>
<string name="gesture_scope_game">Применяется к текущей игре</string>
<string name="gesture_scope_default">Настройки по умолчанию для всех игр</string>
<string name="gesture_reset">Восстановить исходные настройки жестов</string>
<string name="gesture_cancel">Отмена</string>
<string name="gesture_action">Выберите действие</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Колесо мыши</string>
<string name="gesture_threshold">Порог жестов: %1$d пикс.</string>
<string name="gesture_debug">Показывать распознанный жест</string>
<string name="gesture_editor_subtitle">Управление мышью и клавиатурой по жестам</string>
<string name="gesture_tab_one">Один палец</string>
<string name="gesture_tab_two">Два пальца</string>
<string name="gesture_tab_three">Три пальца</string>
<string name="gesture_tab_options">Параметры</string>
<string name="gesture_one_hint">Выберите действие для касания, перетаскивания или удержания.</string>
<string name="gesture_two_hint">Настройте перемещение камеры, масштабирование и дополнительные щелчки.</string>
<string name="gesture_three_hint">Держите дополнительные команды под рукой.</string>
<string name="gesture_options_hint">Настройте движение, распознавание и визуальный отклик.</string>
<string name="gesture_defaults">По умолчанию</string>
<string name="gesture_game">Эта игра</string>
<string name="gesture_use_defaults">Использовать настройки по умолчанию</string>
<string name="gesture_inheriting">Используются настройки по умолчанию. Изменение создаст настройки для этой игры.</string>
<string name="gesture_save_changes">Сохранить изменения</string>
<string name="gesture_close">Закрыть</string>
<string name="gesture_action_label">ДЕЙСТВИЕ</string>
<string name="gesture_action_for">Для %1$s</string>
<string name="gesture_search_actions">Поиск действий мыши или клавиш клавиатуры</string>
<string name="gesture_clear_search">Очистить поиск</string>
<string name="gesture_all_actions">Все</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Цифровой блок</string>
<string name="gesture_group_symbols">Символы</string>
<string name="gesture_movement">Движение мыши</string>
<string name="gesture_movement_hint">Прямое перетаскивание следует позиции касания. Относительное следует движению пальца и полезно, когда игра возвращает мышь в центр.</string>
<string name="gesture_middle_relative_hint">Панорамирование средней кнопкой всегда следует движению пальца, чтобы избежать скачков курсора.</string>
<string name="gesture_direct">Прямой</string>
<string name="gesture_relative">Относительное</string>
<string name="gesture_recognition">Распознавание жестов</string>
<string name="gesture_threshold_hint">Пройдите это расстояние, прежде чем жест двумя или тремя пальцами станет перемещением камеры или масштабированием.</string>
<string name="gesture_feedback">Визуальный отклик</string>
<string name="gesture_mouse_behavior">Поведение кнопки мыши</string>
<string name="gesture_ms">%1$d мс</string>
+28 -3
View File
@@ -505,7 +505,9 @@
<string name="comp_delete_original_title">Удалить оригинальную версию?</string>
<string name="comp_delete_original_body">Эта оригинальная версия %1$s из более ранней сборки %2$s. Оригинальная версия текущей сборки всегда сохраняется.</string>
<string name="comp_nightlies_count">В Nightlies · %1$d</string>
<string name="comp_refresh_to_list">Обновите, чтобы увидеть пакеты в Nightlies.</string>
<string name="comp_channel_stable">Стабильная</string>
<string name="comp_channel_nightly">Ночная</string>
<string name="comp_refresh_to_list">Обновите, чтобы увидеть пакеты в Nightlies и DroidDeck.</string>
<string name="comp_nothing_new">С момента последней проверки нового нет.</string>
<string name="comp_import_wcp">Импорт .wcp</string>
<string name="comp_restore_original">Восстановить оригинальные файлы этого Proton</string>
@@ -583,6 +585,16 @@
<string name="drawer_prev_page">Предыдущая страница</string>
<string name="drawer_next_page">Следующая страница</string>
<string name="drawer_hud">HUD производительности</string>
<string name="drawer_hud_fps">Частота кадров</string>
<string name="drawer_hud_battery">Температура батареи</string>
<string name="drawer_hud_graph">График производительности</string>
<string name="drawer_hud_color">Цвет</string>
<string name="drawer_hud_color_mint">Мята</string>
<string name="drawer_hud_color_white">Белый</string>
<string name="drawer_hud_color_sky">Небесный</string>
<string name="drawer_hud_color_amber">Янтарный</string>
<string name="drawer_hud_color_violet">Фиолетовый</string>
<string name="drawer_hud_opacity">Непрозрачность</string>
<string name="drawer_scaling">Режим масштабирования</string>
<string name="drawer_scaling_sharpness">Резкость масштабирования</string>
<string name="drawer_effects">Экранные эффекты</string>
@@ -1809,7 +1821,8 @@
<string name="cmgr_original_kept">Оригинал установленной сборки сохраняется: через него можно вернуться.</string>
<string name="cmgr_not_stored">Не сохранено</string>
<string name="cmgr_deleted_original">Удален оригинал %2$s из сборки %1$s.</string>
<string name="cmgr_nightlies_only">Загрузки доступны только из выпусков Nightlies</string>
<string name="cmgr_nightlies_only">Загрузки доступны только из выпусков Nightlies и DroidDeck</string>
<string name="cmgr_nightly_replaced">Не удалось загрузить: возможно, эта ночная сборка заменена более новой. Обновите список и повторите попытку.</string>
<string name="cmgr_list_predates_checksums">Этот список пакетов создан до появления контрольных сумм — обновите его и повторите попытку</string>
<string name="cmgr_checksum_mismatch">Контрольная сумма не совпадает</string>
@@ -2065,6 +2078,9 @@
<string name="cloud_last_sync">Последняя синхронизация: %1$s</string>
<string name="cloud_never">Еще не синхронизировано</string>
<string name="cloud_done">Файлов: %1$d</string>
<string name="cloud_up_to_date">Уже актуально</string>
<string name="cloud_signed_out">Войдите в магазин, чтобы синхронизировать сохранения</string>
<string name="cloud_not_synced">Сохранения не синхронизированы</string>
<string name="stores_eyebrow_installed">установлено</string>
<string name="stores_eyebrow_library">в вашей библиотеке</string>
<string name="stores_eyebrow_store">магазин</string>
@@ -2369,7 +2385,7 @@
<string name="touch_done">Готово</string>
<string name="touch_save_failed">Не удалось сохранить сенсорную раскладку</string>
<string name="touch_saved">Сенсорная раскладка сохранена в Steam</string>
<string name="touch_app_id">Приложение %1$d</string>
<string name="touch_app_id">Приложение %1$s</string>
<string name="touch_label_hint">Подпись (необязательно)</string>
<string name="touch_icons_missing">Значки Steam не найдены</string>
<plurals name="touch_icons_found">
@@ -2464,6 +2480,15 @@
<string name="glasses_vr_fov">Поле зрения SteamVR</string>
<string name="glasses_vr_fov_hint">Меньше — SteamVR ближе и заполняет очки; больше — шире обзор вокруг.</string>
<string name="glasses_playing">Игра на %1$s</string>
<string name="glasses_phone_recenter">Перецентрировать</string>
<string name="glasses_phone_steamvr_menu">Меню SteamVR</string>
<string name="glasses_phone_switch_sticks">Стики: руки ⇄ игра</string>
<string name="glasses_phone_controllers">Контроллеры: %1$s</string>
<string name="glasses_phone_keyboard">Клавиатура</string>
<string name="glasses_phone_session_menu">Меню сеанса</string>
<string name="glasses_phone_stop_steamvr">Остановить SteamVR</string>
<string name="glasses_phone_brightness">Яркость %1$d / %2$d</string>
<string name="glasses_phone_battery">Батарея %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Калибровка отслеживания</string>
<string name="glasses_calibration_hint">Уменьшает дрейф и выравнивает опорный горизонт.</string>
<string name="glasses_calibration_saved_hint">Для этих очков применяется сохранённая калибровка.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Klicka en gång</string>
<string name="gesture_hold_delay">Fördröjning före hållning</string>
<string name="gesture_double_delay">Intervall för dubbeltryck</string>
<string name="gesture_scope_game">Gäller det aktuella spelet</string>
<string name="gesture_scope_default">Standardinställningar för alla spel</string>
<string name="gesture_reset">Återställ de ursprungliga gestinställningarna</string>
<string name="gesture_cancel">Avbryt</string>
<string name="gesture_action">Välj åtgärd</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Mushjul</string>
<string name="gesture_threshold">Gesttröskel: %1$d px</string>
<string name="gesture_debug">Visa identifierad gest</string>
<string name="gesture_editor_subtitle">Mus- och tangentbordsstyrning ordnad efter gest</string>
<string name="gesture_tab_one">Ett finger</string>
<string name="gesture_tab_two">Två fingrar</string>
<string name="gesture_tab_three">Tre fingrar</string>
<string name="gesture_tab_options">Alternativ</string>
<string name="gesture_one_hint">Välj vad ett tryck, drag eller håll ska göra.</string>
<string name="gesture_two_hint">Ställ in kamerapanorering, zoom och sekundära klick.</string>
<string name="gesture_three_hint">Ha fler genvägar inom räckhåll.</string>
<string name="gesture_options_hint">Justera rörelse, identifiering och visuell återkoppling.</string>
<string name="gesture_defaults">Standardvärden</string>
<string name="gesture_game">Det här spelet</string>
<string name="gesture_use_defaults">Använd standardinställningar</string>
<string name="gesture_inheriting">Standardinställningar används. Redigering skapar inställningar för spelet.</string>
<string name="gesture_save_changes">Spara ändringar</string>
<string name="gesture_close">Stäng</string>
<string name="gesture_action_label">ÅTGÄRD</string>
<string name="gesture_action_for">För %1$s</string>
<string name="gesture_search_actions">Sök efter musåtgärder eller tangenter</string>
<string name="gesture_clear_search">Rensa sökning</string>
<string name="gesture_all_actions">Alla</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Numeriskt tangentbord</string>
<string name="gesture_group_symbols">Symboler</string>
<string name="gesture_movement">Musrörelse</string>
<string name="gesture_movement_hint">Direkta drag följer pekpositionen. Relativa drag följer fingerrörelsen och är användbara när ett spel centrerar musen.</string>
<string name="gesture_middle_relative_hint">Panorering med musens mittknapp följer alltid fingerrörelsen för att undvika att pekaren hoppar.</string>
<string name="gesture_direct">Direkt</string>
<string name="gesture_relative">Relativ</string>
<string name="gesture_recognition">Gestidentifiering</string>
<string name="gesture_threshold_hint">Flytta fingrarna så här långt innan en gest med två eller tre fingrar blir panorering eller zoom.</string>
<string name="gesture_feedback">Visuell återkoppling</string>
<string name="gesture_mouse_behavior">Musknappens beteende</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -504,7 +504,9 @@
<string name="comp_delete_original_title">Ta bort det här originalet?</string>
<string name="comp_delete_original_body">Det här originalet av %1$s är från ett tidigare bygge av %2$s. Originalet från det aktuella bygget behålls alltid.</string>
<string name="comp_nightlies_count">I nattbyggena · %1$d</string>
<string name="comp_refresh_to_list">Uppdatera för att lista paket i nattbyggena.</string>
<string name="comp_channel_stable">Stabil</string>
<string name="comp_channel_nightly">Nattbygge</string>
<string name="comp_refresh_to_list">Uppdatera för att lista paket i Nightlies och DroidDeck.</string>
<string name="comp_nothing_new">Inget nytt sedan senaste kontrollen.</string>
<string name="comp_import_wcp">Importera .wcp</string>
<string name="comp_restore_original">Återställ den här Protonens original</string>
@@ -582,6 +584,16 @@
<string name="drawer_prev_page">Föregående sida</string>
<string name="drawer_next_page">Nästa sida</string>
<string name="drawer_hud">Prestanda-HUD</string>
<string name="drawer_hud_fps">Bildfrekvens</string>
<string name="drawer_hud_battery">Batteritemperatur</string>
<string name="drawer_hud_graph">Prestandagraf</string>
<string name="drawer_hud_color">Färg</string>
<string name="drawer_hud_color_mint">Mint</string>
<string name="drawer_hud_color_white">Vit</string>
<string name="drawer_hud_color_sky">Himmelsblå</string>
<string name="drawer_hud_color_amber">Amber</string>
<string name="drawer_hud_color_violet">Lila</string>
<string name="drawer_hud_opacity">Opacitet</string>
<string name="drawer_scaling">Skalningsläge</string>
<string name="drawer_scaling_sharpness">Skalningsskärpa</string>
<string name="drawer_effects">Skärmeffekter</string>
@@ -1770,7 +1782,8 @@
<string name="cmgr_original_kept">Den installerade versionens original behålls: det är vägen tillbaka.</string>
<string name="cmgr_not_stored">Inte sparad</string>
<string name="cmgr_deleted_original">Tog bort %1$s-originalet av %2$s.</string>
<string name="cmgr_nightlies_only">Nedladdningar kommer bara från Nightlies-utgåvorna</string>
<string name="cmgr_nightlies_only">Nedladdningar kommer bara från Nightlies- och DroidDeck-utgåvorna</string>
<string name="cmgr_nightly_replaced">Nedladdningen misslyckades: det här nattbygget kan ha ersatts av ett nyare. Uppdatera listan och försök igen.</string>
<string name="cmgr_list_predates_checksums">Den här paketlistan är från innan kontrollsummor fanns - uppdatera den och försök igen</string>
<string name="cmgr_checksum_mismatch">Kontrollsumman stämmer inte</string>
@@ -2026,6 +2039,9 @@
<string name="cloud_last_sync">Senast synkad %1$s</string>
<string name="cloud_never">Inte synkad än</string>
<string name="cloud_done">%1$d filer</string>
<string name="cloud_up_to_date">Redan uppdaterat</string>
<string name="cloud_signed_out">Logga in i butiken för att synkronisera sparfiler</string>
<string name="cloud_not_synced">Sparfilerna synkroniserades inte</string>
<string name="stores_eyebrow_installed">installerat</string>
<string name="stores_eyebrow_library">i ditt bibliotek</string>
<string name="stores_eyebrow_store">butik</string>
@@ -2329,7 +2345,7 @@
<string name="touch_done">Klar</string>
<string name="touch_save_failed">Det gick inte att spara pekskärmslayouten</string>
<string name="touch_saved">Pekskärmslayout sparad till Steam</string>
<string name="touch_app_id">App %1$d</string>
<string name="touch_app_id">App %1$s</string>
<string name="touch_label_hint">Etikett (valfritt)</string>
<string name="touch_icons_missing">Steams ikoner hittades inte</string>
<plurals name="touch_icons_found">
@@ -2420,6 +2436,15 @@
<string name="glasses_vr_fov">SteamVR-synfält</string>
<string name="glasses_vr_fov_hint">Lägre för SteamVR närmare och fyller glasögonen; högre visar mer runt dig.</string>
<string name="glasses_playing">Spelar på %1$s</string>
<string name="glasses_phone_recenter">Centrera om</string>
<string name="glasses_phone_steamvr_menu">SteamVR-meny</string>
<string name="glasses_phone_switch_sticks">Spakar: händer ⇄ spel</string>
<string name="glasses_phone_controllers">Handkontroller: %1$s</string>
<string name="glasses_phone_keyboard">Tangentbord</string>
<string name="glasses_phone_session_menu">Sessionsmeny</string>
<string name="glasses_phone_stop_steamvr">Stoppa SteamVR</string>
<string name="glasses_phone_brightness">Ljusstyrka %1$d / %2$d</string>
<string name="glasses_phone_battery">Batteri %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Spårningskalibrering</string>
<string name="glasses_calibration_hint">Minskar drift och justerar horisontreferensen.</string>
<string name="glasses_calibration_saved_hint">Sparad kalibrering används för de här glasögonen.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">คลิกหนึ่งครั้ง</string>
<string name="gesture_hold_delay">ระยะเวลาก่อนกดค้าง</string>
<string name="gesture_double_delay">ช่วงเวลาแตะสองครั้ง</string>
<string name="gesture_scope_game">ใช้กับเกมปัจจุบัน</string>
<string name="gesture_scope_default">การตั้งค่าเริ่มต้นสำหรับทุกเกม</string>
<string name="gesture_reset">คืนค่าการตั้งค่าท่าทางเดิม</string>
<string name="gesture_cancel">ยกเลิก</string>
<string name="gesture_action">เลือกการกระทำ</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">ล้อเมาส์</string>
<string name="gesture_threshold">เกณฑ์ท่าทาง: %1$d พิกเซล</string>
<string name="gesture_debug">แสดงท่าทางที่ตรวจพบ</string>
<string name="gesture_editor_subtitle">การควบคุมเมาส์และแป้นพิมพ์แยกตามท่าทาง</string>
<string name="gesture_tab_one">หนึ่งนิ้ว</string>
<string name="gesture_tab_two">สองนิ้ว</string>
<string name="gesture_tab_three">สามนิ้ว</string>
<string name="gesture_tab_options">ตัวเลือก</string>
<string name="gesture_one_hint">เลือกการทำงานเมื่อแตะ ลาก หรือกดค้าง</string>
<string name="gesture_two_hint">ตั้งค่าการเลื่อนกล้อง การซูม และการคลิกรอง</string>
<string name="gesture_three_hint">เข้าถึงทางลัดเพิ่มเติมได้ง่าย</string>
<string name="gesture_options_hint">ปรับการเคลื่อนไหว การตรวจจับ และการตอบสนองทางภาพ</string>
<string name="gesture_defaults">ค่าเริ่มต้น</string>
<string name="gesture_game">เกมนี้</string>
<string name="gesture_use_defaults">ใช้ค่าเริ่มต้น</string>
<string name="gesture_inheriting">กำลังใช้การตั้งค่าเริ่มต้น การแก้ไขจะสร้างการตั้งค่าเฉพาะเกม</string>
<string name="gesture_save_changes">บันทึกการเปลี่ยนแปลง</string>
<string name="gesture_close">ปิด</string>
<string name="gesture_action_label">การกระทำ</string>
<string name="gesture_action_for">สำหรับ %1$s</string>
<string name="gesture_search_actions">ค้นหาการกระทำของเมาส์หรือปุ่มแป้นพิมพ์</string>
<string name="gesture_clear_search">ล้างการค้นหา</string>
<string name="gesture_all_actions">ทั้งหมด</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">แป้นตัวเลข</string>
<string name="gesture_group_symbols">สัญลักษณ์</string>
<string name="gesture_movement">การเคลื่อนที่ของเมาส์</string>
<string name="gesture_movement_hint">การลากแบบตรงจะตามตำแหน่งที่สัมผัส ส่วนการลากแบบสัมพัทธ์จะตามการเคลื่อนนิ้ว เหมาะเมื่อเกมนำเมาส์กลับไปตรงกลาง</string>
<string name="gesture_middle_relative_hint">การเลื่อนมุมมองด้วยปุ่มเมาส์กลางจะตามการเคลื่อนนิ้วเสมอเพื่อไม่ให้เคอร์เซอร์กระโดด</string>
<string name="gesture_direct">โดยตรง</string>
<string name="gesture_relative">สัมพัทธ์</string>
<string name="gesture_recognition">การตรวจจับท่าทาง</string>
<string name="gesture_threshold_hint">เคลื่อนนิ้วตามระยะนี้ก่อนที่ท่าทางสองหรือสามนิ้วจะกลายเป็นการเลื่อนมุมมองหรือซูม</string>
<string name="gesture_feedback">การตอบสนองทางภาพ</string>
<string name="gesture_mouse_behavior">การทำงานของปุ่มเมาส์</string>
<string name="gesture_ms">%1$d มิลลิวินาที</string>
+28 -3
View File
@@ -502,7 +502,9 @@
<string name="comp_delete_original_title">ลบต้นฉบับนี้?</string>
<string name="comp_delete_original_body">ต้นฉบับ %1$s นี้มาจากบิลด์ก่อนหน้าของ %2$s ต้นฉบับของบิลด์ปัจจุบันจะถูกเก็บไว้เสมอ</string>
<string name="comp_nightlies_count">ใน Nightlies · %1$d</string>
<string name="comp_refresh_to_list">รีเฟรชเพื่อแสดงรายการแพ็กเกจใน Nightlies</string>
<string name="comp_channel_stable">เสถียร</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">รีเฟรชเพื่อแสดงรายการแพ็กเกจใน Nightlies และ DroidDeck</string>
<string name="comp_nothing_new">ไม่มีอะไรใหม่ตั้งแต่การตรวจสอบครั้งล่าสุด</string>
<string name="comp_import_wcp">นำเข้า .wcp</string>
<string name="comp_restore_original">คืนค่าต้นฉบับของ Proton นี้</string>
@@ -580,6 +582,16 @@
<string name="drawer_prev_page">หน้าก่อนหน้า</string>
<string name="drawer_next_page">หน้าถัดไป</string>
<string name="drawer_hud">HUD ประสิทธิภาพ</string>
<string name="drawer_hud_fps">อัตราเฟรม</string>
<string name="drawer_hud_battery">อุณหภูมิแบตเตอรี่</string>
<string name="drawer_hud_graph">กราฟประสิทธิภาพ</string>
<string name="drawer_hud_color">สี</string>
<string name="drawer_hud_color_mint">มิ้นต์</string>
<string name="drawer_hud_color_white">ขาว</string>
<string name="drawer_hud_color_sky">ฟ้าสดใส</string>
<string name="drawer_hud_color_amber">อำพัน</string>
<string name="drawer_hud_color_violet">ม่วง</string>
<string name="drawer_hud_opacity">ความโปร่งใส</string>
<string name="drawer_scaling">โหมดการปรับขนาด</string>
<string name="drawer_scaling_sharpness">ความคมชัดของการปรับขนาด</string>
<string name="drawer_effects">เอฟเฟกต์หน้าจอ</string>
@@ -1749,7 +1761,8 @@
<string name="cmgr_original_kept">ต้นฉบับของบิลด์ที่ติดตั้งไว้ถูกเก็บไว้: นี่คือทางกลับ</string>
<string name="cmgr_not_stored">ไม่ได้บันทึกไว้</string>
<string name="cmgr_deleted_original">ลบต้นฉบับ %1$s ของ %2$s แล้ว</string>
<string name="cmgr_nightlies_only">การดาวน์โหลดมาจากรุ่นที่เผยแพร่ใน Nightlies เท่านั้น</string>
<string name="cmgr_nightlies_only">การดาวน์โหลดมาจากรุ่นที่เผยแพร่ใน Nightlies และ DroidDeck เท่านั้น</string>
<string name="cmgr_nightly_replaced">ดาวน์โหลดไม่สำเร็จ: บิลด์ nightly นี้อาจถูกแทนที่ด้วยบิลด์ที่ใหม่กว่า รีเฟรชรายการแล้วลองอีกครั้ง</string>
<string name="cmgr_list_predates_checksums">รายการแพ็กเกจนี้เก่ากว่าระบบค่าตรวจสอบ - รีเฟรชแล้วลองใหม่</string>
<string name="cmgr_checksum_mismatch">ค่าตรวจสอบไม่ตรงกัน</string>
@@ -2005,6 +2018,9 @@
<string name="cloud_last_sync">ซิงค์ล่าสุด %1$s</string>
<string name="cloud_never">ยังไม่ได้ซิงค์</string>
<string name="cloud_done">%1$d ไฟล์</string>
<string name="cloud_up_to_date">อัปเดตแล้ว</string>
<string name="cloud_signed_out">ลงชื่อเข้าใช้ร้านค้าเพื่อซิงค์เซฟ</string>
<string name="cloud_not_synced">เซฟไม่ได้ซิงค์</string>
<string name="stores_eyebrow_installed">ติดตั้งแล้ว</string>
<string name="stores_eyebrow_library">อยู่ในไลบรารีของคุณ</string>
<string name="stores_eyebrow_store">สโตร์</string>
@@ -2306,7 +2322,7 @@
<string name="touch_done">เสร็จสิ้น</string>
<string name="touch_save_failed">ไม่สามารถบันทึกเค้าโครงสัมผัสได้</string>
<string name="touch_saved">บันทึกเค้าโครงสัมผัสลง Steam แล้ว</string>
<string name="touch_app_id">แอป %1$d</string>
<string name="touch_app_id">แอป %1$s</string>
<string name="touch_label_hint">ป้ายชื่อ (ไม่บังคับ)</string>
<string name="touch_icons_missing">ไม่พบไอคอนของ Steam</string>
<plurals name="touch_icons_found">
@@ -2395,6 +2411,15 @@
<string name="glasses_vr_fov">ขอบเขตการมองเห็นของ SteamVR</string>
<string name="glasses_vr_fov_hint">ค่าต่ำจะดึง SteamVR เข้ามาใกล้และเต็มแว่นตา ค่าสูงจะแสดงสิ่งรอบตัวคุณได้มากขึ้น</string>
<string name="glasses_playing">กำลังเล่นบน %1$s</string>
<string name="glasses_phone_recenter">จัดกึ่งกลางใหม่</string>
<string name="glasses_phone_steamvr_menu">เมนู SteamVR</string>
<string name="glasses_phone_switch_sticks">สติ๊ก: มือ ⇄ เกม</string>
<string name="glasses_phone_controllers">คอนโทรลเลอร์: %1$s</string>
<string name="glasses_phone_keyboard">แป้นพิมพ์</string>
<string name="glasses_phone_session_menu">เมนูเซสชัน</string>
<string name="glasses_phone_stop_steamvr">หยุด SteamVR</string>
<string name="glasses_phone_brightness">ความสว่าง %1$d / %2$d</string>
<string name="glasses_phone_battery">แบตเตอรี่ %1$d%% · %2$d °C</string>
<string name="glasses_calibration">การปรับเทียบการติดตาม</string>
<string name="glasses_calibration_hint">ลดการดริฟต์และปรับแนวระดับอ้างอิงให้ตรง</string>
<string name="glasses_calibration_saved_hint">ใช้การปรับเทียบที่บันทึกไว้กับแว่นตานี้แล้ว</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Bir kez tıkla</string>
<string name="gesture_hold_delay">Basılı tutma gecikmesi</string>
<string name="gesture_double_delay">Çift dokunma aralığı</string>
<string name="gesture_scope_game">Geçerli oyuna uygulanır</string>
<string name="gesture_scope_default">Tüm oyunlar için varsayılan ayarlar</string>
<string name="gesture_reset">İlk hareket ayarlarına sıfırla</string>
<string name="gesture_cancel">İptal</string>
<string name="gesture_action">Eylem seç</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Fare tekerleği</string>
<string name="gesture_threshold">Hareket eşiği: %1$d piksel</string>
<string name="gesture_debug">Algılanan hareketi göster</string>
<string name="gesture_editor_subtitle">Hareketlere göre düzenlenmiş fare ve klavye kontrolleri</string>
<string name="gesture_tab_one">Tek parmak</string>
<string name="gesture_tab_two">İki parmak</string>
<string name="gesture_tab_three">Üç parmak</string>
<string name="gesture_tab_options">Seçenekler</string>
<string name="gesture_one_hint">Dokunma, sürükleme veya basılı tutmanın ne yapacağını seçin.</string>
<string name="gesture_two_hint">Kamera kaydırmasını, yakınlaştırmayı ve ikincil tıklamaları ayarlayın.</string>
<string name="gesture_three_hint">Ek kısayolları elinizin altında tutun.</string>
<string name="gesture_options_hint">Hareketi, algılamayı ve görsel geri bildirimi ayarlayın.</string>
<string name="gesture_defaults">Varsayılanlar</string>
<string name="gesture_game">Bu oyun</string>
<string name="gesture_use_defaults">Varsayılanları kullan</string>
<string name="gesture_inheriting">Varsayılan ayarlar kullanılıyor. Düzenleme, oyuna özel ayarlar oluşturur.</string>
<string name="gesture_save_changes">Değişiklikleri kaydet</string>
<string name="gesture_close">Kapat</string>
<string name="gesture_action_label">EYLEM</string>
<string name="gesture_action_for">%1$s için</string>
<string name="gesture_search_actions">Fare eylemlerini veya klavye tuşlarını ara</string>
<string name="gesture_clear_search">Aramayı temizle</string>
<string name="gesture_all_actions">Tümü</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Sayısal tuş takımı</string>
<string name="gesture_group_symbols">Semboller</string>
<string name="gesture_movement">Fare hareketi</string>
<string name="gesture_movement_hint">Doğrudan sürükleme dokunma konumunu izler. Göreli sürükleme parmak hareketini izler ve oyun fareyi merkeze aldığında kullanışlıdır.</string>
<string name="gesture_middle_relative_hint">Orta fare düğmesiyle kaydırma, imlecin sıçramasını önlemek için her zaman parmak hareketini izler.</string>
<string name="gesture_direct">Doğrudan</string>
<string name="gesture_relative">Göreli</string>
<string name="gesture_recognition">Hareket algılama</string>
<string name="gesture_threshold_hint">İki veya üç parmak hareketinin kaydırma ya da yakınlaştırmaya dönüşmesi için bu mesafeyi aşın.</string>
<string name="gesture_feedback">Görsel geri bildirim</string>
<string name="gesture_mouse_behavior">Fare düğmesi davranışı</string>
<string name="gesture_ms">%1$d ms</string>
+28 -3
View File
@@ -501,7 +501,9 @@
<string name="comp_delete_original_title">Bu orijinal silinsin mi?</string>
<string name="comp_delete_original_body">Bu %1$s orijinali, %2$s sürümünün önceki bir derlemesine ait. Geçerli derlemenin orijinali her zaman saklanır.</string>
<string name="comp_nightlies_count">Nightlies içinde · %1$d</string>
<string name="comp_refresh_to_list">Nightlies paketlerini listelemek için yenileyin.</string>
<string name="comp_channel_stable">Kararlı</string>
<string name="comp_channel_nightly">Nightly</string>
<string name="comp_refresh_to_list">Nightlies ve DroidDeck paketlerini listelemek için yenileyin.</string>
<string name="comp_nothing_new">Son kontrolden beri yeni bir şey yok.</string>
<string name="comp_import_wcp">.wcp içe aktar</string>
<string name="comp_restore_original">Bu Proton\'un orijinalini geri yükle</string>
@@ -579,6 +581,16 @@
<string name="drawer_prev_page">Önceki sayfa</string>
<string name="drawer_next_page">Sonraki sayfa</string>
<string name="drawer_hud">Performans HUD\'u</string>
<string name="drawer_hud_fps">Kare hızı</string>
<string name="drawer_hud_battery">Pil sıcaklığı</string>
<string name="drawer_hud_graph">Performans grafiği</string>
<string name="drawer_hud_color">Renk</string>
<string name="drawer_hud_color_mint">Nane</string>
<string name="drawer_hud_color_white">Beyaz</string>
<string name="drawer_hud_color_sky">Gök mavisi</string>
<string name="drawer_hud_color_amber">Kehribar</string>
<string name="drawer_hud_color_violet">Mor</string>
<string name="drawer_hud_opacity">Opaklık</string>
<string name="drawer_scaling">Ölçekleme modu</string>
<string name="drawer_scaling_sharpness">Ölçekleme keskinliği</string>
<string name="drawer_effects">Ekran efektleri</string>
@@ -1759,7 +1771,8 @@
<string name="cmgr_original_kept">Yüklü derlemenin orijinali saklanır: geri dönüş yolu budur.</string>
<string name="cmgr_not_stored">Saklanmıyor</string>
<string name="cmgr_deleted_original">%2$s\'nin %1$s orijinali silindi.</string>
<string name="cmgr_nightlies_only">İndirmeler yalnızca Nightlies yayınlarından gelir</string>
<string name="cmgr_nightlies_only">İndirmeler yalnızca Nightlies ve DroidDeck yayınlarından gelir</string>
<string name="cmgr_nightly_replaced">İndirme başarısız: bu nightly derleme daha yenisiyle değiştirilmiş olabilir. Listeyi yenileyip tekrar deneyin.</string>
<string name="cmgr_list_predates_checksums">Bu paket listesi sağlama toplamlarından önceki bir tarihe ait - yenileyip yeniden deneyin</string>
<string name="cmgr_checksum_mismatch">Sağlama toplamı uyuşmuyor</string>
@@ -2015,6 +2028,9 @@
<string name="cloud_last_sync">Son eşitleme %1$s</string>
<string name="cloud_never">Henüz eşitlenmedi</string>
<string name="cloud_done">%1$d dosya</string>
<string name="cloud_up_to_date">Zaten güncel</string>
<string name="cloud_signed_out">Kayıtları eşitlemek için mağazada oturum açın</string>
<string name="cloud_not_synced">Kayıtlar eşitlenmedi</string>
<string name="stores_eyebrow_installed">yüklü</string>
<string name="stores_eyebrow_library">kütüphanenizde</string>
<string name="stores_eyebrow_store">mağaza</string>
@@ -2315,7 +2331,7 @@
<string name="touch_done">Bitti</string>
<string name="touch_save_failed">Dokunmatik düzen kaydedilemedi</string>
<string name="touch_saved">Dokunmatik düzen Steam\'e kaydedildi</string>
<string name="touch_app_id">Uygulama %1$d</string>
<string name="touch_app_id">Uygulama %1$s</string>
<string name="touch_label_hint">Etiket (isteğe bağlı)</string>
<string name="touch_icons_missing">Steam\'in simgeleri bulunamadı</string>
<plurals name="touch_icons_found">
@@ -2406,6 +2422,15 @@
<string name="glasses_vr_fov">SteamVR görüş alanı</string>
<string name="glasses_vr_fov_hint">Düşük değer SteamVR\'ı yaklaştırır ve gözlüğü doldurur; yüksek değer çevrenizi daha çok gösterir.</string>
<string name="glasses_playing">%1$s ile oynanıyor</string>
<string name="glasses_phone_recenter">Yeniden ortala</string>
<string name="glasses_phone_steamvr_menu">SteamVR menüsü</string>
<string name="glasses_phone_switch_sticks">Çubuklar: eller ⇄ oyun</string>
<string name="glasses_phone_controllers">Kumandalar: %1$s</string>
<string name="glasses_phone_keyboard">Klavye</string>
<string name="glasses_phone_session_menu">Oturum menüsü</string>
<string name="glasses_phone_stop_steamvr">SteamVR’ı durdur</string>
<string name="glasses_phone_brightness">Parlaklık %1$d / %2$d</string>
<string name="glasses_phone_battery">Pil %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Takip kalibrasyonu</string>
<string name="glasses_calibration_hint">Kaymayı azaltır ve yatay düzlem referansını hizalar.</string>
<string name="glasses_calibration_saved_hint">Kayıtlı kalibrasyon bu gözlüğe uygulanır.</string>
-12
View File
@@ -18,8 +18,6 @@
<string name="gesture_click_once">Одне клацання</string>
<string name="gesture_hold_delay">Затримка утримання</string>
<string name="gesture_double_delay">Інтервал подвійного дотику</string>
<string name="gesture_scope_game">Застосовується до поточної гри</string>
<string name="gesture_scope_default">Типові налаштування для всіх ігор</string>
<string name="gesture_reset">Відновити початкові налаштування жестів</string>
<string name="gesture_cancel">Скасувати</string>
<string name="gesture_action">Виберіть дію</string>
@@ -37,23 +35,16 @@
<string name="gesture_scroll">Коліщатко миші</string>
<string name="gesture_threshold">Поріг жестів: %1$d пікс.</string>
<string name="gesture_debug">Показувати розпізнаний жест</string>
<string name="gesture_editor_subtitle">Керування мишею та клавіатурою за жестами</string>
<string name="gesture_tab_one">Один палець</string>
<string name="gesture_tab_two">Два пальці</string>
<string name="gesture_tab_three">Три пальці</string>
<string name="gesture_tab_options">Параметри</string>
<string name="gesture_one_hint">Виберіть дію для дотику, перетягування чи утримання.</string>
<string name="gesture_two_hint">Налаштуйте переміщення камери, масштабування та додаткові клацання.</string>
<string name="gesture_three_hint">Тримайте додаткові команди під рукою.</string>
<string name="gesture_options_hint">Налаштуйте рух, розпізнавання та візуальний відгук.</string>
<string name="gesture_defaults">Стандартні</string>
<string name="gesture_game">Ця гра</string>
<string name="gesture_use_defaults">Використовувати типові</string>
<string name="gesture_inheriting">Використовуються типові налаштування. Зміна створить налаштування для цієї гри.</string>
<string name="gesture_save_changes">Зберегти зміни</string>
<string name="gesture_close">Закрити</string>
<string name="gesture_action_label">ДІЯ</string>
<string name="gesture_action_for">Для %1$s</string>
<string name="gesture_search_actions">Пошук дій миші або клавіш клавіатури</string>
<string name="gesture_clear_search">Очистити пошук</string>
<string name="gesture_all_actions">Усі</string>
@@ -68,12 +59,9 @@
<string name="gesture_group_numpad">Цифровий блок</string>
<string name="gesture_group_symbols">Символи</string>
<string name="gesture_movement">Рух миші</string>
<string name="gesture_movement_hint">Пряме перетягування відповідає положенню дотику. Відносне відповідає руху пальця й корисне, коли гра повертає мишу до центру.</string>
<string name="gesture_middle_relative_hint">Переміщення середньою кнопкою завжди відповідає руху пальця, щоб уникнути стрибків курсора.</string>
<string name="gesture_direct">Пряме</string>
<string name="gesture_relative">Відносний</string>
<string name="gesture_recognition">Розпізнавання жестів</string>
<string name="gesture_threshold_hint">Подолайте цю відстань, перш ніж жест двома чи трьома пальцями стане переміщенням камери або масштабуванням.</string>
<string name="gesture_feedback">Візуальний відгук</string>
<string name="gesture_mouse_behavior">Поведінка кнопки миші</string>
<string name="gesture_ms">%1$d мс</string>
+28 -3
View File
@@ -508,7 +508,9 @@
<string name="comp_delete_original_title">Видалити цей оригінал?</string>
<string name="comp_delete_original_body">Цей оригінал %1$s походить із попередньої збірки %2$s. Оригінал поточної збірки зберігається завжди.</string>
<string name="comp_nightlies_count">У нічних збірках · %1$d</string>
<string name="comp_refresh_to_list">Оновіть, щоб побачити пакети з нічних збірок.</string>
<string name="comp_channel_stable">Стабільна</string>
<string name="comp_channel_nightly">Нічна</string>
<string name="comp_refresh_to_list">Оновіть, щоб побачити пакети з Nightlies і DroidDeck.</string>
<string name="comp_nothing_new">Нічого нового з часу останньої перевірки.</string>
<string name="comp_import_wcp">Імпортувати .wcp</string>
<string name="comp_restore_original">Відновити оригінал цього Proton</string>
@@ -586,6 +588,16 @@
<string name="drawer_prev_page">Попередня сторінка</string>
<string name="drawer_next_page">Наступна сторінка</string>
<string name="drawer_hud">HUD продуктивності</string>
<string name="drawer_hud_fps">Частота кадрів</string>
<string name="drawer_hud_battery">Температура батареї</string>
<string name="drawer_hud_graph">Графік продуктивності</string>
<string name="drawer_hud_color">Колір</string>
<string name="drawer_hud_color_mint">М\'ята</string>
<string name="drawer_hud_color_white">Білий</string>
<string name="drawer_hud_color_sky">Небесний</string>
<string name="drawer_hud_color_amber">Бурштиновий</string>
<string name="drawer_hud_color_violet">Фіолетовий</string>
<string name="drawer_hud_opacity">Непрозорість</string>
<string name="drawer_scaling">Режим масштабування</string>
<string name="drawer_scaling_sharpness">Чіткість масштабування</string>
<string name="drawer_effects">Ефекти екрана</string>
@@ -1812,7 +1824,8 @@
<string name="cmgr_original_kept">Оригінал встановленої збірки збережено: це шлях назад.</string>
<string name="cmgr_not_stored">Не збережено</string>
<string name="cmgr_deleted_original">Видалено оригінал %2$s зі збірки %1$s.</string>
<string name="cmgr_nightlies_only">Завантаження надходять лише з випусків Nightlies</string>
<string name="cmgr_nightlies_only">Завантаження надходять лише з випусків Nightlies і DroidDeck</string>
<string name="cmgr_nightly_replaced">Не вдалося завантажити: можливо, цю нічну збірку замінено новішою. Оновіть список і спробуйте ще раз.</string>
<string name="cmgr_list_predates_checksums">Цей список пакетів створено до появи контрольних сум - оновіть його і спробуйте ще раз</string>
<string name="cmgr_checksum_mismatch">Контрольна сума не збіглася</string>
@@ -2068,6 +2081,9 @@
<string name="cloud_last_sync">Остання синхронізація %1$s</string>
<string name="cloud_never">Ще не синхронізовано</string>
<string name="cloud_done">%1$d файлів</string>
<string name="cloud_up_to_date">Уже актуально</string>
<string name="cloud_signed_out">Увійдіть у магазин, щоб синхронізувати збереження</string>
<string name="cloud_not_synced">Збереження не синхронізовано</string>
<string name="stores_eyebrow_installed">встановлено</string>
<string name="stores_eyebrow_library">у вашій бібліотеці</string>
<string name="stores_eyebrow_store">магазин</string>
@@ -2375,7 +2391,7 @@
<string name="touch_done">Готово</string>
<string name="touch_save_failed">Не вдалося зберегти сенсорну розкладку</string>
<string name="touch_saved">Сенсорну розкладку збережено в Steam</string>
<string name="touch_app_id">Застосунок %1$d</string>
<string name="touch_app_id">Застосунок %1$s</string>
<string name="touch_label_hint">Підпис (необов\'язково)</string>
<string name="touch_icons_missing">Значки Steam не знайдено</string>
<plurals name="touch_icons_found">
@@ -2470,6 +2486,15 @@
<string name="glasses_vr_fov">Поле зору SteamVR</string>
<string name="glasses_vr_fov_hint">Нижче значення наближає SteamVR і заповнює окуляри; вище — показує більше навколо вас.</string>
<string name="glasses_playing">Гра на %1$s</string>
<string name="glasses_phone_recenter">Перецентрувати</string>
<string name="glasses_phone_steamvr_menu">Меню SteamVR</string>
<string name="glasses_phone_switch_sticks">Стіки: руки ⇄ гра</string>
<string name="glasses_phone_controllers">Контролери: %1$s</string>
<string name="glasses_phone_keyboard">Клавіатура</string>
<string name="glasses_phone_session_menu">Меню сеансу</string>
<string name="glasses_phone_stop_steamvr">Зупинити SteamVR</string>
<string name="glasses_phone_brightness">Яскравість %1$d / %2$d</string>
<string name="glasses_phone_battery">Акумулятор %1$d%% · %2$d °C</string>
<string name="glasses_calibration">Калібрування відстеження</string>
<string name="glasses_calibration_hint">Зменшує дрейф і вирівнює опорний горизонт.</string>
<string name="glasses_calibration_saved_hint">До цих окулярів застосовано збережене калібрування.</string>
Loaded 100 of 162 files, more files were not shown because too many files have changed in this diff. Show more