mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-13 03:51:10 +00:00
* fix(input): restore on-screen touch behaviour: slide between buttons, mouse pass-through, keyboard on release, overlay haptics, stick reach and hit areas * fix(dual-screen): restore second-screen bars, swapped Terminal and Deck panel tabs * fix(input): fit on-screen layouts to the real view size, cutout, Steam + QAM mode and unfolded strip * fix(input): unfolded strip keeps press haptics * fix(input): restore layout import/export, element editor rows and layout tools Bring back .icp layout import and export on the saved layouts page, the per-element image, opacity and label controls, a uniform size slider and reset positions in the layout editor, and non-destructive Steam, QAM and keyboard button toggles stored on the layout style. Remove strings left unused by the input profile unification. * fix(input): keep hit slack to gamepad-shaped buttons and fit touch tests to saved layout geometry * fix(input): button size regenerates the gamepad and scales spacing A generated gamepad now stores its button size and is regenerated at that size, so spacing follows the radius and the layout keeps regenerating on rotation. Edited layouts scale positions from their anchor edge or centre so gaps grow and shrink with the controls. * fix(input): button size rescales moved gamepads around the generator Gamepad layouts that no longer match the generated positions exactly were scaled element by element from screen thirds, which split the face buttons and D-pad across anchors. Gamepad controls now take the generator's positions at the new size plus each control's own offset from the generated position, so groups keep their shape and spacing.
This commit is contained in:
1 parent
a33954b8bd
commit
8fa30b99f9
70 files changed
+2383
-1789
No files matched your search
@@ -79,6 +79,7 @@ import com.droiddeck.launcher.input.OnScreenControls
|
||||
import com.droiddeck.launcher.input.InputRouter
|
||||
import com.droiddeck.launcher.input.InputOutput
|
||||
import com.droiddeck.launcher.input.InputCommand
|
||||
import com.droiddeck.launcher.input.quickButton
|
||||
import com.droiddeck.launcher.input.InputProfiles
|
||||
import com.droiddeck.launcher.input.InputProfile
|
||||
import com.droiddeck.launcher.input.InputAction
|
||||
@@ -160,6 +161,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
private var unfoldedControls by mutableStateOf(false)
|
||||
private var unfoldedControlsWithController by mutableStateOf(false)
|
||||
private var adaptiveSticks by mutableStateOf<Boolean?>(null)
|
||||
private var quickButtons by mutableStateOf<Map<InputCommand, Boolean>>(emptyMap())
|
||||
private var picturePosition by mutableStateOf("center")
|
||||
|
||||
private fun applyGameAlignment() {
|
||||
@@ -173,7 +175,8 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
}
|
||||
WaylandCompositor.nativeSetScaleMode(SCALE_FIT, alignment)
|
||||
}
|
||||
private var unfoldedPanel by mutableStateOf<com.droiddeck.launcher.ui.InputSurfaceView?>(null)
|
||||
private var unfoldedPanel by mutableStateOf<OnScreenControls?>(null)
|
||||
private var unfoldedColumn: android.widget.LinearLayout? = null
|
||||
private lateinit var sessionRoot: FrameLayout
|
||||
private var inputRouter: InputRouter? = null
|
||||
private var physicalInputBindings: com.droiddeck.launcher.input.PhysicalInputBindings? = null
|
||||
@@ -1416,6 +1419,14 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
primaryInputLayout?.let { com.droiddeck.launcher.input.InputLibraries.setAdaptiveSticks(this@SessionActivity, it.id, on) }
|
||||
refreshInputProfile()
|
||||
},
|
||||
quickButtons = quickButtons.takeIf {
|
||||
unfoldedPanel != null || oscMode != SessionPrefs.OSC_NEVER && !steamTouchInUse
|
||||
}.orEmpty(),
|
||||
onQuickButton = { button, on ->
|
||||
primaryInputLayout?.let { com.droiddeck.launcher.input.InputLibraries.setQuickButton(this@SessionActivity, it.id, button, on) }
|
||||
refreshInputProfile()
|
||||
updateOnScreenControls()
|
||||
},
|
||||
unfoldedControlsWithController = unfoldedControlsWithController,
|
||||
onUnfoldedControlsWithController = ::chooseUnfoldedControlsWithController,
|
||||
onBackground = { drawerOpen = false; pip.background(); moveTaskToBack(true) },
|
||||
@@ -2813,7 +2824,8 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
}
|
||||
return onScreenControls?.let { takes(it, it::takesTouchAt) } == true ||
|
||||
steamTouchControls?.let { takes(it, it::takesTouchAt) } == true ||
|
||||
unfoldedPanel?.let { takes(it, it::takesTouchAt) } == true
|
||||
unfoldedPanel?.let { takes(it, it::takesTouchAt) } == true ||
|
||||
unfoldedColumn?.getChildAt(0)?.let { takes(it) { _, _ -> true } } == true
|
||||
}
|
||||
|
||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||
@@ -3401,6 +3413,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
DroidDeckTheme { SessionMenu(docked = true) }
|
||||
},
|
||||
onSwap = if (bottomSwapAvailable && com.droiddeck.launcher.input.DualScreen.builtIn(target)) ({ putGameOnBottom(true) }) else null,
|
||||
onDeckPanel = ::selectDeckPanel,
|
||||
dashboard = if (bottomPages().isEmpty()) null else ({
|
||||
DroidDeckTheme {
|
||||
BottomDashboard(
|
||||
@@ -3511,10 +3524,11 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
private fun refreshInputProfile() {
|
||||
val library = com.droiddeck.launcher.input.InputLibraries.read(this)
|
||||
val desktop = loadingMode() == SessionService.MODE_DESKTOP
|
||||
inputProfile = library.compileActive(desktop, secondScreenMode.bindings)
|
||||
inputProfile = library.compileActive(desktop, secondScreenMode.panel(this))
|
||||
primaryInputLayout = library.activeLayout(desktop, InputRole.PRIMARY)
|
||||
adaptiveSticks = primaryInputLayout?.adaptiveSticks
|
||||
secondaryInputLayout = library.panelLayout(desktop, secondScreenMode.bindings)
|
||||
quickButtons = primaryInputLayout?.takeIf { it.editable }?.let { l -> l.quickButtons.associateWith { it !in l.style.hidden } }.orEmpty()
|
||||
secondaryInputLayout = library.panelLayout(desktop, secondScreenMode.panel(this))
|
||||
inputUsesLocalActions = InputControl.padControls.any { inputProfile.action(InputRole.PHYSICAL, it) !is InputAction.Native }
|
||||
inputUsesPointer = inputProfile.bindings.values.any { bindings ->
|
||||
bindings.values.any { it is InputAction.Pointer || it is InputAction.MouseButton || it is InputAction.Scroll }
|
||||
@@ -3527,8 +3541,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
DeckControls.refresh()
|
||||
onScreenControls?.updateLayout(primaryInputLayout)
|
||||
bottomInputControls?.updateLayout(primaryInputLayout)
|
||||
unfoldedPanel?.updateCustomLayout(primaryInputLayout?.elements.orEmpty())
|
||||
unfoldedPanel?.updateStyle(primaryInputLayout?.style ?: com.droiddeck.launcher.input.InputSurfaceStyle())
|
||||
unfoldedPanel?.updateLayout(primaryInputLayout)
|
||||
updateOnScreenPad()
|
||||
secondScreenPresentation?.refreshControls()
|
||||
}
|
||||
@@ -3537,6 +3550,13 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
if (SessionState.mode == SessionService.MODE_STEAM) padBridge?.triggerQam()
|
||||
}
|
||||
|
||||
private fun selectDeckPanel(panel: com.droiddeck.launcher.input.DeckPanel) {
|
||||
if (SessionPrefs.deckPanel(this) == panel) return
|
||||
releasePads()
|
||||
SessionPrefs.setDeckPanel(this, panel)
|
||||
refreshInputProfile()
|
||||
}
|
||||
|
||||
private fun chooseUnfoldedControls(on: Boolean) {
|
||||
SessionPrefs.setUnfoldedControls(this, on)
|
||||
unfoldedControls = on
|
||||
@@ -3573,19 +3593,35 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
Log.i(TAG, if (wanted) "unfolded controls: game ${width}x$gameHeight, controls ${width}x${height - gameHeight}"
|
||||
else "unfolded controls: game full screen")
|
||||
}
|
||||
val dock = com.droiddeck.launcher.input.OnScreenLayout.Dock(!com.droiddeck.launcher.session.SessionDisplay.foldable(this), SessionState.deckPad)
|
||||
var panel = unfoldedPanel
|
||||
if (!wanted) {
|
||||
if (panel != null) { sessionRoot.removeView(panel); unfoldedPanel = null; updateOnScreenControls() }
|
||||
return
|
||||
if (panel != null && (!wanted || panel.dock != dock)) {
|
||||
sessionRoot.removeView(unfoldedColumn)
|
||||
unfoldedColumn = null
|
||||
unfoldedPanel = null
|
||||
panel = null
|
||||
if (!wanted) updateOnScreenControls()
|
||||
}
|
||||
if (!wanted) return
|
||||
if (panel == null) {
|
||||
panel = com.droiddeck.launcher.ui.InputSurfaceView(this, padBridge, primaryInputLayout?.elements.orEmpty(), InputRole.PRIMARY,
|
||||
primaryInputLayout?.style ?: com.droiddeck.launcher.input.InputSurfaceStyle())
|
||||
sessionRoot.addView(panel, sessionRoot.indexOfChild(surfaceView) + 1)
|
||||
panel = OnScreenControls(this, padBridge, dock).also { it.updateLayout(primaryInputLayout) }
|
||||
val column = android.widget.LinearLayout(this).apply {
|
||||
orientation = android.widget.LinearLayout.VERTICAL
|
||||
addView(unfoldedBar(), android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
(com.droiddeck.launcher.ui.BAR_HEIGHT.value * resources.displayMetrics.density + 0.5f).toInt()))
|
||||
addView(panel, android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 0, 1f))
|
||||
}
|
||||
sessionRoot.addView(column, sessionRoot.indexOfChild(surfaceView) + 1)
|
||||
unfoldedColumn = column
|
||||
unfoldedPanel = panel
|
||||
updateOnScreenControls()
|
||||
}
|
||||
panel.layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, height - gameHeight, Gravity.BOTTOM)
|
||||
unfoldedColumn?.layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, height - gameHeight, Gravity.BOTTOM)
|
||||
}
|
||||
|
||||
private fun unfoldedBar(): View = com.droiddeck.launcher.ui.bottomScreenBarView(this) {
|
||||
com.droiddeck.launcher.ui.sessionBarModel(getString(R.string.deck_tab_gamepad), { chooseUnfoldedControls(false) },
|
||||
{ drawerOpen = true }, ::tapSteamButton, ::tapQam)
|
||||
}
|
||||
|
||||
private fun bottomKeyboardPresentation(): SecondScreenPresentation? {
|
||||
@@ -3725,7 +3761,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
private fun panelMode(mode: SecondScreenMode) {
|
||||
val rebind = secondScreenMode.bindings != mode.bindings
|
||||
val rebind = secondScreenMode.panel(this) != mode.panel(this)
|
||||
secondScreenMode = mode
|
||||
SessionState.secondScreenMode = mode
|
||||
if (rebind) refreshInputProfile()
|
||||
@@ -4210,7 +4246,8 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
glassesSlot = when {
|
||||
c == null || c.visibility != View.VISIBLE -> 0
|
||||
c.isButtonsOnly -> -1
|
||||
controllerSettings?.keyboardButton != false -> 2
|
||||
primaryInputLayout?.let { l -> l.elements.any { it.quickButton == InputCommand.KEYBOARD && !l.style.hides(it) } }
|
||||
?: (controllerSettings?.keyboardButton != false) -> 2
|
||||
else -> 1
|
||||
}
|
||||
}
|
||||
@@ -4996,10 +5033,15 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
val swapBack = { putGameOnBottom(false) }
|
||||
val steam = SessionState.mode == SessionService.MODE_STEAM
|
||||
val openMenu = { drawerOpen = true }
|
||||
fun bar(title: String?, extras: List<com.droiddeck.launcher.ui.BarExtra> = emptyList()) = com.droiddeck.launcher.ui.BottomBarModel(
|
||||
title, openMenu, openMenu, if (steam) ({ tapSteamButton() }) else null, if (steam) ({ tapQam() }) else null,
|
||||
extras + com.droiddeck.launcher.ui.BarExtra(getString(R.string.swap_screens), icon = R.drawable.ic_bottom_swap, onClick = swapBack),
|
||||
)
|
||||
fun bar(title: String?, extras: List<com.droiddeck.launcher.ui.BarExtra> = emptyList(), tabs: com.droiddeck.launcher.ui.BarTabs? = null) =
|
||||
com.droiddeck.launcher.ui.BottomBarModel(
|
||||
title, openMenu, openMenu, if (steam) ({ tapSteamButton() }) else null, if (steam) ({ tapQam() }) else null,
|
||||
extras + com.droiddeck.launcher.ui.BarExtra(getString(R.string.swap_screens), icon = R.drawable.ic_bottom_swap, onClick = swapBack),
|
||||
tabs = tabs,
|
||||
)
|
||||
val keyboardExtra = com.droiddeck.launcher.ui.BarExtra(getString(R.string.second_show_keyboard), icon = R.drawable.ic_bottom_keyboard) {
|
||||
keyboard?.toggle()
|
||||
}
|
||||
val profileLayout = secondaryInputLayout
|
||||
androidx.compose.foundation.layout.Box(
|
||||
Modifier.fillMaxSize().background(androidx.compose.ui.graphics.Color.Black)
|
||||
@@ -5014,16 +5056,34 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
},
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
secondScreenMode.controls && (secondScreenMode != SecondScreenMode.DECK_CONTROLS || SessionState.deckPad) -> {
|
||||
androidx.compose.runtime.key(profileLayout) {
|
||||
androidx.compose.ui.viewinterop.AndroidView(
|
||||
factory = { context -> com.droiddeck.launcher.ui.InputSurfaceView(context, padBridge, profileLayout?.elements.orEmpty(),
|
||||
surfaceStyle = profileLayout?.style ?: com.droiddeck.launcher.input.InputSurfaceStyle()) },
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
secondScreenMode.controls && (secondScreenMode != SecondScreenMode.DECK_CONTROLS || SessionState.deckPad) ->
|
||||
androidx.compose.foundation.layout.Column(Modifier.fillMaxSize()) {
|
||||
when (secondScreenMode) {
|
||||
SecondScreenMode.KEYBOARD_TRACKPAD ->
|
||||
com.droiddeck.launcher.ui.BottomScreenBar(bar(getString(SecondScreenMode.KEYBOARD_TRACKPAD.label), listOf(keyboardExtra)))
|
||||
SecondScreenMode.DECK_CONTROLS -> com.droiddeck.launcher.ui.BottomScreenBar(bar(getString(SecondScreenMode.DECK_CONTROLS.label),
|
||||
tabs = com.droiddeck.launcher.ui.deckPanelTabs(this@SessionActivity, SessionPrefs.deckPanel(this@SessionActivity), ::selectDeckPanel)))
|
||||
else -> Unit
|
||||
}
|
||||
androidx.compose.runtime.key(profileLayout) {
|
||||
androidx.compose.ui.viewinterop.AndroidView(
|
||||
factory = { context -> com.droiddeck.launcher.ui.InputSurfaceView(context, padBridge, profileLayout?.elements.orEmpty(),
|
||||
surfaceStyle = profileLayout?.style ?: com.droiddeck.launcher.input.InputSurfaceStyle()) },
|
||||
modifier = Modifier.fillMaxWidth().weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
secondScreenMode == SecondScreenMode.TERMINAL -> androidx.compose.foundation.layout.Column(Modifier.fillMaxSize()) {
|
||||
var terminal by androidx.compose.runtime.remember { androidx.compose.runtime.mutableStateOf<com.droiddeck.launcher.ui.SessionTerminalPanel?>(null) }
|
||||
com.droiddeck.launcher.ui.BottomScreenBar(bar(getString(SecondScreenMode.TERMINAL.label), listOf(
|
||||
com.droiddeck.launcher.ui.BarExtra(getString(R.string.drawer_keyboard), icon = R.drawable.ic_bottom_keyboard) { terminal?.showKeyboard() },
|
||||
)))
|
||||
androidx.compose.ui.viewinterop.AndroidView(
|
||||
factory = { context -> com.droiddeck.launcher.ui.SessionTerminalPanel(context).also { terminal = it } },
|
||||
modifier = Modifier.fillMaxWidth().weight(1f),
|
||||
)
|
||||
}
|
||||
|
||||
pages.isEmpty() -> com.droiddeck.launcher.ui.BottomScreenBar(bar(null))
|
||||
else -> BottomDashboard(
|
||||
pages, com.droiddeck.launcher.ui.SessionBottomTab.picked(SessionState.sessionId),
|
||||
gameStarts = gameStarts,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.droiddeck.launcher.input
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
internal object InputButtonImages {
|
||||
const val DIR = "screenkeys"
|
||||
private const val MAX_SIZE_DP = 140
|
||||
|
||||
fun file(context: Context, name: String): File? =
|
||||
name.takeIf { it.matches(Regex("[A-Za-z0-9_.-]{1,128}")) && it != "." && it != ".." }?.let { File(File(context.filesDir, DIR), it) }
|
||||
|
||||
fun import(context: Context, uri: Uri): String? {
|
||||
val dir = File(context.filesDir, DIR).apply { mkdirs() }
|
||||
val name = "key_" + UUID.randomUUID() + ".png"
|
||||
val longest = (MAX_SIZE_DP * context.resources.displayMetrics.density).toInt()
|
||||
return runCatching {
|
||||
val bounds = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
context.contentResolver.openInputStream(uri)?.use { BitmapFactory.decodeStream(it, null, bounds) }
|
||||
val source = maxOf(bounds.outWidth, bounds.outHeight)
|
||||
if (source <= 0) return@runCatching null
|
||||
var sample = 1
|
||||
while (source / (sample * 2) >= longest) sample *= 2
|
||||
val bitmap = context.contentResolver.openInputStream(uri)?.use {
|
||||
BitmapFactory.decodeStream(it, null, BitmapFactory.Options().apply { inSampleSize = sample })
|
||||
} ?: return@runCatching null
|
||||
val scale = longest.toFloat() / maxOf(bitmap.width, bitmap.height)
|
||||
val scaled = if (scale < 1f) Bitmap.createScaledBitmap(bitmap, (bitmap.width * scale).toInt().coerceAtLeast(1),
|
||||
(bitmap.height * scale).toInt().coerceAtLeast(1), true) else bitmap
|
||||
try {
|
||||
val saved = File(dir, name).outputStream().use { scaled.compress(Bitmap.CompressFormat.PNG, 100, it) }
|
||||
if (saved) name else null
|
||||
} finally {
|
||||
if (scaled !== bitmap) bitmap.recycle()
|
||||
scaled.recycle()
|
||||
}
|
||||
}.getOrNull().also { if (it == null) File(dir, name).delete() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.droiddeck.launcher.input
|
||||
|
||||
import android.content.Context
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
internal object InputLayoutFile {
|
||||
private val NAMES: Map<Int, String> = mapOf(
|
||||
103 to "KEY_UP", 106 to "KEY_RIGHT", 108 to "KEY_DOWN", 105 to "KEY_LEFT",
|
||||
28 to "KEY_ENTER", 1 to "KEY_ESC", 14 to "KEY_BKSP", 111 to "KEY_DEL", 15 to "KEY_TAB",
|
||||
57 to "KEY_SPACE", 29 to "KEY_CTRL_L", 97 to "KEY_CTRL_R", 110 to "KEY_INSERT",
|
||||
42 to "KEY_SHIFT_L", 54 to "KEY_SHIFT_R", 56 to "KEY_ALT_L", 100 to "KEY_ALT_R",
|
||||
102 to "KEY_HOME", 107 to "KEY_END", 99 to "KEY_PRTSCN", 104 to "KEY_PG_UP", 109 to "KEY_PG_DOWN",
|
||||
58 to "KEY_CAPS_LOCK", 69 to "KEY_NUM_LOCK", 41 to "KEY_GRAVE", 12 to "KEY_MINUS",
|
||||
11 to "KEY_0", 2 to "KEY_1", 3 to "KEY_2", 4 to "KEY_3", 5 to "KEY_4", 6 to "KEY_5",
|
||||
7 to "KEY_6", 8 to "KEY_7", 9 to "KEY_8", 10 to "KEY_9",
|
||||
30 to "KEY_A", 48 to "KEY_B", 46 to "KEY_C", 32 to "KEY_D", 18 to "KEY_E", 33 to "KEY_F",
|
||||
34 to "KEY_G", 35 to "KEY_H", 23 to "KEY_I", 36 to "KEY_J", 37 to "KEY_K", 38 to "KEY_L",
|
||||
50 to "KEY_M", 49 to "KEY_N", 24 to "KEY_O", 25 to "KEY_P", 16 to "KEY_Q", 19 to "KEY_R",
|
||||
31 to "KEY_S", 20 to "KEY_T", 22 to "KEY_U", 47 to "KEY_V", 17 to "KEY_W", 45 to "KEY_X",
|
||||
21 to "KEY_Y", 44 to "KEY_Z",
|
||||
26 to "KEY_BRACKET_LEFT", 27 to "KEY_BRACKET_RIGHT", 43 to "KEY_BACKSLASH", 53 to "KEY_SLASH",
|
||||
39 to "KEY_SEMICOLON", 51 to "KEY_COMMA", 52 to "KEY_PERIOD", 40 to "KEY_APOSTROPHE",
|
||||
59 to "KEY_F1", 60 to "KEY_F2", 61 to "KEY_F3", 62 to "KEY_F4", 63 to "KEY_F5", 64 to "KEY_F6",
|
||||
65 to "KEY_F7", 66 to "KEY_F8", 67 to "KEY_F9", 68 to "KEY_F10", 87 to "KEY_F11", 88 to "KEY_F12",
|
||||
79 to "KEY_KP_1", 80 to "KEY_KP_2", 81 to "KEY_KP_3", 75 to "KEY_KP_4", 76 to "KEY_KP_5",
|
||||
77 to "KEY_KP_6", 71 to "KEY_KP_7", 72 to "KEY_KP_8", 73 to "KEY_KP_9", 82 to "KEY_KP_0",
|
||||
)
|
||||
private val CODES: Map<String, Int> = NAMES.entries.associate { (code, name) -> name to code }
|
||||
|
||||
fun fileName(layout: SavedInputLayout) = layout.name.replace(Regex("[^A-Za-z0-9 _.-]"), "_").trim().ifEmpty { "droiddeck-layout" } + ".icp"
|
||||
|
||||
fun export(layout: SavedInputLayout, bindings: SavedInputBindings?, width: Int, height: Int): String? {
|
||||
val snap = width.coerceAtLeast(1) / 100f
|
||||
val elements = JSONArray()
|
||||
for (e in layout.elements) {
|
||||
val action = bindings?.action(e) ?: InputAction.Disabled
|
||||
val directional = e.kind == InputElementKind.DPAD || e.kind == InputElementKind.STICK
|
||||
val codes = when {
|
||||
directional && action is InputAction.Directions -> listOf(action.up, action.right, action.down, action.left)
|
||||
!directional && action is InputAction.Keys -> action.codes
|
||||
else -> continue
|
||||
}
|
||||
val binds = JSONArray()
|
||||
for (code in codes) {
|
||||
val name = NAMES[code]
|
||||
if (name != null) binds.put(name) else if (directional) binds.put("")
|
||||
}
|
||||
if ((0 until binds.length()).all { binds.getString(it).isEmpty() }) continue
|
||||
val shape = when {
|
||||
directional -> "ROUND_RECT"
|
||||
e.buttonShape == InputButtonShape.CIRCLE -> "CIRCLE"
|
||||
e.buttonShape == InputButtonShape.RECTANGLE -> "RECT"
|
||||
else -> "ROUND_RECT"
|
||||
}
|
||||
val sizePx = e.height * height
|
||||
val scale = when {
|
||||
directional -> sizePx * 2.3f / (14f * snap)
|
||||
shape == "CIRCLE" -> sizePx / (6f * snap)
|
||||
else -> sizePx / (4f * snap)
|
||||
}
|
||||
elements.put(JSONObject()
|
||||
.put("type", when (e.kind) { InputElementKind.DPAD -> "D_PAD"; InputElementKind.STICK -> "STICK"; else -> "BUTTON" })
|
||||
.put("shape", shape).put("customColor", 0).put("bindings", binds).put("scale", scale.toDouble())
|
||||
.put("x", (e.x + e.width / 2).toDouble()).put("y", (e.y + e.height / 2).toDouble())
|
||||
.put("toggleSwitch", e.toggle).put("swipeable", false)
|
||||
.put("text", if (e.icon != 0 || e.image.isNotEmpty()) "" else e.name).put("iconId", 0)
|
||||
.apply { if (e.opacity < 1f) put("opacity", e.opacity.toDouble()) })
|
||||
}
|
||||
if (elements.length() == 0) return null
|
||||
return JSONObject().put("id", 0).put("name", layout.name).put("cursorSpeed", 1.5).put("elements", elements).toString()
|
||||
}
|
||||
|
||||
fun parse(raw: String, width: Int, density: Float): List<LegacyScreenKey>? {
|
||||
val root = runCatching { JSONObject(raw) }.getOrNull() ?: return null
|
||||
val elements = root.optJSONArray("elements") ?: return null
|
||||
val snap = width.coerceAtLeast(1) / 100f
|
||||
val keys = mutableListOf<LegacyScreenKey>()
|
||||
for (i in 0 until elements.length()) {
|
||||
val element = elements.optJSONObject(i) ?: continue
|
||||
val type = element.optString("type", "BUTTON")
|
||||
if (type != "BUTTON" && type != "D_PAD" && type != "STICK") continue
|
||||
val binds = element.optJSONArray("bindings") ?: continue
|
||||
val raw = (0 until binds.length()).map { CODES[binds.optString(it)] ?: 0 }
|
||||
val directional = type != "BUTTON"
|
||||
val codes = when {
|
||||
!directional -> raw.filter { it != 0 }.distinct().take(8)
|
||||
type == "STICK" && raw.size <= 4 -> listOf(raw.getOrElse(0) { 0 }, 0, raw.getOrElse(1) { 0 }, 0, raw.getOrElse(2) { 0 }, 0, raw.getOrElse(3) { 0 }, 0)
|
||||
else -> raw.take(if (type == "STICK") 8 else 4)
|
||||
}
|
||||
if (codes.none { it != 0 }) continue
|
||||
val shape = when {
|
||||
type == "D_PAD" -> 5
|
||||
type == "STICK" -> 6
|
||||
else -> when (element.optString("shape")) { "CIRCLE" -> 2; "RECT" -> 3; "SQUARE" -> 1; else -> 0 }
|
||||
}
|
||||
val scale = element.optDouble("scale", 1.0).toFloat().takeIf { it.isFinite() && it > 0f } ?: 1f
|
||||
val sizePx = when {
|
||||
directional -> 14f * snap * scale / 2.3f
|
||||
shape == 2 -> 6f * snap * scale
|
||||
else -> 4f * snap * scale
|
||||
}
|
||||
fun coordinate(name: String) = element.optDouble(name, .5).toFloat().takeIf { it.isFinite() }?.coerceIn(0f, 1f) ?: .5f
|
||||
keys += LegacyScreenKey(codes, coordinate("x"), coordinate("y"), (sizePx / density).roundToInt().coerceIn(24, 140).toFloat(),
|
||||
text = element.optString("text").trim().take(24),
|
||||
opacity = element.optDouble("opacity", 1.0).toFloat().takeIf { it.isFinite() }?.coerceIn(.2f, 1f) ?: 1f,
|
||||
shape = shape, toggle = element.optBoolean("toggleSwitch"))
|
||||
if (keys.size == 64) break
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
fun import(context: Context, raw: String, fallbackName: String, screen: InputLayoutScreen, style: InputSurfaceStyle,
|
||||
width: Int, height: Int, density: Float, id: String = newInputId()): Pair<SavedInputLayout, SavedInputBindings>? {
|
||||
val keys = parse(raw, width, density)?.takeIf { it.isNotEmpty() } ?: return null
|
||||
val converted = runCatching { LegacyScreenKeyMigration.convert(context, keys, width, height, density) }.getOrNull() ?: return null
|
||||
val name = runCatching { JSONObject(raw).optString("name") }.getOrNull().orEmpty().trim().take(80).ifEmpty { fallbackName.trim().take(80) }
|
||||
val layout = SavedInputLayout(id, name, converted.map { it.first }, style = style, screen = screen,
|
||||
aspect = (width.coerceAtLeast(1).toFloat() / height.coerceAtLeast(1)).coerceIn(.05f, 20f))
|
||||
return layout to SavedInputBindings(newInputId(), name, false, id, elements = converted.associate { it.first.id to it.second })
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import org.json.JSONObject
|
||||
import java.util.UUID
|
||||
|
||||
object InputLibraries {
|
||||
private const val VERSION = 11
|
||||
private const val VERSION = 12
|
||||
private const val KEY = "library"
|
||||
private const val RECOVERY = "library-recovery."
|
||||
const val OVERLAY = "builtin.overlay"
|
||||
@@ -29,25 +29,41 @@ object InputLibraries {
|
||||
if (version < 5) library = scopeLayouts(upgradeStockLayouts(upgradeOverlay(context, library)))
|
||||
if (version < 11) library = neutralStockLayouts(library)
|
||||
if (version < 10) library = restyleGamepads(context, library)
|
||||
if (version < 12) library = barStockLayouts(library)
|
||||
if (version < 6 || !p.contains(LegacyScreenKeyMigration.BACKUP)) {
|
||||
val legacy = LegacyScreenKeyMigration.snapshot(context)
|
||||
if (legacy != null) {
|
||||
val upgraded = runCatching { LegacyScreenKeyMigration.migrate(context, library, legacy) }.getOrElse {
|
||||
val migrated = runCatching { LegacyScreenKeyMigration.migrate(context, library, legacy) }.getOrElse {
|
||||
android.util.Log.e("InputLibraries", "Could not migrate screen keys; keeping the original settings", it)
|
||||
return library
|
||||
}
|
||||
val merged = mergeScreenKeys(migrated, legacy)
|
||||
val upgraded = merged ?: migrated
|
||||
val encoded = encode(upgraded)
|
||||
require(encoded.length <= 2_000_000)
|
||||
if (!p.edit().putString(KEY, encoded).putString(LegacyScreenKeyMigration.BACKUP, legacy).commit()) return library
|
||||
val edit = p.edit().putString(KEY, encoded).putString(LegacyScreenKeyMigration.BACKUP, legacy)
|
||||
if (merged != null) edit.putBoolean(LegacyScreenKeyMigration.MERGED, true)
|
||||
if (!edit.commit()) return library
|
||||
LegacyScreenKeyMigration.clean(context)
|
||||
return upgraded
|
||||
}
|
||||
}
|
||||
val backup = p.getString(LegacyScreenKeyMigration.BACKUP, null)
|
||||
if (backup != null && !p.contains(LegacyScreenKeyMigration.MERGED)) {
|
||||
val merged = mergeScreenKeys(library, backup)
|
||||
if (merged != null) {
|
||||
val encoded = encode(merged)
|
||||
if (encoded.length <= 2_000_000 && p.edit().putString(KEY, encoded).putBoolean(LegacyScreenKeyMigration.MERGED, true).commit()) library = merged
|
||||
}
|
||||
}
|
||||
if (raw == null || version < VERSION) write(context, library)
|
||||
if (p.contains(LegacyScreenKeyMigration.BACKUP)) LegacyScreenKeyMigration.clean(context)
|
||||
return library
|
||||
}
|
||||
|
||||
private fun mergeScreenKeys(library: InputLibrary, legacy: String): InputLibrary? = runCatching { LegacyScreenKeyMigration.merge(library, legacy) }
|
||||
.onFailure { android.util.Log.e("InputLibraries", "Could not show the imported screen keys with the gamepad", it) }.getOrNull()
|
||||
|
||||
fun hasPendingScreenKeyMigration(context: Context) = !prefs(context).contains(LegacyScreenKeyMigration.BACKUP) && LegacyScreenKeyMigration.snapshot(context) != null
|
||||
|
||||
fun hasLibraryRecovery(context: Context) = prefs(context).all.keys.any { it.startsWith(RECOVERY) }
|
||||
@@ -115,8 +131,24 @@ object InputLibraries {
|
||||
}
|
||||
}.onSuccess { ControllerPrefs.setAdaptiveSticks(context, on) }.isSuccess
|
||||
|
||||
fun setQuickButton(context: Context, layoutId: String, button: InputCommand, shown: Boolean): Boolean = runCatching {
|
||||
update(context) { library -> library.layouts.firstOrNull { it.id == layoutId && it.editable }?.let { library.withLayout(it.withQuickButton(button, shown)) } ?: library }
|
||||
}.isSuccess
|
||||
|
||||
fun defaultPositions(context: Context, library: InputLibrary, layout: SavedInputLayout): List<InputSurfaceElement>? {
|
||||
val origin = layout.origin ?: layout.id
|
||||
InputStockLayouts.layouts().firstOrNull { it.id == origin }?.let { return it.elements }
|
||||
if (origin == OVERLAY || origin.startsWith("migrated.layout.")) {
|
||||
val (surfaceContext, metrics) = primaryDisplay(context)
|
||||
val size = if (origin == OVERLAY) listOf(metrics.widthPixels, metrics.heightPixels)
|
||||
else origin.removePrefix("migrated.layout.").split('x').mapNotNull { it.toIntOrNull() }
|
||||
return size.takeIf { it.size == 2 && it.all { side -> side > 0 } }?.let { LegacyGamepadLayout(surfaceContext, it[0], it[1]).elements() }
|
||||
}
|
||||
return library.layouts.firstOrNull { it.id == origin && it.id != layout.id }?.elements
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun primaryDisplay(context: Context): Pair<Context, DisplayMetrics> {
|
||||
internal fun primaryDisplay(context: Context): Pair<Context, DisplayMetrics> {
|
||||
val display = context.getSystemService(DisplayManager::class.java)?.getDisplay(Display.DEFAULT_DISPLAY)
|
||||
val surfaceContext = display?.let(context::createDisplayContext) ?: context
|
||||
return surfaceContext to DisplayMetrics().also { if (display != null) display.getRealMetrics(it) else it.setTo(context.resources.displayMetrics) }
|
||||
@@ -143,7 +175,8 @@ object InputLibraries {
|
||||
val elements = LegacyGamepadLayout(surfaceContext, metrics.widthPixels.coerceAtLeast(1), metrics.heightPixels.coerceAtLeast(1)).elements()
|
||||
val style = InputSurfaceStyle(settings.tint, settings.opacity)
|
||||
val replacements = library.layouts.filter { it.template == InputLayoutTemplate.OVERLAY }.associate { old ->
|
||||
old.id to old.copy(name = "Gamepad", elements = elements, template = InputLayoutTemplate.CUSTOM, style = style)
|
||||
old.id to old.copy(name = "Gamepad", elements = elements, template = InputLayoutTemplate.CUSTOM, style = style,
|
||||
aspect = (metrics.widthPixels.coerceAtLeast(1).toFloat() / metrics.heightPixels.coerceAtLeast(1)).coerceIn(.05f, 20f))
|
||||
}
|
||||
var result = library.copy(layouts = library.layouts.map { replacements[it.id] ?: it })
|
||||
val migrated = mutableMapOf<Pair<String, String>, String>()
|
||||
@@ -172,7 +205,7 @@ object InputLibraries {
|
||||
if (size[0] == metrics.widthPixels && size[1] == metrics.heightPixels) continue
|
||||
val id = "migrated.$key"
|
||||
if (result.layouts.none { it.id == id }) result = result.withLayout(SavedInputLayout(id, "Gamepad ${size[0]} × ${size[1]}",
|
||||
LegacyGamepadLayout(surfaceContext, size[0], size[1]).elements(), style = style))
|
||||
LegacyGamepadLayout(surfaceContext, size[0], size[1]).elements(), style = style, aspect = (size[0].toFloat() / size[1]).coerceIn(.05f, 20f)))
|
||||
}
|
||||
return result.validate()
|
||||
}
|
||||
@@ -206,11 +239,30 @@ object InputLibraries {
|
||||
}
|
||||
val oldBindings = migrated.keys.map { it.first }.toSet()
|
||||
result = result.copy(bindings = result.bindings.filter { it.id !in oldBindings || result.usersOfBindings(it.id).isNotEmpty() })
|
||||
return addStockLayouts(result)
|
||||
}
|
||||
|
||||
private fun addStockLayouts(library: InputLibrary): InputLibrary {
|
||||
val stock = InputStockLayouts.layouts()
|
||||
var result = library
|
||||
for (layout in stock) if (result.layouts.none { it.id == layout.id }) result = result.withLayout(layout)
|
||||
for (preset in InputStockLayouts.presets(stock)) if (result.bindings.none { it.id == preset.id }) result = result.withPreset(preset)
|
||||
return result.validate()
|
||||
}
|
||||
|
||||
private fun barStockLayouts(library: InputLibrary): InputLibrary {
|
||||
var result = library
|
||||
for (stock in InputStockLayouts.layouts().filter { it.id == DECK || it.id == TRACKPAD }) {
|
||||
val saved = result.layouts.firstOrNull { it.id == stock.id } ?: continue
|
||||
val (commands, rest) = saved.elements.partition { it.id.startsWith("command:") }
|
||||
val untouched = commands.isNotEmpty() && commands.all { it.control == InputControl.A && it.kind == InputElementKind.BUTTON } &&
|
||||
rest.size == stock.elements.size && rest.all { e -> stock.elements.any { s -> s.id == e.id && s.copy(y = e.y, height = e.height) == e &&
|
||||
kotlin.math.abs(s.y + s.height - e.y - e.height) < 1e-3f } }
|
||||
if (untouched) result = result.withLayout(saved.copy(elements = stock.elements))
|
||||
}
|
||||
return addStockLayouts(result)
|
||||
}
|
||||
|
||||
private fun migrationBindingId(library: InputLibrary, binding: String, layout: String): String {
|
||||
val seed = JSONArray(listOf(binding, layout)).toString().toByteArray(Charsets.UTF_8)
|
||||
val base = "migrated.bindings." + UUID.nameUUIDFromBytes(seed)
|
||||
@@ -242,7 +294,8 @@ object InputLibraries {
|
||||
.put("width", e.width.toDouble()).put("height", e.height.toDouble()).put("floating", e.floating).put("hideWhenIdle", e.hideWhenIdle).put("mouseGestures", e.mouseGestures).put("toggle", e.toggle).put("icon", e.icon).put("image", e.image)
|
||||
.put("elementOpacity", e.opacity.toDouble()).put("buttonShape", e.buttonShape.name).put("showLabel", e.showLabel))
|
||||
layouts.put(JSONObject().put("id", layout.id).put("name", layout.name).put("template", layout.template.name).put("elements", elements)
|
||||
.put("tint", layout.style.tint ?: JSONObject.NULL).put("opacity", layout.style.opacity).put("screen", layout.screen.name))
|
||||
.put("tint", layout.style.tint ?: JSONObject.NULL).put("opacity", layout.style.opacity).put("screen", layout.screen.name).put("aspect", layout.aspect.toDouble()).put("scale", layout.scale.toDouble())
|
||||
.put("hidden", JSONArray(layout.style.hidden.map { it.name }.sorted())).put("origin", layout.origin ?: JSONObject.NULL))
|
||||
}
|
||||
val bindings = JSONArray()
|
||||
for (b in library.bindings) {
|
||||
@@ -283,8 +336,10 @@ object InputLibraries {
|
||||
e.optDouble("elementOpacity", 1.0).toFloat(), InputButtonShape.valueOf(e.optString("buttonShape", InputButtonShape.ROUNDED.name)), e.optBoolean("showLabel", true))
|
||||
}
|
||||
SavedInputLayout(layout.getString("id"), layout.getString("name"), elements, InputLayoutTemplate.valueOf(layout.getString("template")),
|
||||
InputSurfaceStyle(if (!layout.has("tint")) ControllerPrefs.STEAM_BLUE else if (layout.isNull("tint")) null else layout.getInt("tint"), layout.optInt("opacity", 100)),
|
||||
InputLayoutScreen.valueOf(layout.optString("screen", InputLayoutScreen.BOTH.name)))
|
||||
InputSurfaceStyle(if (!layout.has("tint")) ControllerPrefs.STEAM_BLUE else if (layout.isNull("tint")) null else layout.getInt("tint"), layout.optInt("opacity", 100),
|
||||
layout.optJSONArray("hidden")?.let { hidden -> (0 until hidden.length()).map { InputCommand.valueOf(hidden.getString(it)) }.toSet() }.orEmpty()),
|
||||
InputLayoutScreen.valueOf(layout.optString("screen", InputLayoutScreen.BOTH.name)), layout.optDouble("aspect", 0.0).toFloat(), layout.optionalString("origin"),
|
||||
layout.optDouble("scale", 1.0).toFloat())
|
||||
}
|
||||
val bindings = doc.getJSONArray("bindings").objects(512).map { b ->
|
||||
val controls = b.getJSONObject("controls").actions(28).mapKeys { requireNotNull(InputControl.fromId(it.key)) }
|
||||
|
||||
@@ -9,15 +9,25 @@ enum class InputLayoutScreen { MAIN, SECONDARY, BOTH;
|
||||
if (role == InputRole.PRIMARY) this == MAIN else this == SECONDARY)
|
||||
}
|
||||
|
||||
data class InputSurfaceStyle(val tint: Int? = ControllerPrefs.STEAM_BLUE, val opacity: Int = 100)
|
||||
data class InputSurfaceStyle(val tint: Int? = ControllerPrefs.STEAM_BLUE, val opacity: Int = 100, val hidden: Set<InputCommand> = emptySet()) {
|
||||
fun hides(element: InputSurfaceElement) = element.quickButton?.let { it in hidden } == true
|
||||
fun shown(elements: List<InputSurfaceElement>) = if (hidden.isEmpty()) elements else elements.filterNot(::hides)
|
||||
}
|
||||
|
||||
data class SavedInputLayout(
|
||||
val id: String, val name: String, val elements: List<InputSurfaceElement> = emptyList(),
|
||||
val template: InputLayoutTemplate = InputLayoutTemplate.CUSTOM,
|
||||
val style: InputSurfaceStyle = InputSurfaceStyle(),
|
||||
val screen: InputLayoutScreen = InputLayoutScreen.BOTH,
|
||||
val aspect: Float = 0f,
|
||||
val origin: String? = null,
|
||||
val scale: Float = 1f,
|
||||
) {
|
||||
val editable get() = template == InputLayoutTemplate.CUSTOM
|
||||
val quickButtons get() = QUICK_BUTTONS.filter { button -> elements.any { it.quickButton == button } }
|
||||
fun withQuickButton(button: InputCommand, shown: Boolean) =
|
||||
copy(style = style.copy(hidden = if (shown) style.hidden - button else style.hidden + button))
|
||||
fun derived(id: String, name: String) = copy(id = id, name = name, origin = origin ?: this.id)
|
||||
val adaptiveSticks get() = elements.filter { it.kind == InputElementKind.STICK }.takeIf { editable && it.isNotEmpty() }?.all { it.floating && it.hideWhenIdle }
|
||||
fun supports(role: InputRole) = screen.supports(role) && when (template) {
|
||||
InputLayoutTemplate.OVERLAY -> role == InputRole.PRIMARY
|
||||
@@ -132,7 +142,7 @@ data class InputLibrary(
|
||||
if (shared) return withProfile(target.copy(parts = target.parts + (role to source)))
|
||||
val sourceLayout = layout(sourceId, role)
|
||||
val name = (target.name + " / " + role.name.lowercase()).take(80)
|
||||
val copiedLayout = sourceLayout?.takeIf { it.editable }?.copy(id = newInputId(), name = name)
|
||||
val copiedLayout = sourceLayout?.takeIf { it.editable }?.derived(newInputId(), name)
|
||||
val copiedBindings = preset(source.bindings).copy(id = newInputId(), name = name,
|
||||
layoutId = copiedLayout?.id ?: preset(source.bindings).layoutId)
|
||||
return (if (copiedLayout == null) this else withLayout(copiedLayout)).withPreset(copiedBindings)
|
||||
@@ -143,7 +153,7 @@ data class InputLibrary(
|
||||
val source = layouts.first { it.id == layoutId }
|
||||
require(source.supports(role))
|
||||
val target = profile(profileId)
|
||||
val layout = if (shared || !source.editable) source else source.copy(id = newInputId(), name = (target.name + " / " + source.name).take(80))
|
||||
val layout = if (shared || !source.editable) source else source.derived(newInputId(), (target.name + " / " + source.name).take(80))
|
||||
val previous = preset(target.binding(role))
|
||||
val actions = if (previous.compatible(source)) previous else bindings.firstOrNull { it.compatible(source) } ?: SavedInputBindings(newInputId(), target.name, false,
|
||||
controls = if (source.editable) emptyMap() else InputProfile.defaults(target.base).bindings[role].orEmpty(),
|
||||
@@ -181,7 +191,7 @@ data class InputLibrary(
|
||||
fun copyLayout(id: String, name: String, newId: String = newInputId()): InputLibrary {
|
||||
val source = layouts.first { it.id == id }
|
||||
require(source.editable)
|
||||
return withLayout(source.copy(id = newId, name = inputName(name)))
|
||||
return withLayout(source.derived(newId, inputName(name)))
|
||||
}
|
||||
|
||||
fun removeProfile(id: String): InputLibrary {
|
||||
@@ -227,7 +237,9 @@ data class InputLibrary(
|
||||
require(selected == InputProfiles.AUTO || profiles.any { it.id == selected })
|
||||
require(profiles.any { it.id == steam } && profiles.any { it.id == desktop })
|
||||
for (layout in layouts) {
|
||||
require(layout.style.opacity in 1..100)
|
||||
require(layout.style.opacity in 1..100 && layout.style.hidden.all { it in QUICK_BUTTONS })
|
||||
require(layout.aspect == 0f || layout.aspect.isFinite() && layout.aspect in .05f..20f)
|
||||
require(layout.scale.isFinite() && layout.scale in .5f..2f)
|
||||
inputName(layout.name); require(layout.elements.size <= 64); unique(layout.elements.map { it.id })
|
||||
for (e in layout.elements) {
|
||||
inputName(e.name)
|
||||
|
||||
@@ -234,7 +234,7 @@ class InputRouter(private val output: InputOutput) {
|
||||
when (a) {
|
||||
is InputAction.Keys -> if (down) a.codes.forEach { key(it, true) } else a.codes.asReversed().forEach { key(it, false) }
|
||||
is InputAction.MouseButton -> button(a.code, down)
|
||||
is InputAction.Command -> if (down) output.command(a.command, role)
|
||||
is InputAction.Command -> if (!down) output.command(a.command, role)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,61 @@
|
||||
package com.droiddeck.launcher.input
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import com.droiddeck.launcher.R
|
||||
|
||||
enum class DeckPanel(val id: String, val layout: String, val bindings: String, @StringRes val label: Int) {
|
||||
GAMEPAD("gamepad", "builtin.deck.gamepad", "preset.deck.gamepad", R.string.deck_tab_gamepad),
|
||||
GRIPS("grips", "builtin.deck.grips", "preset.deck.grips", R.string.deck_tab_grips),
|
||||
LEFT("left", "builtin.deck.left", "preset.deck.left", R.string.deck_tab_left),
|
||||
RIGHT("right", "builtin.deck.right", "preset.deck.right", R.string.deck_tab_right),
|
||||
BOTH("both", InputLibraries.DECK, InputStockLayouts.DECK, R.string.deck_tab_both);
|
||||
|
||||
companion object {
|
||||
fun from(id: String?) = entries.firstOrNull { it.id == id } ?: BOTH
|
||||
}
|
||||
}
|
||||
|
||||
internal object InputStockLayouts {
|
||||
private val NEUTRAL = InputSurfaceStyle(tint = null)
|
||||
const val DECK = "preset.deck"
|
||||
const val TRACKPAD = "preset.trackpad"
|
||||
private fun commands(indices: List<Int>): List<InputSurfaceElement> {
|
||||
val names = listOf("DroidDeck menu", "Keyboard", "Steam", "Quick access")
|
||||
val icons = listOf(InputButtonIcons.MENU, InputButtonIcons.KEYBOARD, InputButtonIcons.STEAM, InputButtonIcons.QUICK_ACCESS)
|
||||
val step = .98f / indices.size
|
||||
return indices.mapIndexed { position, i ->
|
||||
InputSurfaceElement(InputControl.A, .02f + position * step, .01f, step - .02f, .11f,
|
||||
"command:$i", name = names[i], icon = icons[i])
|
||||
}
|
||||
}
|
||||
private fun commandActions(): Map<String, InputAction> = listOf(InputCommand.MENU, InputCommand.KEYBOARD, InputCommand.STEAM, InputCommand.QUICK_ACCESS)
|
||||
.mapIndexed { i, command -> "command:$i" to InputAction.Command(command) }.toMap()
|
||||
private fun grips() = listOf(InputControl.L4, InputControl.L5, InputControl.R5, InputControl.R4).mapIndexed { i, c ->
|
||||
InputSurfaceElement(c, .02f + i * .245f, .78f, .225f, .20f)
|
||||
}
|
||||
private fun pads() = listOf(InputSurfaceElement(InputControl.LEFT_PAD, .02f, .14f, .47f, .62f),
|
||||
InputSurfaceElement(InputControl.RIGHT_PAD, .51f, .14f, .47f, .62f))
|
||||
private fun pads() = listOf(InputSurfaceElement(InputControl.LEFT_PAD, .02f, .02f, .47f, .74f),
|
||||
InputSurfaceElement(InputControl.RIGHT_PAD, .51f, .02f, .47f, .74f))
|
||||
private fun gripGrid() = listOf(InputControl.L4 to (.02f to .02f), InputControl.L5 to (.02f to .51f),
|
||||
InputControl.R4 to (.51f to .02f), InputControl.R5 to (.51f to .51f)).map { (c, at) ->
|
||||
InputSurfaceElement(c, at.first, at.second, .47f, .47f)
|
||||
}
|
||||
private fun pad(right: Boolean) = listOf(
|
||||
InputSurfaceElement(if (right) InputControl.RIGHT_PAD else InputControl.LEFT_PAD, .02f, .02f, .96f, .74f),
|
||||
InputSurfaceElement(if (right) InputControl.RIGHT_CLICK else InputControl.LEFT_CLICK, .02f, .78f, .96f, .20f),
|
||||
)
|
||||
private fun gamepad(): List<InputSurfaceElement> {
|
||||
fun round(c: InputControl, x: Float, y: Float, size: Float) = InputSurfaceElement(c, x, y, size, size, buttonShape = InputButtonShape.CIRCLE)
|
||||
fun pill(c: InputControl, x: Float) = InputSurfaceElement(c, x, .02f, .2f, .12f, buttonShape = InputButtonShape.PILL)
|
||||
return listOf(pill(InputControl.LT, .02f), pill(InputControl.LB, .24f), pill(InputControl.RB, .56f), pill(InputControl.RT, .78f),
|
||||
InputSurfaceElement(InputControl.LS, .02f, .17f, .4f, .4f),
|
||||
InputSurfaceElement(InputControl.RIGHT_PAD, .58f, .59f, .4f, .39f),
|
||||
round(InputControl.UP, .14f, .6f, .12f), round(InputControl.LEFT, .03f, .73f, .12f),
|
||||
round(InputControl.RIGHT, .25f, .73f, .12f), round(InputControl.DOWN, .14f, .86f, .12f),
|
||||
round(InputControl.Y, .72f, .17f, .12f), round(InputControl.X, .61f, .3f, .12f),
|
||||
round(InputControl.B, .83f, .3f, .12f), round(InputControl.A, .72f, .43f, .12f),
|
||||
InputSurfaceElement(InputControl.SELECT, .42f, .3f, .07f, .1f, buttonShape = InputButtonShape.PILL),
|
||||
InputSurfaceElement(InputControl.START, .51f, .3f, .07f, .1f, buttonShape = InputButtonShape.PILL))
|
||||
}
|
||||
fun layouts() = listOf(
|
||||
SavedInputLayout(InputLibraries.DECK, "Deck grips + trackpads", commands(listOf(2, 3, 0)) + pads() + grips(), style = NEUTRAL, screen = InputLayoutScreen.SECONDARY),
|
||||
SavedInputLayout(InputLibraries.TRACKPAD, "Trackpad + keyboard", commands(listOf(0, 1)) +
|
||||
InputSurfaceElement(InputControl.RIGHT_PAD, .02f, .14f, .96f, .84f, mouseGestures = true), style = NEUTRAL, screen = InputLayoutScreen.SECONDARY),
|
||||
SavedInputLayout(InputLibraries.DECK, "Deck grips + trackpads", pads() + grips(), style = NEUTRAL, screen = InputLayoutScreen.SECONDARY),
|
||||
SavedInputLayout(InputLibraries.TRACKPAD, "Trackpad + keyboard", listOf(
|
||||
InputSurfaceElement(InputControl.RIGHT_PAD, .02f, .02f, .96f, .96f, mouseGestures = true)), style = NEUTRAL, screen = InputLayoutScreen.SECONDARY),
|
||||
SavedInputLayout(DeckPanel.GAMEPAD.layout, "Deck gamepad", gamepad(), style = NEUTRAL, screen = InputLayoutScreen.SECONDARY),
|
||||
SavedInputLayout(DeckPanel.GRIPS.layout, "Deck grips", gripGrid(), style = NEUTRAL, screen = InputLayoutScreen.SECONDARY),
|
||||
SavedInputLayout(DeckPanel.LEFT.layout, "Deck left trackpad", pad(right = false), style = NEUTRAL, screen = InputLayoutScreen.SECONDARY),
|
||||
SavedInputLayout(DeckPanel.RIGHT.layout, "Deck right trackpad", pad(right = true), style = NEUTRAL, screen = InputLayoutScreen.SECONDARY),
|
||||
)
|
||||
|
||||
fun actions(layout: SavedInputLayout): Map<String, InputAction> = (commandActions() + if (layout.id == InputLibraries.TRACKPAD) mapOf(
|
||||
fun actions(layout: SavedInputLayout): Map<String, InputAction> = (if (layout.id == InputLibraries.TRACKPAD) mapOf(
|
||||
"legacy:right-pad" to InputAction.Pointer(), "legacy:a" to InputAction.MouseButton(272), "legacy:b" to InputAction.MouseButton(273),
|
||||
) else emptyMap()).filterKeys { id -> layout.elements.any { it.id == id } }
|
||||
|
||||
@@ -35,7 +64,8 @@ internal object InputStockLayouts {
|
||||
|
||||
fun presets(layouts: List<SavedInputLayout>) = layouts.map { layout ->
|
||||
val desktop = layout.id == InputLibraries.TRACKPAD
|
||||
SavedInputBindings(if (desktop) TRACKPAD else DECK, layout.name, false, layout.id,
|
||||
val id = if (desktop) TRACKPAD else DeckPanel.entries.first { it.layout == layout.id }.bindings
|
||||
SavedInputBindings(id, layout.name, false, layout.id,
|
||||
controls = InputProfile.defaults(if (desktop) InputProfile.DESKTOP else InputProfile.GAME).bindings[InputRole.SECONDARY].orEmpty(),
|
||||
elements = actions(layout), clicks = clicks(layout))
|
||||
}
|
||||
|
||||
@@ -38,7 +38,33 @@ data class InputSurfaceElement(
|
||||
val hasClick get() = kind == InputElementKind.STICK || kind == InputElementKind.TRACKPAD
|
||||
|
||||
fun bounded() = copy(x = x.coerceIn(0f, 0.97f), y = y.coerceIn(0f, 0.97f),
|
||||
width = width.coerceIn(0.03f, 1f - x.coerceIn(0f, 0.97f)), height = height.coerceIn(0.03f, 1f - y.coerceIn(0f, 0.97f)))
|
||||
width = width.coerceIn(0.03f, (1f - x.coerceIn(0f, 0.97f)).coerceAtLeast(0.03f)), height = height.coerceIn(0.03f, (1f - y.coerceIn(0f, 0.97f)).coerceAtLeast(0.03f)))
|
||||
}
|
||||
|
||||
internal val QUICK_BUTTONS = listOf(InputCommand.STEAM, InputCommand.QUICK_ACCESS, InputCommand.KEYBOARD)
|
||||
|
||||
val InputSurfaceElement.quickButton: InputCommand? get() = when {
|
||||
id == "legacy:${InputControl.GUIDE.id}" -> InputCommand.STEAM
|
||||
id == "legacy:${InputControl.QAM.id}" -> InputCommand.QUICK_ACCESS
|
||||
id == "builtin:keyboard" -> InputCommand.KEYBOARD
|
||||
else -> null
|
||||
}
|
||||
|
||||
internal fun List<InputSurfaceElement>.scaled(factor: Float): List<InputSurfaceElement> = map { e ->
|
||||
fun anchor(centre: Float) = when { centre < 1f / 3f -> 0f; centre > 2f / 3f -> 1f; else -> .5f }
|
||||
val w = (e.width * factor).coerceIn(.03f, 1f)
|
||||
val h = (e.height * factor).coerceIn(.03f, 1f)
|
||||
val cx = e.x + e.width / 2
|
||||
val cy = e.y + e.height / 2
|
||||
val ax = anchor(cx)
|
||||
val ay = anchor(cy)
|
||||
e.copy(x = (ax + (cx - ax) * factor - w / 2).coerceIn(0f, 1f - w), y = (ay + (cy - ay) * factor - h / 2).coerceIn(0f, 1f - h),
|
||||
width = w, height = h).bounded()
|
||||
}
|
||||
|
||||
internal fun List<InputSurfaceElement>.withPositionsOf(defaults: List<InputSurfaceElement>): List<InputSurfaceElement> {
|
||||
val byId = defaults.associateBy { it.id }
|
||||
return map { e -> byId[e.id]?.let { d -> e.copy(x = d.x, y = d.y, width = d.width, height = d.height).bounded() } ?: e }
|
||||
}
|
||||
|
||||
object InputSurfaceLayout {
|
||||
|
||||
@@ -71,6 +71,12 @@ class InputSurfaceSource(private val pad: PadBridge, private val role: InputRole
|
||||
InputTiming.end(timing)
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
if (closed) return
|
||||
route?.takeIf { it.action is InputAction.Command }?.release()
|
||||
update(0f)
|
||||
}
|
||||
|
||||
fun click(down: Boolean) {
|
||||
if (closed) return
|
||||
val timing = InputTiming.begin()
|
||||
|
||||
@@ -4,10 +4,10 @@ import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import kotlin.math.*
|
||||
|
||||
internal class LegacyGamepadLayout(private val context: Context, private val width: Int, private val height: Int) {
|
||||
internal class LegacyGamepadLayout(private val context: Context, private val width: Int, private val height: Int, private val safe: Rect = Rect(),
|
||||
private val scale: Float = 1f) {
|
||||
private val resources get() = context.resources
|
||||
private val settings = ControllerPrefs.read(context)
|
||||
private val safe = Rect()
|
||||
private var fit = 1f
|
||||
private class Control(val id: String, val group: String, val stick: Int, val radiusDp: Float, val offsetXDp: Float, val offsetYDp: Float) {
|
||||
var radius = 0f
|
||||
@@ -41,7 +41,7 @@ internal class LegacyGamepadLayout(private val context: Context, private val wid
|
||||
|
||||
private fun dp(value: Float) = value * resources.displayMetrics.density
|
||||
|
||||
private fun scaled(value: Float) = dp(value) * settings.size / 100f * fit
|
||||
private fun scaled(value: Float) = dp(value) * settings.size / 100f * scale * fit
|
||||
|
||||
private fun fitScale(): Float {
|
||||
val metrics = resources.displayMetrics
|
||||
@@ -195,6 +195,76 @@ internal class LegacyGamepadLayout(private val context: Context, private val wid
|
||||
return result
|
||||
}
|
||||
|
||||
fun regenerate(stored: List<InputSurfaceElement>): List<InputSurfaceElement> = withGeometry(stored, elements())
|
||||
|
||||
fun rescale(stored: List<InputSurfaceElement>, from: LegacyGamepadLayout): List<InputSurfaceElement> {
|
||||
val before = from.elements().associateBy { it.id }
|
||||
val after = elements().associateBy { it.id }
|
||||
return stored.map { e ->
|
||||
val b = before[e.id] ?: return@map e
|
||||
val a = after[e.id] ?: return@map e
|
||||
val w = (a.width * e.width / b.width).coerceIn(.03f, 1f)
|
||||
val h = (a.height * e.height / b.height).coerceIn(.03f, 1f)
|
||||
val cx = a.x + a.width / 2 + (e.x + e.width / 2 - b.x - b.width / 2)
|
||||
val cy = a.y + a.height / 2 + (e.y + e.height / 2 - b.y - b.height / 2)
|
||||
e.copy(x = (cx - w / 2).coerceIn(0f, 1f - w), y = (cy - h / 2).coerceIn(0f, 1f - h), width = w, height = h).bounded()
|
||||
}
|
||||
}
|
||||
|
||||
fun buttonsOnly(stored: List<InputSurfaceElement>): List<InputSurfaceElement> {
|
||||
val inset = dp(BUTTONS_ONLY_INSET_DP)
|
||||
val bottom = height - safe.bottom - inset
|
||||
val radius = dp(BUTTONS_ONLY_RADIUS_DP)
|
||||
fun pick(control: InputControl, shown: Boolean) = stored.firstOrNull { it.id == "legacy:${control.id}" }
|
||||
?: stored.firstOrNull { it.control == control && it.kind == InputElementKind.BUTTON }
|
||||
?: InputSurfaceElement(control, 0f, 0f, 0f, 0f, buttonShape = InputButtonShape.CIRCLE).takeIf { shown }
|
||||
return listOfNotNull(
|
||||
pick(InputControl.GUIDE, settings.steamButton)?.let { circle(it, safe.left + inset, bottom, radius) },
|
||||
pick(InputControl.QAM, settings.qamButton)?.let { circle(it, width - safe.right - inset, bottom, radius) },
|
||||
stored.firstOrNull { it.id == KEYBOARD_ID }?.let { circle(it, width / 2f, bottom, dp(KEYBOARD_RADIUS_DP)) },
|
||||
)
|
||||
}
|
||||
|
||||
fun dock(stored: List<InputSurfaceElement>, portrait: Boolean, grips: Boolean): List<InputSurfaceElement> {
|
||||
val boxes = GamepadGeometry.layout(width.toFloat(), height.toFloat(), resources.displayMetrics.density, portrait)
|
||||
val placed = mutableListOf<InputSurfaceElement>()
|
||||
fun box(control: InputControl, slot: GamepadGeometry.Slot, shape: InputButtonShape) {
|
||||
val b = boxes[slot] ?: return
|
||||
placed += InputSurfaceElement(control, b.left / width, b.top / height, b.width / width, b.height / height,
|
||||
floating = false, buttonShape = shape).bounded()
|
||||
}
|
||||
fun cross(controls: List<InputControl>, slot: GamepadGeometry.Slot) {
|
||||
val b = boxes[slot] ?: return
|
||||
val side = min(b.width, b.height)
|
||||
val spread = side * CROSS_SPREAD
|
||||
val radius = side * CROSS_RADIUS
|
||||
controls.zip(listOf(0f to -1f, 1f to 0f, 0f to 1f, -1f to 0f)).forEach { (control, direction) ->
|
||||
placed += circle(InputSurfaceElement(control, 0f, 0f, 0f, 0f, buttonShape = InputButtonShape.CIRCLE),
|
||||
b.cx + direction.first * spread, b.cy + direction.second * spread, radius)
|
||||
}
|
||||
}
|
||||
box(InputControl.LS, GamepadGeometry.Slot.LEFT_MAIN, InputButtonShape.CIRCLE)
|
||||
cross(DPAD_ORDER, GamepadGeometry.Slot.LEFT_SECOND)
|
||||
box(InputControl.RS, GamepadGeometry.Slot.RIGHT_MAIN, InputButtonShape.CIRCLE)
|
||||
cross(FACE_ORDER, GamepadGeometry.Slot.RIGHT_SECOND)
|
||||
box(InputControl.LT, GamepadGeometry.Slot.LEFT_OUTER_SHOULDER, InputButtonShape.PILL)
|
||||
box(InputControl.LB, GamepadGeometry.Slot.LEFT_INNER_SHOULDER, InputButtonShape.PILL)
|
||||
box(InputControl.RB, GamepadGeometry.Slot.RIGHT_INNER_SHOULDER, InputButtonShape.PILL)
|
||||
box(InputControl.RT, GamepadGeometry.Slot.RIGHT_OUTER_SHOULDER, InputButtonShape.PILL)
|
||||
box(InputControl.SELECT, GamepadGeometry.Slot.VIEW, InputButtonShape.PILL)
|
||||
box(InputControl.START, GamepadGeometry.Slot.MENU, InputButtonShape.PILL)
|
||||
if (grips) GRIPS.forEach { (control, slot) -> box(control, slot, InputButtonShape.ROUNDED) }
|
||||
return withGeometry(stored, placed) + placed.filter { p -> GRIPS.any { it.first == p.control } && stored.none { it.id == p.id } }
|
||||
}
|
||||
|
||||
private fun circle(e: InputSurfaceElement, cx: Float, cy: Float, radius: Float) =
|
||||
e.copy(x = (cx - radius) / width, y = (cy - radius) / height, width = 2 * radius / width, height = 2 * radius / height).bounded()
|
||||
|
||||
private fun withGeometry(stored: List<InputSurfaceElement>, placed: List<InputSurfaceElement>): List<InputSurfaceElement> {
|
||||
val byId = placed.associateBy { it.id }
|
||||
return stored.mapNotNull { e -> byId[e.id]?.let { e.copy(x = it.x, y = it.y, width = it.width, height = it.height) } }
|
||||
}
|
||||
|
||||
private fun keyboard(): InputSurfaceElement {
|
||||
val radius = dp(KEYBOARD_RADIUS_DP)
|
||||
val cx = safe.left + dp(KEYBOARD_X_DP)
|
||||
@@ -268,5 +338,13 @@ internal class LegacyGamepadLayout(private val context: Context, private val wid
|
||||
const val KEYBOARD_RADIUS_DP = 18f
|
||||
const val KEYBOARD_X_DP = 90f
|
||||
const val KEYBOARD_Y_DP = 34f
|
||||
const val BUTTONS_ONLY_RADIUS_DP = 30f
|
||||
const val BUTTONS_ONLY_INSET_DP = 44f
|
||||
const val CROSS_SPREAD = .30f
|
||||
const val CROSS_RADIUS = .16f
|
||||
val DPAD_ORDER = listOf(InputControl.UP, InputControl.RIGHT, InputControl.DOWN, InputControl.LEFT)
|
||||
val FACE_ORDER = listOf(InputControl.Y, InputControl.B, InputControl.A, InputControl.X)
|
||||
val GRIPS = listOf(InputControl.L4 to GamepadGeometry.Slot.L4, InputControl.L5 to GamepadGeometry.Slot.L5,
|
||||
InputControl.R5 to GamepadGeometry.Slot.R5, InputControl.R4 to GamepadGeometry.Slot.R4)
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import org.json.JSONObject
|
||||
|
||||
internal object LegacyScreenKeyMigration {
|
||||
const val BACKUP = "legacy-screen-keys-backup"
|
||||
const val MERGED = "legacy-screen-keys-merged"
|
||||
private const val SHOWN = "migrated.screenkeys.0"
|
||||
|
||||
fun snapshot(context: Context): String? {
|
||||
val values = ControllerPrefs.prefs(context).all.filterKeys { it == "screenKeys" || it == "screenKeysShown" || it.startsWith("screenLayout.") }
|
||||
@@ -38,7 +40,8 @@ internal object LegacyScreenKeyMigration {
|
||||
if (result.profiles.any { it.id == id }) continue
|
||||
val converted = convert(context, set.second, metrics.widthPixels, metrics.heightPixels, metrics.density)
|
||||
if (converted.isEmpty()) continue
|
||||
val layout = SavedInputLayout("$id.layout", set.first, converted.map { it.first }, style = style, screen = InputLayoutScreen.MAIN)
|
||||
val layout = SavedInputLayout("$id.layout", set.first, converted.map { it.first }, style = style, screen = InputLayoutScreen.MAIN,
|
||||
aspect = (metrics.widthPixels.coerceAtLeast(1).toFloat() / metrics.heightPixels.coerceAtLeast(1)).coerceIn(.05f, 20f))
|
||||
val bindings = SavedInputBindings("$id.bindings", set.first, false, layout.id, elements = converted.associate { it.first.id to it.second })
|
||||
val base = library.profile(library.steam)
|
||||
val profile = SavedInputProfile(id, set.first, base.base, base.parts + (InputRole.PRIMARY to InputPart(bindings.id, layout.id)))
|
||||
@@ -47,30 +50,58 @@ internal object LegacyScreenKeyMigration {
|
||||
return result.validate()
|
||||
}
|
||||
|
||||
fun merge(library: InputLibrary, raw: String): InputLibrary {
|
||||
val old = JSONObject(raw)
|
||||
if (!old.optBoolean("screenKeysShown", true) || old.optString("screenKeys").isBlank()) return library
|
||||
val keys = library.layouts.firstOrNull { it.id == "$SHOWN.layout" } ?: return library
|
||||
val actions = library.bindings.firstOrNull { it.id == "$SHOWN.bindings" }?.elements.orEmpty()
|
||||
var result = library
|
||||
for (part in listOf(false, true).map { library.activePart(it, InputRole.PRIMARY) }.distinct()) {
|
||||
val layout = result.layouts.firstOrNull { it.id == part.layout } ?: continue
|
||||
val preset = result.preset(part.bindings)
|
||||
if (!layout.editable || preset.layoutId != layout.id || layout.elements.any { e -> keys.elements.any { it.id == e.id } } ||
|
||||
layout.elements.size + keys.elements.size > 64) continue
|
||||
val added = keys.elements.mapNotNull { e -> actions[e.id]?.let { e.id to it } }.toMap()
|
||||
result = result.withLayout(layout.copy(elements = layout.elements + keys.elements))
|
||||
.withPreset(preset.copy(elements = added + preset.elements))
|
||||
}
|
||||
return result.validate()
|
||||
}
|
||||
|
||||
internal fun convert(context: Context, raw: String, width: Int, height: Int, density: Float): List<Pair<InputSurfaceElement, InputAction>> =
|
||||
raw.split(';').filter { it.isNotBlank() }.mapIndexed { index, entry ->
|
||||
val parts = entry.split(':')
|
||||
require(parts.size >= 2) { "Invalid legacy screen key" }
|
||||
val codes = parts[0].split('+').map { it.toInt() }
|
||||
convert(context, parse(raw), width, height, density)
|
||||
|
||||
internal fun parse(raw: String): List<LegacyScreenKey> = raw.split(';').filter { it.isNotBlank() }.map { entry ->
|
||||
val parts = entry.split(':')
|
||||
require(parts.size >= 2) { "Invalid legacy screen key" }
|
||||
val codes = parts[0].split('+').map { it.toInt() }
|
||||
val position = parts[1].split(',').map { it.toFloat() }
|
||||
require(position.size == 3)
|
||||
fun text(at: Int) = parts.getOrNull(at).orEmpty().replace("%2C", ",").replace("%3A", ":").replace("%3B", ";").replace("%25", "%")
|
||||
LegacyScreenKey(codes, position[0], position[1], position[2], text(2), text(3), text(4),
|
||||
parts.getOrNull(5)?.toFloatOrNull() ?: 1f, parts.getOrNull(6)?.toIntOrNull() ?: 0, parts.getOrNull(7) == "1", parts.getOrNull(8) != "0")
|
||||
}
|
||||
|
||||
internal fun convert(context: Context, keys: List<LegacyScreenKey>, width: Int, height: Int, density: Float): List<Pair<InputSurfaceElement, InputAction>> =
|
||||
keys.mapIndexed { index, key ->
|
||||
val codes = key.codes
|
||||
require(codes.all { it in 0..255 })
|
||||
val position = parts[1].split(',').map { it.toFloat() }
|
||||
require(position.size == 3 && position.all { it.isFinite() })
|
||||
fun text(at: Int) = parts.getOrNull(at).orEmpty().replace("%2C", ",").replace("%3A", ":").replace("%3B", ";").replace("%25", "%")
|
||||
val shape = parts.getOrNull(6)?.toIntOrNull() ?: 0
|
||||
require(listOf(key.x, key.y, key.size).all { it.isFinite() })
|
||||
val shape = key.shape
|
||||
val kind = when (shape) { 5 -> InputElementKind.DPAD; 6 -> InputElementKind.STICK; 4 -> InputElementKind.TRIGGER; else -> InputElementKind.BUTTON }
|
||||
val label = text(3).ifEmpty { text(2) }.ifEmpty { codes.filter { it != 0 }.joinToString("+") { pcKeyLabel(context, it) } }.ifBlank { "Button" }.take(80)
|
||||
val image = text(4)
|
||||
val icon = codes.singleOrNull()?.takeIf { InputButtonIcons.has(it) && text(3).isEmpty() && text(2).isEmpty() } ?: 0
|
||||
val heightPx = position[2].coerceIn(24f, 140f) * density
|
||||
val label = key.text.ifEmpty { key.glyph }.ifEmpty { codes.filter { it != 0 }.joinToString("+") { pcKeyLabel(context, it) } }.ifBlank { "Button" }.take(80)
|
||||
val image = key.image
|
||||
val icon = codes.singleOrNull()?.takeIf { InputButtonIcons.has(it) && key.text.isEmpty() && key.glyph.isEmpty() } ?: 0
|
||||
val heightPx = key.size.coerceIn(24f, 140f) * density
|
||||
val ratio = when { shape == 2 -> 1f; shape == 4 -> 1.7f; shape == 5 || shape == 6 || image.isNotEmpty() || icon != 0 -> 1.15f; else -> (.55f * label.length + 1.05f).coerceIn(1.7f, 4.6f) }
|
||||
val w = (heightPx * ratio / width.coerceAtLeast(1)).coerceIn(.03f, 1f)
|
||||
val h = (heightPx / height.coerceAtLeast(1)).coerceIn(.03f, 1f)
|
||||
val element = InputSurfaceElement(kind.control, (position[0] - w / 2).coerceIn(0f, 1f - w), (position[1] - h / 2).coerceIn(0f, 1f - h), w, h,
|
||||
val element = InputSurfaceElement(kind.control, (key.x - w / 2).coerceIn(0f, 1f - w), (key.y - h / 2).coerceIn(0f, 1f - h), w, h,
|
||||
id = "imported:$index", kind = kind, name = label, floating = false,
|
||||
toggle = parts.getOrNull(7) == "1" && kind != InputElementKind.DPAD && kind != InputElementKind.STICK,
|
||||
icon = icon, image = image, opacity = (parts.getOrNull(5)?.toFloatOrNull() ?: 1f).coerceIn(.2f, 1f),
|
||||
toggle = key.toggle && kind != InputElementKind.DPAD && kind != InputElementKind.STICK,
|
||||
icon = icon, image = image, opacity = key.opacity.coerceIn(.2f, 1f),
|
||||
buttonShape = when (shape) { 0 -> InputButtonShape.PILL; 2 -> InputButtonShape.CIRCLE; 3 -> InputButtonShape.RECTANGLE; else -> InputButtonShape.ROUNDED },
|
||||
showLabel = parts.getOrNull(8) != "0").bounded()
|
||||
showLabel = key.labels).bounded()
|
||||
val action = when (kind) {
|
||||
InputElementKind.DPAD -> InputAction.Directions(codes.getOrElse(0) { 0 }, codes.getOrElse(1) { 0 }, codes.getOrElse(2) { 0 }, codes.getOrElse(3) { 0 })
|
||||
InputElementKind.STICK -> InputAction.Directions(codes.getOrElse(0) { 0 }, codes.getOrElse(2) { 0 }, codes.getOrElse(4) { 0 }, codes.getOrElse(6) { 0 }, listOf(1, 3, 5, 7).map { codes.getOrElse(it) { 0 } })
|
||||
@@ -80,3 +111,9 @@ internal object LegacyScreenKeyMigration {
|
||||
element to action
|
||||
}
|
||||
}
|
||||
|
||||
internal data class LegacyScreenKey(
|
||||
val codes: List<Int>, val x: Float, val y: Float, val size: Float,
|
||||
val glyph: String = "", val text: String = "", val image: String = "",
|
||||
val opacity: Float = 1f, val shape: Int = 0, val toggle: Boolean = false, val labels: Boolean = true,
|
||||
)
|
||||
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Rect
|
||||
import android.graphics.Typeface
|
||||
import android.os.Build
|
||||
import android.view.Gravity
|
||||
@@ -14,9 +15,15 @@ import android.view.WindowInsets
|
||||
import android.widget.FrameLayout
|
||||
import com.droiddeck.launcher.ui.InputSurfaceView
|
||||
|
||||
class OnScreenControls(context: Context, pad: PadBridge?) : FrameLayout(context) {
|
||||
private val surface = InputSurfaceView(context, pad, inputRole = InputRole.PRIMARY)
|
||||
class OnScreenControls(context: Context, pad: PadBridge?, val dock: OnScreenLayout.Dock? = null) : FrameLayout(context) {
|
||||
private val surface = InputSurfaceView(context, pad, inputRole = InputRole.PRIMARY, haptics = dock != null)
|
||||
private var layout: SavedInputLayout? = null
|
||||
private val safe = Rect()
|
||||
private var viewWidth = 0
|
||||
private var viewHeight = 0
|
||||
private val placements = object : LinkedHashMap<Placement, List<InputSurfaceElement>>(4, .75f, true) {
|
||||
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<Placement, List<InputSurfaceElement>>) = size > PLACEMENT_CACHE
|
||||
}
|
||||
private val quickToggle = QuickToggle(context)
|
||||
var isButtonsOnly = false
|
||||
private set
|
||||
@@ -54,25 +61,41 @@ class OnScreenControls(context: Context, pad: PadBridge?) : FrameLayout(context)
|
||||
render()
|
||||
}
|
||||
|
||||
private data class Placement(val layout: SavedInputLayout?, val width: Int, val height: Int, val safe: Rect, val buttonsOnly: Boolean)
|
||||
|
||||
private fun placed(): List<InputSurfaceElement> {
|
||||
val key = Placement(layout, viewWidth, viewHeight, Rect(safe), isButtonsOnly)
|
||||
return placements.getOrPut(key) {
|
||||
OnScreenLayout.elements(context, layout, viewWidth, viewHeight, safe, isButtonsOnly, dock)
|
||||
}
|
||||
}
|
||||
|
||||
private fun render() {
|
||||
val elements = layout?.elements.orEmpty()
|
||||
surface.updateCustomLayout(when {
|
||||
isButtonsOnly -> elements.filter { it.control == InputControl.GUIDE || it.control == InputControl.QAM || it.id == "builtin:keyboard" }
|
||||
isQuickHidden -> elements.filter { it.id == "builtin:keyboard" }
|
||||
else -> elements
|
||||
})
|
||||
val elements = placed()
|
||||
surface.updateCustomLayout(if (isQuickHidden) elements.filter { it.id == "builtin:keyboard" } else elements)
|
||||
val style = layout?.style ?: InputSurfaceStyle()
|
||||
surface.updateStyle(style)
|
||||
quickToggle.tint = style.tint
|
||||
quickToggle.alpha = style.opacity / 100f
|
||||
quickToggle.visibility = if (isButtonsOnly || layout == null) GONE else VISIBLE
|
||||
quickToggle.visibility = if (isButtonsOnly || layout == null || dock != null) GONE else VISIBLE
|
||||
quickToggle.invalidate()
|
||||
}
|
||||
|
||||
fun takesTouchAt(x: Float, y: Float) = surface.takesTouchAt(x, y) ||
|
||||
quickToggle.visibility == VISIBLE && x >= quickToggle.left && x < quickToggle.right && y >= quickToggle.top && y < quickToggle.bottom
|
||||
fun releaseAll() = surface.releaseInputs()
|
||||
fun reload() { releaseAll(); render() }
|
||||
fun reload() { releaseAll(); placements.clear(); render() }
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val w = MeasureSpec.getSize(widthMeasureSpec)
|
||||
val h = MeasureSpec.getSize(heightMeasureSpec)
|
||||
if (w != viewWidth || h != viewHeight) {
|
||||
viewWidth = w
|
||||
viewHeight = h
|
||||
render()
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() { releaseAll(); super.onDetachedFromWindow() }
|
||||
|
||||
@@ -87,6 +110,11 @@ class OnScreenControls(context: Context, pad: PadBridge?) : FrameLayout(context)
|
||||
params.bottomMargin = bottom
|
||||
quickToggle.layoutParams = params
|
||||
}
|
||||
val fresh = Rect(cutout?.safeInsetLeft ?: 0, if (dock == null) cutout?.safeInsetTop ?: 0 else 0, cutout?.safeInsetRight ?: 0, cutout?.safeInsetBottom ?: 0)
|
||||
if (fresh != safe) {
|
||||
safe.set(fresh)
|
||||
render()
|
||||
}
|
||||
return super.onApplyWindowInsets(insets)
|
||||
}
|
||||
|
||||
@@ -136,5 +164,6 @@ class OnScreenControls(context: Context, pad: PadBridge?) : FrameLayout(context)
|
||||
const val QUICK_CENTER_DP = 34f
|
||||
const val QUICK_HIT_DP = 26f
|
||||
const val QUICK_RADIUS_DP = 18f
|
||||
const val PLACEMENT_CACHE = 4
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.droiddeck.launcher.input
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
object OnScreenLayout {
|
||||
data class Dock(val portrait: Boolean, val grips: Boolean)
|
||||
|
||||
private const val TOLERANCE = .01f
|
||||
private const val KEYBOARD_ID = "builtin:keyboard"
|
||||
|
||||
fun elements(context: Context, layout: SavedInputLayout?, width: Int, height: Int, safe: Rect,
|
||||
buttonsOnly: Boolean = false, dock: Dock? = null): List<InputSurfaceElement> {
|
||||
val stored = layout?.elements ?: return emptyList()
|
||||
if (width <= 0 || height <= 0) return stored
|
||||
val generator = LegacyGamepadLayout(context, width, height, safe, layout.scale)
|
||||
if (buttonsOnly && dock == null) return generator.buttonsOnly(stored)
|
||||
val (reference, generated) = reference(context, layout, width, height)
|
||||
val gamepad = if (generated) stored.filter(::isGamepad) else emptyList()
|
||||
val others = fit(stored.filterNot { generated && isGamepad(it) }, reference.first, reference.second, width, height, safe)
|
||||
val placed = when {
|
||||
gamepad.isEmpty() -> emptyList()
|
||||
dock != null -> generator.dock(gamepad, dock.portrait, dock.grips)
|
||||
else -> generator.regenerate(gamepad)
|
||||
}
|
||||
val byId = (placed + others).associateBy { it.id }
|
||||
return stored.mapNotNull { byId[it.id] } + placed.filter { p -> stored.none { it.id == p.id } }
|
||||
}
|
||||
|
||||
fun fit(elements: List<InputSurfaceElement>, referenceWidth: Float, referenceHeight: Float, width: Int, height: Int, safe: Rect): List<InputSurfaceElement> {
|
||||
val w = width.toFloat()
|
||||
val h = height.toFloat()
|
||||
val scale = min(w / referenceWidth, h / referenceHeight)
|
||||
return elements.map { e ->
|
||||
val ew = e.width * referenceWidth * scale
|
||||
val eh = e.height * referenceHeight * scale
|
||||
val left = anchor(e.x, e.width, referenceWidth, w, scale).coerceIn(safe.left.toFloat(), max(safe.left.toFloat(), w - safe.right - ew))
|
||||
val top = anchor(e.y, e.height, referenceHeight, h, scale).coerceIn(safe.top.toFloat(), max(safe.top.toFloat(), h - safe.bottom - eh))
|
||||
e.copy(x = left / w, y = top / h, width = ew / w, height = eh / h).bounded()
|
||||
}
|
||||
}
|
||||
|
||||
private fun anchor(start: Float, size: Float, reference: Float, actual: Float, scale: Float): Float {
|
||||
val centre = start + size / 2f
|
||||
val scaled = size * reference * scale
|
||||
return when {
|
||||
centre < 1f / 3f -> start * reference * scale
|
||||
centre > 2f / 3f -> actual - (1f - start - size) * reference * scale - scaled
|
||||
else -> centre * actual - scaled / 2f
|
||||
}
|
||||
}
|
||||
|
||||
private fun isGamepad(e: InputSurfaceElement) = e.id.startsWith("legacy:") || e.id == KEYBOARD_ID
|
||||
|
||||
fun generatedSize(context: Context, layout: SavedInputLayout, width: Int, height: Int): Pair<Int, Int>? =
|
||||
reference(context, layout, width, height).takeIf { it.second }?.first?.let { it.first.toInt() to it.second.toInt() }
|
||||
|
||||
private fun reference(context: Context, layout: SavedInputLayout, width: Int, height: Int): Pair<Pair<Float, Float>, Boolean> {
|
||||
val (display, metrics) = InputLibraries.primaryDisplay(context)
|
||||
val long = max(metrics.widthPixels, metrics.heightPixels).coerceAtLeast(1)
|
||||
val short = min(metrics.widthPixels, metrics.heightPixels).coerceAtLeast(1)
|
||||
val gamepad = layout.elements.filter(::isGamepad)
|
||||
if (gamepad.any { it.id.startsWith("legacy:") }) {
|
||||
val named = layout.id.removePrefix("migrated.layout.").takeIf { it != layout.id }?.split('x')?.mapNotNull { it.toIntOrNull() }
|
||||
?.takeIf { it.size == 2 && it.all { size -> size > 0 } }?.let { it[0] to it[1] }
|
||||
for ((w, h) in listOfNotNull(named, width to height, long to short, short to long).distinct()) {
|
||||
if (matches(gamepad, LegacyGamepadLayout(display, w, h, scale = layout.scale).elements())) return (w.toFloat() to h.toFloat()) to true
|
||||
}
|
||||
}
|
||||
val aspect = layout.aspect.takeIf { it > 0f } ?: (long.toFloat() / short)
|
||||
return (aspect to 1f) to false
|
||||
}
|
||||
|
||||
private fun matches(stored: List<InputSurfaceElement>, generated: List<InputSurfaceElement>): Boolean {
|
||||
val byId = generated.associateBy { it.id }
|
||||
return stored.all { e ->
|
||||
val g = byId[e.id] ?: return@all false
|
||||
abs(e.x - g.x) <= TOLERANCE && abs(e.y - g.y) <= TOLERANCE && abs(e.width - g.width) <= TOLERANCE && abs(e.height - g.height) <= TOLERANCE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.droiddeck.launcher.input
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.view.Display
|
||||
import androidx.annotation.StringRes
|
||||
import com.droiddeck.launcher.R
|
||||
import com.droiddeck.launcher.session.SessionPrefs
|
||||
|
||||
enum class SecondScreenMode(val id: String, @StringRes val label: Int, val bindings: String? = null) {
|
||||
NONE("none", R.string.second_mode_none),
|
||||
@@ -16,6 +18,8 @@ enum class SecondScreenMode(val id: String, @StringRes val label: Int, val bindi
|
||||
|
||||
val controls: Boolean get() = this == CUSTOM_CONTROLS || bindings != null
|
||||
|
||||
fun panel(context: Context): String? = if (this == DECK_CONTROLS) SessionPrefs.deckPanel(context).bindings else bindings
|
||||
|
||||
companion object {
|
||||
fun opening(remembered: String?, deckPad: Boolean, dashboard: Boolean = false, bottomDesktop: Boolean = false, desktopSession: Boolean = false): SecondScreenMode {
|
||||
entries.firstOrNull {
|
||||
|
||||
@@ -1558,6 +1558,13 @@ object SessionPrefs {
|
||||
prefs(context).edit().putString(if (right) "gamepadRight" else "gamepadLeft", surface).apply()
|
||||
}
|
||||
|
||||
fun deckPanel(context: Context): com.droiddeck.launcher.input.DeckPanel =
|
||||
com.droiddeck.launcher.input.DeckPanel.from(prefs(context).getString("deckPanel", null))
|
||||
|
||||
fun setDeckPanel(context: Context, panel: com.droiddeck.launcher.input.DeckPanel) {
|
||||
prefs(context).edit().putString("deckPanel", panel.id).apply()
|
||||
}
|
||||
|
||||
fun suspendPolicy(context: Context, mode: String): String =
|
||||
prefs(context).getString("suspendPolicy.${prefMode(mode)}",
|
||||
if (mode == SessionService.MODE_STEAM) SUSPEND_NATIVE else SUSPEND_MANUAL)
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -47,6 +48,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.droiddeck.launcher.R
|
||||
import com.droiddeck.launcher.input.DeckPanel
|
||||
import com.droiddeck.launcher.session.SessionService
|
||||
import com.droiddeck.launcher.session.SessionState
|
||||
|
||||
@@ -59,6 +61,8 @@ internal class BarExtra(
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
|
||||
internal class BarTabs(val labels: List<String>, val selected: Int, val onSelect: (Int) -> Unit)
|
||||
|
||||
internal class BottomBarModel(
|
||||
val title: String?,
|
||||
val onClose: (() -> Unit)?,
|
||||
@@ -67,10 +71,22 @@ internal class BottomBarModel(
|
||||
val onQam: (() -> Unit)?,
|
||||
val extras: List<BarExtra> = emptyList(),
|
||||
val menuActive: Boolean = false,
|
||||
val tabs: BarTabs? = null,
|
||||
)
|
||||
|
||||
@Composable
|
||||
internal fun BottomScreenBar(model: BottomBarModel, modifier: Modifier = Modifier) {
|
||||
val tabs = model.tabs
|
||||
if (tabs == null) BarRow(model, modifier) else Column(modifier.fillMaxWidth().blockTouches()) {
|
||||
BarRow(model)
|
||||
Box(Modifier.fillMaxWidth().padding(start = BAR_PAD, end = BAR_PAD, bottom = 8.dp), contentAlignment = Alignment.Center) {
|
||||
TabStrip(tabs.labels, tabs.selected, tabs.onSelect, Modifier.testTag("bottom-bar-tabs"), bumpers = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BarRow(model: BottomBarModel, modifier: Modifier = Modifier) {
|
||||
val colors = MaterialTheme.colorScheme
|
||||
BoxWithConstraints(modifier.fillMaxWidth().height(BAR_HEIGHT).blockTouches()) {
|
||||
val buttons = listOfNotNull(model.onClose, model.onMenu, model.onQam).size + model.extras.size
|
||||
@@ -195,11 +211,15 @@ internal fun sessionBarModel(
|
||||
onSteam: () -> Unit,
|
||||
onQam: () -> Unit,
|
||||
extras: List<BarExtra> = emptyList(),
|
||||
tabs: BarTabs? = null,
|
||||
): BottomBarModel {
|
||||
val steam = SessionState.mode == SessionService.MODE_STEAM
|
||||
return BottomBarModel(title, onClose, onMenu, onSteam.takeIf { steam }, onQam.takeIf { steam }, extras)
|
||||
return BottomBarModel(title, onClose, onMenu, onSteam.takeIf { steam }, onQam.takeIf { steam }, extras, tabs = tabs)
|
||||
}
|
||||
|
||||
internal fun deckPanelTabs(context: Context, selected: DeckPanel, onSelect: (DeckPanel) -> Unit) =
|
||||
BarTabs(DeckPanel.entries.map { context.getString(it.label) }, selected.ordinal) { onSelect(DeckPanel.entries[it]) }
|
||||
|
||||
internal fun bottomScreenBarView(context: Context, model: () -> BottomBarModel): ComposeView = ComposeView(context).apply {
|
||||
setContent { DroidDeckTheme { BottomScreenBar(model()) } }
|
||||
}
|
||||
@@ -6,20 +6,38 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import com.droiddeck.launcher.input.*
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import com.droiddeck.launcher.R
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
internal fun InputElementProperties(element: InputSurfaceElement, onChange: (InputSurfaceElement) -> Unit) {
|
||||
val current by rememberUpdatedState(element)
|
||||
val change by rememberUpdatedState(onChange)
|
||||
OutlinedTextField(element.name, { onChange(element.copy(name = it.take(80))) }, label = { Text(stringResource(R.string.input_name)) },
|
||||
singleLine = true, modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp))
|
||||
if (element.kind == InputElementKind.BUTTON || element.kind == InputElementKind.TRIGGER) {
|
||||
val host = rememberMenuHost()
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val pickImage = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
if (uri != null) scope.launch {
|
||||
withContext(Dispatchers.IO) { InputButtonImages.import(context.applicationContext, uri) }?.let { change(current.copy(icon = 0, image = it)) }
|
||||
}
|
||||
}
|
||||
ToggleRow(host, "element-toggle", stringResource(R.string.input_toggle_button), stringResource(R.string.input_toggle_button_hint), element.toggle) { onChange(element.copy(toggle = it)) }
|
||||
ChoiceRow(host, "element-shape", stringResource(R.string.input_button_shape), null,
|
||||
InputButtonShape.entries.map { it to stringResource(when (it) { InputButtonShape.ROUNDED -> R.string.input_shape_rounded; InputButtonShape.PILL -> R.string.input_shape_pill; InputButtonShape.CIRCLE -> R.string.input_shape_circle; InputButtonShape.RECTANGLE -> R.string.input_shape_rectangle }) },
|
||||
@@ -30,6 +48,7 @@ internal fun InputElementProperties(element: InputSurfaceElement, onChange: (Inp
|
||||
ValueChip(if (element.image.isNotEmpty()) stringResource(R.string.input_imported_image) else if (element.icon == 0) stringResource(R.string.input_button_text) else InputButtonIcons.label(context, element.icon), open) { host.open = if (open) null else "element-icon" }
|
||||
AnchoredMenu(open, onDismiss = { host.open = null }, title = stringResource(R.string.input_button_symbol)) { firstItemFocus ->
|
||||
MenuItem(stringResource(R.string.input_button_text), element.icon == 0 && element.image.isEmpty(), focusRequester = firstItemFocus) { onChange(element.copy(icon = 0, image = "")); host.open = null }
|
||||
MenuItem(stringResource(R.string.screen_key_image), element.image.isNotEmpty()) { host.open = null; pickImage.launch("image/*") }
|
||||
for (code in InputButtonIcons.codes) MenuItem(InputButtonIcons.label(context, code), element.icon == code && element.image.isEmpty(), leading = {
|
||||
val color = MaterialTheme.colorScheme.onSurface
|
||||
val symbol = remember(context, code) { InputButtonIcons.drawable(context, code) }
|
||||
@@ -51,4 +70,10 @@ internal fun InputElementProperties(element: InputSurfaceElement, onChange: (Inp
|
||||
ToggleRow(host, "element-floating", stringResource(R.string.input_floating_stick), null, element.floating) { onChange(element.copy(floating = it)) }
|
||||
ToggleRow(host, "element-hide-idle", stringResource(R.string.input_hide_idle), null, element.hideWhenIdle) { onChange(element.copy(hideWhenIdle = it)) }
|
||||
}
|
||||
val host = rememberMenuHost()
|
||||
if ((element.kind == InputElementKind.BUTTON || element.kind == InputElementKind.TRIGGER) && element.icon == 0 && element.image.isEmpty() ||
|
||||
element.kind == InputElementKind.STICK && element.id.startsWith("legacy:"))
|
||||
ToggleRow(host, "element-label", stringResource(R.string.input_show_label), null, element.showLabel) { onChange(element.copy(showLabel = it)) }
|
||||
SliderRow(stringResource(R.string.ctrl_opacity), null, (element.opacity * 100).roundToInt().coerceIn(20, 100), 20..100, step = 5,
|
||||
format = { "$it%" }, modifier = Modifier.testTag("setting-element-opacity")) { onChange(element.copy(opacity = it / 100f)) }
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
package com.droiddeck.launcher.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.util.DisplayMetrics
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.focusGroup
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
@@ -21,6 +27,9 @@ import androidx.compose.ui.window.DialogProperties
|
||||
import com.droiddeck.launcher.R
|
||||
import com.droiddeck.launcher.input.*
|
||||
import com.droiddeck.launcher.session.SessionPrefs
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun InputSettingsDialog(onBack: () -> Unit, onChanged: () -> Unit) {
|
||||
@@ -88,7 +97,9 @@ private fun InputSettingsContent(onBack: () -> Unit, onChanged: () -> Unit, embe
|
||||
LaunchedEffect(surface) { onSurfaceEditing(surface) }
|
||||
DisposableEffect(Unit) { onDispose { onSurfaceEditing(false) } }
|
||||
var managingLayout by remember { mutableStateOf<SavedInputLayout?>(null) }
|
||||
var exporting by remember { mutableStateOf<String?>(null) }
|
||||
var error by remember { mutableStateOf<String?>(null) }
|
||||
val scope = rememberCoroutineScope()
|
||||
val controller = rememberControllerSettings()
|
||||
var oscMode by remember { mutableStateOf(SessionPrefs.oscMode(context)) }
|
||||
fun update(change: (InputLibrary) -> InputLibrary): Boolean = runCatching { InputLibraries.update(context, change) }
|
||||
@@ -107,6 +118,27 @@ private fun InputSettingsContent(onBack: () -> Unit, onChanged: () -> Unit, embe
|
||||
val profile = library.profile(profileId)
|
||||
val preset = library.preset(profile.binding(role))
|
||||
val layout = library.layout(profileId, role)
|
||||
val importer = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
|
||||
if (uri == null) return@rememberLauncherForActivityResult
|
||||
val target = role
|
||||
scope.launch {
|
||||
val raw = withContext(Dispatchers.IO) { readLayoutFile(context, uri) }
|
||||
val metrics = inputDisplayMetrics(context, target)
|
||||
val imported = raw?.let { InputLayoutFile.import(context, it, layoutFileName(context, uri) ?: context.getString(R.string.ctrl_layout),
|
||||
if (target == InputRole.PRIMARY) InputLayoutScreen.MAIN else InputLayoutScreen.SECONDARY, layout?.style ?: InputSurfaceStyle(),
|
||||
metrics.widthPixels, metrics.heightPixels, metrics.density) }
|
||||
if (imported == null) error = context.getString(R.string.input_layout_import_failed)
|
||||
else if (update { it.withLayout(imported.first).withPreset(imported.second).chooseLayout(profileId, target, imported.first.id) }) go(InputPage.SOURCE)
|
||||
}
|
||||
}
|
||||
val exporter = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("application/json")) { uri ->
|
||||
val text = exporting
|
||||
exporting = null
|
||||
if (uri != null && text != null) scope.launch {
|
||||
val saved = withContext(Dispatchers.IO) { runCatching { context.contentResolver.openOutputStream(uri, "wt")?.use { it.write(text.toByteArray()) } != null }.getOrDefault(false) }
|
||||
if (!saved) error = context.getString(R.string.input_save_failed)
|
||||
}
|
||||
}
|
||||
fun rename(title: Int, name: String, save: (String) -> Unit) {
|
||||
naming = InputNameRequest(title, name) { value, _, _ -> save(value) }
|
||||
}
|
||||
@@ -249,6 +281,8 @@ private fun InputSettingsContent(onBack: () -> Unit, onChanged: () -> Unit, embe
|
||||
InputColorRow(host, layout.style.tint) { color -> update { it.withLayout(layout.copy(style = layout.style.copy(tint = color))) } }
|
||||
SliderRow(stringResource(R.string.ctrl_opacity), null, layout.style.opacity, 1..100, step = 1,
|
||||
format = { "$it%" }) { opacity -> update { it.withLayout(layout.copy(style = layout.style.copy(opacity = opacity))) } }
|
||||
for (button in layout.quickButtons) ToggleRow(host, "quick-${button.name.lowercase()}", stringResource(quickButtonLabel(button)), null,
|
||||
button !in layout.style.hidden) { on -> update { it.withLayout(layout.withQuickButton(button, on)) } }
|
||||
}
|
||||
if (role == InputRole.SECONDARY) InputHint(stringResource(R.string.input_second_screen_enable))
|
||||
}
|
||||
@@ -302,10 +336,14 @@ private fun InputSettingsContent(onBack: () -> Unit, onChanged: () -> Unit, embe
|
||||
if (other.isNotEmpty()) PadTextButton(onClick = { showOther = !showOther }, modifier = Modifier.padding(8.dp)) {
|
||||
Text(stringResource(if (showOther) R.string.input_hide_other_layouts else R.string.input_other_layouts, other.size))
|
||||
}
|
||||
PadTextButton(onClick = { naming = InputNameRequest(R.string.input_new_layout, "") { name, _, _ ->
|
||||
val created = SavedInputLayout(newInputId(), name, screen = if (role == InputRole.PRIMARY) InputLayoutScreen.MAIN else InputLayoutScreen.SECONDARY)
|
||||
if (update { it.withLayout(created).useLayout(profileId, role, created.id, shared = true) }) { go(InputPage.SOURCE); surface = true }
|
||||
} }, modifier = Modifier.padding(8.dp)) { Text(stringResource(R.string.input_new_layout)) }
|
||||
Row {
|
||||
PadTextButton(onClick = { naming = InputNameRequest(R.string.input_new_layout, "") { name, _, _ ->
|
||||
val created = SavedInputLayout(newInputId(), name, screen = if (role == InputRole.PRIMARY) InputLayoutScreen.MAIN else InputLayoutScreen.SECONDARY)
|
||||
if (update { it.withLayout(created).useLayout(profileId, role, created.id, shared = true) }) { go(InputPage.SOURCE); surface = true }
|
||||
} }, modifier = Modifier.padding(8.dp)) { Text(stringResource(R.string.input_new_layout)) }
|
||||
PadTextButton(onClick = { importer.launch(arrayOf("application/json", "text/plain", "application/octet-stream", "*/*")) },
|
||||
modifier = Modifier.padding(8.dp).testTag("input-layout-import")) { Text(stringResource(R.string.boot_movie_import)) }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -329,6 +367,16 @@ private fun InputSettingsContent(onBack: () -> Unit, onChanged: () -> Unit, embe
|
||||
managingLayout = null
|
||||
rename(R.string.input_rename_layout, saved.name) { name -> update { it.withLayout(saved.copy(name = name)) } }
|
||||
}
|
||||
val exported = remember(saved, library) {
|
||||
val metrics = inputDisplayMetrics(context, if (saved.screen == InputLayoutScreen.SECONDARY) InputRole.SECONDARY else InputRole.PRIMARY)
|
||||
InputLayoutFile.export(saved, library.bindings.firstOrNull { it.id == preset.id && it.layoutId == saved.id }
|
||||
?: library.bindings.firstOrNull { it.layoutId == saved.id }, metrics.widthPixels, metrics.heightPixels)
|
||||
}
|
||||
if (exported != null) SecondaryButton(stringResource(R.string.screen_key_layout_export)) {
|
||||
managingLayout = null
|
||||
exporting = exported
|
||||
exporter.launch(InputLayoutFile.fileName(saved))
|
||||
}
|
||||
val used = library.usersOfLayout(saved.id).isNotEmpty() || library.bindings.any { it.layoutId == saved.id && library.selectedBindings(it.id) }
|
||||
if (!used && saved.editable) SecondaryButton(stringResource(R.string.input_delete)) {
|
||||
managingLayout = null
|
||||
@@ -413,6 +461,38 @@ private fun InputNavigationRow(title: String, detail: String?, modifier: Modifie
|
||||
}
|
||||
}
|
||||
|
||||
internal fun quickButtonLabel(button: InputCommand) = when (button) {
|
||||
InputCommand.STEAM -> R.string.ctrl_steam_button
|
||||
InputCommand.QUICK_ACCESS -> R.string.ctrl_qam_button
|
||||
else -> R.string.ctrl_keyboard_button
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
internal fun inputDisplayMetrics(context: Context, role: InputRole): DisplayMetrics = DisplayMetrics().also { metrics ->
|
||||
(context.findActivity() as? com.droiddeck.launcher.SessionActivity)?.inputEditorDisplay(role)?.getRealMetrics(metrics)
|
||||
?: metrics.setTo(context.resources.displayMetrics)
|
||||
}
|
||||
|
||||
private fun readLayoutFile(context: Context, uri: Uri): String? = runCatching {
|
||||
context.contentResolver.openInputStream(uri)?.use { input ->
|
||||
val out = java.io.ByteArrayOutputStream()
|
||||
val buffer = ByteArray(8192)
|
||||
while (true) {
|
||||
val read = input.read(buffer)
|
||||
if (read < 0) break
|
||||
out.write(buffer, 0, read)
|
||||
if (out.size() > 1_000_000) return@use null
|
||||
}
|
||||
out.toString(Charsets.UTF_8.name())
|
||||
}
|
||||
}.getOrNull()
|
||||
|
||||
private fun layoutFileName(context: Context, uri: Uri): String? = runCatching {
|
||||
context.contentResolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { cursor ->
|
||||
if (cursor.moveToFirst()) cursor.getString(0)?.substringBeforeLast('.')?.trim()?.takeIf { it.isNotEmpty() } else null
|
||||
}
|
||||
}.getOrNull()
|
||||
|
||||
@Composable
|
||||
internal fun roleLabel(role: InputRole) = stringResource(when (role) {
|
||||
InputRole.PHYSICAL -> R.string.input_physical; InputRole.PRIMARY -> R.string.input_primary; InputRole.SECONDARY -> R.string.input_secondary
|
||||
|
||||
@@ -58,7 +58,18 @@ import com.droiddeck.launcher.SessionActivity
|
||||
import com.droiddeck.launcher.input.*
|
||||
import com.droiddeck.launcher.session.SessionState
|
||||
|
||||
private class SurfaceDraft(val layout: SavedInputLayout, val preset: SavedInputBindings) {
|
||||
private data class SurfaceSnapshot(val elements: List<InputSurfaceElement>, val actions: Map<String, InputAction>,
|
||||
val clicks: Map<String, InputAction>, val scale: Float)
|
||||
|
||||
private class GamepadScaler(private val context: android.content.Context, private val width: Int, private val height: Int) {
|
||||
private fun generator(scale: Float) = LegacyGamepadLayout(context, width, height, scale = scale)
|
||||
val ids = generator(1f).elements().map { it.id }.toSet()
|
||||
fun rescale(stored: List<InputSurfaceElement>, from: Float, to: Float) = generator(to).rescale(stored, generator(from))
|
||||
fun reset(stored: List<InputSurfaceElement>) = generator(1f).regenerate(stored).associateBy { it.id }.let { placed -> stored.map { placed[it.id] ?: it } }
|
||||
}
|
||||
|
||||
private class SurfaceDraft(val layout: SavedInputLayout, val preset: SavedInputBindings, val defaults: List<InputSurfaceElement>? = null,
|
||||
private val gamepad: GamepadScaler? = null) {
|
||||
var elements by mutableStateOf(layout.elements)
|
||||
var actions by mutableStateOf(preset.elements)
|
||||
var clicks by mutableStateOf(preset.clicks)
|
||||
@@ -70,15 +81,41 @@ private class SurfaceDraft(val layout: SavedInputLayout, val preset: SavedInputB
|
||||
var adding by mutableStateOf(false)
|
||||
var properties by mutableStateOf(false)
|
||||
var clickProperties by mutableStateOf(false)
|
||||
var history by mutableStateOf<List<Triple<List<InputSurfaceElement>, Map<String, InputAction>, Map<String, InputAction>>>>(emptyList())
|
||||
var history by mutableStateOf<List<SurfaceSnapshot>>(emptyList())
|
||||
var layoutScale by mutableFloatStateOf(layout.scale)
|
||||
private var scaleBase by mutableStateOf<Triple<List<InputSurfaceElement>, List<InputSurfaceElement>, Float>?>(null)
|
||||
private var scaleValue by mutableIntStateOf(100)
|
||||
private val rescales get() = gamepad != null && elements.any { it.id in gamepad.ids }
|
||||
val scale get() = when {
|
||||
scaleBase?.second == elements -> scaleValue
|
||||
rescales -> (layoutScale * 100).roundToInt()
|
||||
else -> 100
|
||||
}
|
||||
val positioned get() = (if (rescales) gamepad!!.reset(elements) else defaults?.let { elements.withPositionsOf(it) })
|
||||
?.takeIf { it != elements || rescales && layoutScale != 1f }
|
||||
val element get() = elements.firstOrNull { it.id == selected }
|
||||
val dirty get() = elements != layout.elements || actions != preset.elements || clicks != preset.clicks
|
||||
fun checkpoint() { history = (history + Triple(elements, actions, clicks)).takeLast(40) }
|
||||
fun undo() { history.lastOrNull()?.let { elements = it.first; actions = it.second; clicks = it.third; history = history.dropLast(1) } }
|
||||
val dirty get() = elements != layout.elements || actions != preset.elements || clicks != preset.clicks || layoutScale != layout.scale
|
||||
fun checkpoint() { history = (history + SurfaceSnapshot(elements, actions, clicks, layoutScale)).takeLast(40) }
|
||||
fun undo() { history.lastOrNull()?.let { elements = it.elements; actions = it.actions; clicks = it.clicks; layoutScale = it.scale; history = history.dropLast(1) } }
|
||||
fun scaleAll(percent: Int) {
|
||||
val base = scaleBase?.takeIf { it.second == elements } ?: Triple(elements, elements, if (rescales) layoutScale else 0f).also { checkpoint() }
|
||||
val factor = percent / 100f
|
||||
elements = if (base.third > 0f && gamepad != null) {
|
||||
layoutScale = factor
|
||||
val others = base.first.filterNot { it.id in gamepad.ids }.scaled(factor / base.third).associateBy { it.id }
|
||||
gamepad.rescale(base.first, base.third, factor).map { others[it.id] ?: it }
|
||||
} else base.first.scaled(factor)
|
||||
scaleValue = percent; scaleBase = Triple(base.first, elements, base.third)
|
||||
}
|
||||
fun resetPositions() { positioned?.let { checkpoint(); elements = it; if (rescales) layoutScale = 1f } }
|
||||
fun action(e: InputSurfaceElement) = preset.copy(elements = actions).action(e)
|
||||
fun clickAction(e: InputSurfaceElement) = preset.copy(elements = actions, clicks = clicks).clickAction(e)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun displayAspect(display: Display): Float? = android.util.DisplayMetrics().also(display::getRealMetrics)
|
||||
.takeIf { it.widthPixels > 0 && it.heightPixels > 0 }?.let { (it.widthPixels.toFloat() / it.heightPixels).coerceIn(.05f, 20f) }
|
||||
|
||||
@Composable
|
||||
fun InputSurfaceDialog(profile: String, onDismiss: () -> Unit, onChanged: () -> Unit,
|
||||
role: InputRole = InputRole.SECONDARY, layoutId: String? = null, bindingsId: String? = null) {
|
||||
@@ -89,7 +126,14 @@ fun InputSurfaceDialog(profile: String, onDismiss: () -> Unit, onChanged: () ->
|
||||
val savedBindings = remember { library.preset(bindingsId ?: library.profile(profile).binding(role)) }
|
||||
val layoutUsers = library.usersOfLayout(savedLayout.id).size
|
||||
val bindingUsers = library.usersOfBindings(savedBindings.id).size
|
||||
val draft = remember { SurfaceDraft(savedLayout, savedBindings) }
|
||||
val draft = remember {
|
||||
val (display, metrics) = InputLibraries.primaryDisplay(context)
|
||||
val gamepad = savedLayout.elements.takeIf { e -> e.any { it.id.startsWith("legacy:") } }?.let {
|
||||
val (w, h) = OnScreenLayout.generatedSize(context, savedLayout, metrics.widthPixels, metrics.heightPixels) ?: (metrics.widthPixels to metrics.heightPixels)
|
||||
GamepadScaler(display, w, h)
|
||||
}
|
||||
SurfaceDraft(savedLayout, savedBindings, InputLibraries.defaultPositions(context, library, savedLayout), gamepad)
|
||||
}
|
||||
val manager = remember { context.getSystemService(DisplayManager::class.java) }
|
||||
var revision by remember { mutableIntStateOf(0) }
|
||||
var discard by remember { mutableStateOf(false) }
|
||||
@@ -109,7 +153,7 @@ fun InputSurfaceDialog(profile: String, onDismiss: () -> Unit, onChanged: () ->
|
||||
InputLibraries.update(context) { latest ->
|
||||
val l = latest.layouts.first { it.id == savedLayout.id }
|
||||
val p = latest.preset(savedBindings.id)
|
||||
latest.withLayout(l.copy(elements = draft.elements)).withPreset(p.copy(elements = draft.actions.filterKeys { id -> draft.elements.any { it.id == id } },
|
||||
latest.withLayout(l.copy(elements = draft.elements, aspect = target?.let(::displayAspect) ?: l.aspect, scale = draft.layoutScale)).withPreset(p.copy(elements = draft.actions.filterKeys { id -> draft.elements.any { it.id == id } },
|
||||
clicks = draft.clicks.filterKeys { id -> draft.elements.any { it.id == id && it.hasClick } }))
|
||||
}
|
||||
}.onSuccess { onChanged(); onDismiss() }.onFailure { failure = it.message ?: context.getString(R.string.input_save_failed) }
|
||||
@@ -204,7 +248,7 @@ private fun SurfaceCanvas(draft: SurfaceDraft, transparent: Boolean = false) {
|
||||
AndroidView(factory = { InputSurfaceEditorView(it) }, modifier = Modifier.fillMaxSize().testTag("input-layout-canvas"),
|
||||
update = { view ->
|
||||
view.setBackgroundColor(if (transparent) android.graphics.Color.TRANSPARENT else android.graphics.Color.rgb(10, 11, 13))
|
||||
view.style = draft.layout.style; view.elements = draft.elements; view.selected = draft.selected; view.snap = draft.snap
|
||||
view.style = draft.layout.style.copy(hidden = emptySet()); view.elements = draft.elements; view.selected = draft.selected; view.snap = draft.snap
|
||||
view.isEnabled = !draft.properties && !draft.adding
|
||||
view.onSelect = { if (!draft.properties) draft.selected = it }
|
||||
view.onBeginEdit = draft::checkpoint
|
||||
@@ -269,12 +313,15 @@ private fun SurfaceToolbar(draft: SurfaceDraft, onSave: () -> Unit, onLeave: ()
|
||||
SecondaryButton(stringResource(R.string.common_cancel), compact = true, onClick = onLeave)
|
||||
SecondaryButton(stringResource(R.string.input_editor_add), enabled = draft.elements.size < 64, compact = true) { draft.adding = true }
|
||||
SecondaryButton(stringResource(R.string.input_editor_undo), enabled = draft.history.isNotEmpty(), compact = true) { draft.undo() }
|
||||
if (draft.defaults != null) SecondaryButton(stringResource(R.string.input_reset_positions), enabled = draft.positioned != null, compact = true) { draft.resetPositions() }
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(draft.snap, { draft.snap = it })
|
||||
Text(stringResource(R.string.ctrl_editor_snap))
|
||||
}
|
||||
PrimaryButton(stringResource(R.string.input_editor_done), compact = true, onClick = onSave)
|
||||
}
|
||||
if (draft.elements.isNotEmpty()) SliderRow(stringResource(R.string.ctrl_size), null, draft.scale, 80..125, step = 5,
|
||||
format = { "$it%" }, modifier = Modifier.testTag("input-editor-scale")) { draft.scaleAll(it) }
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.droiddeck.launcher.input.PointerGestures
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.HorizontalScrollView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.droiddeck.launcher.input.InputRole
|
||||
@@ -35,7 +34,7 @@ import com.droiddeck.launcher.input.InputSurfaceSource
|
||||
import com.droiddeck.launcher.input.InputElementKind
|
||||
import com.droiddeck.launcher.input.InputButtonIcons
|
||||
import com.droiddeck.launcher.input.InputButtonShape
|
||||
import java.io.File
|
||||
import com.droiddeck.launcher.input.InputButtonImages
|
||||
import com.droiddeck.launcher.input.PadBridge
|
||||
import com.droiddeck.launcher.session.SessionPrefs
|
||||
import kotlin.math.atan2
|
||||
@@ -49,40 +48,94 @@ class InputSurfaceView(
|
||||
private var customLayout: List<InputSurfaceElement> = emptyList(),
|
||||
private val inputRole: InputRole = InputRole.SECONDARY,
|
||||
private var surfaceStyle: InputSurfaceStyle = InputSurfaceStyle(),
|
||||
private val haptics: Boolean = inputRole != InputRole.PRIMARY,
|
||||
) : FrameLayout(context) {
|
||||
private val content = FrameLayout(context)
|
||||
private val elementSources = ArrayList<InputSurfaceSource>()
|
||||
private var customCanvas: ViewGroup? = null
|
||||
init { addView(content, LayoutParams(-1, -1)); renderCustom(pad) }
|
||||
private val owners = HashMap<Int, View>()
|
||||
private var requestedLayout = customLayout
|
||||
init { customLayout = surfaceStyle.shown(customLayout); addView(content, LayoutParams(-1, -1)); renderCustom(pad) }
|
||||
|
||||
var onTouchMiss: ((MotionEvent) -> Unit)? = null
|
||||
private var forwardedPointers = 0
|
||||
|
||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) forwardedPointers = 0
|
||||
if (onTouchMiss == null) return super.dispatchTouchEvent(event)
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) { forwardedPointers = 0; cancelOwners(event) }
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN || event.actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
val index = event.actionIndex
|
||||
if (!takesTouchAt(event.getX(index), event.getY(index))) forwardedPointers = forwardedPointers or (1 shl event.getPointerId(index))
|
||||
else if (SessionPrefs.lowLatency(context)) requestUnbufferedDispatch(event)
|
||||
if (event.getToolType(index) == MotionEvent.TOOL_TYPE_MOUSE || !takesTouchAt(event.getX(index), event.getY(index)))
|
||||
forwardedPointers = forwardedPointers or (1 shl event.getPointerId(index))
|
||||
else if (onTouchMiss != null && SessionPrefs.lowLatency(context)) requestUnbufferedDispatch(event)
|
||||
}
|
||||
if (forwardedPointers == 0) return super.dispatchTouchEvent(event)
|
||||
if (forwardedPointers == 0) return route(event)
|
||||
var all = 0
|
||||
for (index in 0 until event.pointerCount) all = all or (1 shl event.getPointerId(index))
|
||||
event.pointerSubset(all and forwardedPointers.inv())?.let { split ->
|
||||
try { super.dispatchTouchEvent(split) } finally { split.recycle() }
|
||||
}
|
||||
val routed = event.pointerSubset(all and forwardedPointers.inv())?.let { split ->
|
||||
try { route(split) } finally { split.recycle() }
|
||||
} ?: false
|
||||
event.pointerSubset(all and forwardedPointers)?.let { split ->
|
||||
try { onTouchMiss?.invoke(split) } finally { split.recycle() }
|
||||
}
|
||||
if (event.actionMasked == MotionEvent.ACTION_POINTER_UP) forwardedPointers = forwardedPointers and (1 shl event.getPointerId(event.actionIndex)).inv()
|
||||
if (event.actionMasked == MotionEvent.ACTION_UP || event.actionMasked == MotionEvent.ACTION_CANCEL) forwardedPointers = 0
|
||||
return true
|
||||
return onTouchMiss != null || routed
|
||||
}
|
||||
|
||||
private fun route(event: MotionEvent): Boolean {
|
||||
val action = event.actionMasked
|
||||
if (action == MotionEvent.ACTION_CANCEL) { cancelOwners(event); return true }
|
||||
val index = event.actionIndex
|
||||
val pointer = event.getPointerId(index)
|
||||
var taken = true
|
||||
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
val target = elementAt(event.getX(index), event.getY(index))
|
||||
taken = target != null
|
||||
when {
|
||||
target is HoldButton -> { owners[pointer] = target; target.press(pointer, true) }
|
||||
target != null && !(target is StickView && target in owners.values) -> owners[pointer] = target
|
||||
}
|
||||
}
|
||||
if (action == MotionEvent.ACTION_MOVE) for (i in 0 until event.pointerCount) slide(event.getPointerId(i), event.getX(i), event.getY(i))
|
||||
for (view in owners.values.distinct()) {
|
||||
if (view is HoldButton) continue
|
||||
var bits = 0
|
||||
for ((id, owner) in owners) if (owner === view) bits = bits or (1 shl id)
|
||||
event.pointerSubset(bits)?.let { split ->
|
||||
try { split.offsetLocation(-originX(view), -originY(view)); view.dispatchTouchEvent(split) } finally { split.recycle() }
|
||||
}
|
||||
}
|
||||
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
|
||||
(owners.remove(pointer) as? HoldButton)?.press(pointer, false, event.flags and MotionEvent.FLAG_CANCELED != 0)
|
||||
}
|
||||
return taken
|
||||
}
|
||||
|
||||
private fun slide(pointer: Int, x: Float, y: Float) {
|
||||
val owner = owners[pointer]
|
||||
if (owner != null && owner !is HoldButton) return
|
||||
val over = elementAt(x, y) as? HoldButton
|
||||
if (over === owner) return
|
||||
(owner as? HoldButton)?.press(pointer, false, cancelled = true)
|
||||
if (over == null) owners.remove(pointer) else { owners[pointer] = over; over.press(pointer, true) }
|
||||
}
|
||||
|
||||
private fun cancelOwners(event: MotionEvent) {
|
||||
if (owners.isEmpty()) return
|
||||
val views = owners.values.distinct()
|
||||
owners.clear()
|
||||
for (view in views) {
|
||||
if (view is HoldButton) { view.cancel(); continue }
|
||||
val cancel = MotionEvent.obtain(event.downTime, event.eventTime, MotionEvent.ACTION_CANCEL, 0f, 0f, 0)
|
||||
try { view.dispatchTouchEvent(cancel) } finally { cancel.recycle() }
|
||||
}
|
||||
}
|
||||
|
||||
fun updateStyle(style: InputSurfaceStyle) {
|
||||
if (surfaceStyle == style) return
|
||||
val relayout = surfaceStyle.hidden != style.hidden
|
||||
surfaceStyle = style
|
||||
if (relayout) updateCustomLayout(requestedLayout)
|
||||
customCanvas?.let { canvas -> for (i in 0 until canvas.childCount) styleElement(canvas.getChildAt(i)) }
|
||||
}
|
||||
|
||||
@@ -92,23 +145,30 @@ class InputSurfaceView(
|
||||
view.invalidate()
|
||||
}
|
||||
|
||||
fun updateCustomLayout(layout: List<InputSurfaceElement>) {
|
||||
fun updateCustomLayout(requested: List<InputSurfaceElement>) {
|
||||
requestedLayout = requested
|
||||
val layout = surfaceStyle.shown(requested)
|
||||
val sameElements = customLayout.map { it.copy(x = 0f, y = 0f, width = 1f, height = 1f) } == layout.map { it.copy(x = 0f, y = 0f, width = 1f, height = 1f) }
|
||||
customLayout = layout
|
||||
if (sameElements) customCanvas?.requestLayout() else {
|
||||
elementSources.forEach { it.close() }; elementSources.clear()
|
||||
content.removeAllViews(); renderCustom(pad)
|
||||
owners.clear(); content.removeAllViews(); renderCustom(pad)
|
||||
}
|
||||
}
|
||||
|
||||
fun releaseInputs() {
|
||||
val now = android.os.SystemClock.uptimeMillis()
|
||||
val cancel = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0f, 0f, 0)
|
||||
try { super.dispatchTouchEvent(cancel) } finally { cancel.recycle() }
|
||||
try { cancelOwners(cancel) } finally { cancel.recycle() }
|
||||
forwardedPointers = 0
|
||||
elementSources.forEach { it.release() }
|
||||
}
|
||||
|
||||
override fun onVisibilityChanged(changedView: View, visibility: Int) {
|
||||
super.onVisibilityChanged(changedView, visibility)
|
||||
if (visibility != VISIBLE) releaseInputs()
|
||||
}
|
||||
|
||||
private fun renderCustom(pad: PadBridge?) {
|
||||
val canvas = object : ViewGroup(context) {
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
@@ -129,7 +189,7 @@ class InputSurfaceView(
|
||||
}
|
||||
}
|
||||
}
|
||||
canvas.clipChildren = customLayout.none { it.kind == InputElementKind.STICK && classic(it) }
|
||||
canvas.clipChildren = customLayout.none { it.kind == InputElementKind.STICK && (classic(it) || adaptive(it)) }
|
||||
for (element in customLayout) {
|
||||
val source = pad?.let { InputSurfaceSource(it, inputRole, element).also { s -> elementSources += s } }
|
||||
canvas.addView(when (element.kind) {
|
||||
@@ -146,7 +206,7 @@ class InputSurfaceView(
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
if (pad != null && elementSources.isEmpty()) {
|
||||
content.removeAllViews()
|
||||
owners.clear(); content.removeAllViews()
|
||||
renderCustom(pad)
|
||||
}
|
||||
}
|
||||
@@ -157,19 +217,52 @@ class InputSurfaceView(
|
||||
super.onDetachedFromWindow()
|
||||
}
|
||||
|
||||
fun takesTouchAt(x: Float, y: Float): Boolean = controlUnder(this, x, y)
|
||||
fun takesTouchAt(x: Float, y: Float): Boolean = elementAt(x, y) != null
|
||||
|
||||
private fun controlUnder(view: View, x: Float, y: Float): Boolean {
|
||||
if (view.visibility != VISIBLE || x < 0f || y < 0f || x >= view.width || y >= view.height) return false
|
||||
if (view.isClickable || view is HorizontalScrollView || view is Surface || view is DirectionPad ||
|
||||
view is androidx.compose.ui.platform.ComposeView) return true
|
||||
val group = view as? ViewGroup ?: return false
|
||||
return (group.childCount - 1 downTo 0).any { i ->
|
||||
val child = group.getChildAt(i)
|
||||
controlUnder(child, x + group.scrollX - child.x, y + group.scrollY - child.y)
|
||||
}
|
||||
private fun elementAt(x: Float, y: Float): View? {
|
||||
val canvas = customCanvas ?: return null
|
||||
if (visibility != VISIBLE || x < 0f || y < 0f || x >= width || y >= height) return null
|
||||
val views = (canvas.childCount - 1 downTo 0).map(canvas::getChildAt).filter { it.visibility == VISIBLE }
|
||||
views.firstOrNull { !(it is StickView && it.adaptive) && hits(it, x, y, 0f) }?.let { return it }
|
||||
views.filter { it is HoldButton && hits(it, x, y, slack(it)) }.minByOrNull { distance(it, x, y) }?.let { return it }
|
||||
if (views.any { it is HoldButton && hits(it, x, y, slack(it) + ADAPTIVE_CLEARANCE_PX) }) return null
|
||||
return views.filter { it is StickView && it.adaptive && it !in owners.values && (hits(it, x, y, 0f) || it.captures(x - originX(it), y - originY(it))) }
|
||||
.minByOrNull { distance(it, x, y) }
|
||||
}
|
||||
|
||||
private fun hits(view: View, x: Float, y: Float, slack: Float): Boolean {
|
||||
val left = originX(view)
|
||||
val top = originY(view)
|
||||
if ((view as? HoldButton)?.round == true && slack > 0f) {
|
||||
val reach = min(view.width, view.height) / 2f + slack
|
||||
return hypot(x - left - view.width / 2f, y - top - view.height / 2f) <= reach
|
||||
}
|
||||
return x >= left - slack && x < left + view.width + slack && y >= top - slack && y < top + view.height + slack
|
||||
}
|
||||
|
||||
private fun slack(view: View) = if ((view as? HoldButton)?.gamepad == true) min(view.width, view.height) / 2f * HIT_SLACK else 0f
|
||||
|
||||
private fun distance(view: View, x: Float, y: Float): Float {
|
||||
val cx = originX(view) + ((view as? StickView)?.centreX() ?: (view.width / 2f))
|
||||
return hypot(x - cx, y - originY(view) - view.height / 2f)
|
||||
}
|
||||
|
||||
private fun originX(view: View): Float {
|
||||
var x = 0f
|
||||
var at: View = view
|
||||
while (at !== this) { x += at.left - ((at.parent as? View)?.scrollX ?: 0); at = at.parent as? View ?: break }
|
||||
return x
|
||||
}
|
||||
|
||||
private fun originY(view: View): Float {
|
||||
var y = 0f
|
||||
var at: View = view
|
||||
while (at !== this) { y += at.top - ((at.parent as? View)?.scrollY ?: 0); at = at.parent as? View ?: break }
|
||||
return y
|
||||
}
|
||||
|
||||
private fun feedback(view: View, type: Int) { if (haptics) view.performHapticFeedback(type) }
|
||||
|
||||
private abstract class Surface(context: Context) : View(context) {
|
||||
var tint: Int? = null
|
||||
protected val density = resources.displayMetrics.density
|
||||
@@ -231,11 +324,13 @@ class InputSurfaceView(
|
||||
protected fun textColor(lit: Boolean) = if (lit) Color.WHITE else tint?.let { light(it, 210, 0.75f) } ?: TEXT
|
||||
}
|
||||
|
||||
private class HoldButton(context: Context, private val element: InputSurfaceElement, private val source: InputSurfaceSource?) : Surface(context) {
|
||||
private inner class HoldButton(context: Context, private val element: InputSurfaceElement, private val source: InputSurfaceSource?) : Surface(context) {
|
||||
private var down = false
|
||||
private val pointers = HashSet<Int>()
|
||||
val round get() = element.buttonShape == InputButtonShape.CIRCLE
|
||||
val gamepad get() = round || element.buttonShape == InputButtonShape.PILL
|
||||
private val symbol = InputButtonIcons.drawable(context, element.icon)
|
||||
private val bitmap = element.image.takeIf { it.matches(Regex("[A-Za-z0-9_.-]{1,128}")) && it != "." && it != ".." }?.let { name ->
|
||||
val file = File(File(context.filesDir, "screenkeys"), name)
|
||||
private val bitmap = InputButtonImages.file(context, element.image)?.let { file ->
|
||||
val size = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
BitmapFactory.decodeFile(file.path, size)
|
||||
val options = BitmapFactory.Options().apply {
|
||||
@@ -282,23 +377,20 @@ class InputSurfaceView(
|
||||
canvas.drawText(element.name, cx, height / 2f + labelPaint.textSize * .35f, labelPaint)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> set(true)
|
||||
MotionEvent.ACTION_UP -> set(false)
|
||||
MotionEvent.ACTION_CANCEL -> { set(false); source?.release() }
|
||||
}
|
||||
return true
|
||||
fun press(pointer: Int, pressed: Boolean, cancelled: Boolean = false) {
|
||||
if (pressed) pointers.add(pointer) else pointers.remove(pointer)
|
||||
set(pointers.isNotEmpty(), cancelled)
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() { set(false); source?.release(); super.onDetachedFromWindow() }
|
||||
fun cancel() { pointers.clear(); set(false, cancelled = true); source?.release() }
|
||||
|
||||
private fun set(pressed: Boolean) {
|
||||
override fun onDetachedFromWindow() { cancel(); super.onDetachedFromWindow() }
|
||||
|
||||
private fun set(pressed: Boolean, cancelled: Boolean = false) {
|
||||
if (down == pressed) return
|
||||
down = pressed
|
||||
if (pressed) performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
source?.update(if (pressed) 1f else 0f)
|
||||
if (pressed) feedback(this, HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
if (!pressed && cancelled) source?.cancel() else source?.update(if (pressed) 1f else 0f)
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
@@ -314,7 +406,7 @@ class InputSurfaceView(
|
||||
}
|
||||
override fun onButton(button: Int, pressed: Boolean, x: Float, y: Float) { source?.gestureButton(button, pressed) }
|
||||
override fun onWheel(steps: Int) { source?.gestureWheel(steps) }
|
||||
override fun onLongPress() { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) }
|
||||
override fun onLongPress() { feedback(this@TrackpadView, HapticFeedbackConstants.LONG_PRESS) }
|
||||
}).apply { bounds = RectF(-1e9f, -1e9f, 1e9f, 1e9f) }
|
||||
|
||||
private var touching = false
|
||||
@@ -396,7 +488,7 @@ class InputSurfaceView(
|
||||
private fun click(down: Boolean) {
|
||||
if (clicked == down) return
|
||||
clicked = down
|
||||
if (down) performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
if (down) feedback(this, HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
source?.click(down)
|
||||
invalidate()
|
||||
}
|
||||
@@ -418,9 +510,18 @@ class InputSurfaceView(
|
||||
private val ring = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE }
|
||||
private val knob = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
|
||||
private fun reach() = min(width, height) * 0.30f
|
||||
val adaptive get() = adaptive(element)
|
||||
|
||||
private fun centreX() = when {
|
||||
fun reach() = min(width, height) * if (classic(element)) CLASSIC_REACH else PANEL_REACH
|
||||
|
||||
fun captures(x: Float, y: Float): Boolean {
|
||||
val cx = centreX()
|
||||
val dx = if (element.control == InputControl.LS) maxOf(0f, x - cx) else x - cx
|
||||
val limit = reach() * ADAPTIVE_REACH
|
||||
return dx * dx + (y - height / 2f) * (y - height / 2f) <= limit * limit
|
||||
}
|
||||
|
||||
fun centreX() = when {
|
||||
!classic(element) || width <= height -> width / 2f
|
||||
element.control == InputControl.LS -> width - height / 2f
|
||||
else -> height / 2f
|
||||
@@ -465,7 +566,7 @@ class InputSurfaceView(
|
||||
originX = if (floating) event.x else centreX()
|
||||
originY = if (floating) event.y else height / 2f
|
||||
touching = true
|
||||
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
feedback(this, HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
if (lastUp != 0L && event.eventTime - lastUp < CLICK_MS) setClick(true)
|
||||
follow(event.x, event.y, r, force = true)
|
||||
}
|
||||
@@ -501,7 +602,7 @@ class InputSurfaceView(
|
||||
private fun setClick(down: Boolean) {
|
||||
if (clicking == down) return
|
||||
clicking = down
|
||||
if (down) performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
if (down) feedback(this, HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
source?.click(down)
|
||||
}
|
||||
|
||||
@@ -556,7 +657,7 @@ class InputSurfaceView(
|
||||
|
||||
private fun set(bits: Int) {
|
||||
if (bits == held) return
|
||||
if (bits and held.inv() != 0) performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
if (bits and held.inv() != 0) feedback(this, HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
held = bits
|
||||
source?.update((if (bits and 2 != 0) 1f else 0f) - (if (bits and 8 != 0) 1f else 0f),
|
||||
(if (bits and 4 != 0) 1f else 0f) - (if (bits and 1 != 0) 1f else 0f))
|
||||
@@ -573,6 +674,11 @@ class InputSurfaceView(
|
||||
companion object {
|
||||
private const val CLICK_MS = 300L
|
||||
private const val STICK_TAP_MS = 200L
|
||||
private const val CLASSIC_REACH = 0.5f
|
||||
private const val PANEL_REACH = 0.30f
|
||||
private const val HIT_SLACK = 0.25f
|
||||
private const val ADAPTIVE_CLEARANCE_PX = 5f
|
||||
private val ADAPTIVE_REACH = 1.4f * kotlin.math.sqrt(1.5f)
|
||||
|
||||
|
||||
private const val CORNER = 20f
|
||||
@@ -588,6 +694,8 @@ class InputSurfaceView(
|
||||
private val TEXT_DIM = Color.rgb(0x7A, 0x80, 0x8A)
|
||||
private val KNOB = Color.rgb(0x2A, 0x2D, 0x33)
|
||||
|
||||
private fun adaptive(element: InputSurfaceElement) = element.kind == InputElementKind.STICK && element.floating && element.hideWhenIdle
|
||||
|
||||
private fun classic(element: InputSurfaceElement) = (element.id == "legacy:${element.control.id}" || element.id == "builtin:keyboard") &&
|
||||
(element.buttonShape == InputButtonShape.CIRCLE || element.buttonShape == InputButtonShape.PILL)
|
||||
|
||||
|
||||
@@ -18,11 +18,13 @@ import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
|
||||
import androidx.lifecycle.setViewTreeLifecycleOwner
|
||||
import androidx.lifecycle.setViewTreeViewModelStoreOwner
|
||||
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
||||
import com.droiddeck.launcher.input.DeckPanel
|
||||
import com.droiddeck.launcher.input.KeyboardHost
|
||||
import com.droiddeck.launcher.input.PadBridge
|
||||
import com.droiddeck.launcher.input.SecondScreenMode
|
||||
import com.droiddeck.launcher.SessionActivity
|
||||
import com.droiddeck.launcher.session.BottomDesktop
|
||||
import com.droiddeck.launcher.session.SessionPrefs
|
||||
import com.droiddeck.launcher.session.SessionService
|
||||
import com.droiddeck.launcher.session.SessionState
|
||||
|
||||
@@ -39,6 +41,7 @@ class SecondScreenPresentation(
|
||||
private val dashboard: (@androidx.compose.runtime.Composable () -> Unit)? = null,
|
||||
private val onSwap: (() -> Unit)? = null,
|
||||
private val onMenuTouched: () -> Unit = {},
|
||||
private val onDeckPanel: (DeckPanel) -> Unit = { SessionPrefs.setDeckPanel(sessionActivity, it) },
|
||||
) : Presentation(sessionActivity, display) {
|
||||
private val frame = FrameLayout(context)
|
||||
private var menuView: androidx.compose.ui.platform.ComposeView? = null
|
||||
@@ -55,6 +58,7 @@ class SecondScreenPresentation(
|
||||
private var currentMode = SecondScreenMode.NONE
|
||||
private var keyboardHost: KeyboardHost? = null
|
||||
private val keyboardShown = androidx.compose.runtime.mutableStateOf(false)
|
||||
private val deckPanel = androidx.compose.runtime.mutableStateOf(DeckPanel.BOTH)
|
||||
private var keyboardPending = false
|
||||
private var imeSeen = false
|
||||
private var fieldKeyboard = false
|
||||
@@ -284,6 +288,8 @@ class SecondScreenPresentation(
|
||||
when (mode) {
|
||||
SecondScreenMode.TERMINAL -> renderTerminal()
|
||||
SecondScreenMode.CUSTOM_CONTROLS, SecondScreenMode.KEYBOARD_TRACKPAD, SecondScreenMode.DECK_CONTROLS -> {
|
||||
if (mode == SecondScreenMode.DECK_CONTROLS) deckPanel.value = SessionPrefs.deckPanel(context)
|
||||
bar(mode)
|
||||
val layout = panelLayout(mode)
|
||||
val controls = InputSurfaceView(context, pad, layout?.elements.orEmpty(),
|
||||
surfaceStyle = layout?.style ?: com.droiddeck.launcher.input.InputSurfaceStyle())
|
||||
@@ -301,19 +307,39 @@ class SecondScreenPresentation(
|
||||
}
|
||||
|
||||
private fun panelLayout(mode: SecondScreenMode) = com.droiddeck.launcher.input.InputLibraries.read(context)
|
||||
.panelLayout(SessionState.mode == SessionService.MODE_DESKTOP, mode.bindings)
|
||||
.panelLayout(SessionState.mode == SessionService.MODE_DESKTOP, mode.panel(context))
|
||||
|
||||
private fun bar(mode: SecondScreenMode, extras: () -> List<BarExtra> = { emptyList() }) {
|
||||
root.addView(bottomScreenBarView(context) {
|
||||
sessionBarModel(context.getString(mode.label), onClose, onMenu, onSteamMenu, onQam, extras())
|
||||
}, LinearLayout.LayoutParams(-1, -2))
|
||||
private fun bar(mode: SecondScreenMode) {
|
||||
val first = barModel(mode) ?: return
|
||||
root.addView(bottomScreenBarView(context) { barModel(mode) ?: first }, LinearLayout.LayoutParams(-1, -2))
|
||||
}
|
||||
|
||||
internal fun barModel(mode: SecondScreenMode): BottomBarModel? {
|
||||
val swap = listOfNotNull(onSwap?.let { BarExtra(context.getString(R.string.swap_screens), icon = R.drawable.ic_bottom_swap, tag = "bottom-swap", onClick = it) })
|
||||
fun model(extras: List<BarExtra>, tabs: BarTabs? = null) =
|
||||
sessionBarModel(context.getString(mode.label), onClose, onMenu, onSteamMenu, onQam, extras, tabs)
|
||||
return when (mode) {
|
||||
SecondScreenMode.KEYBOARD_TRACKPAD -> model(listOf(BarExtra(
|
||||
context.getString(if (keyboardShown.value) R.string.second_hide_keyboard else R.string.second_show_keyboard),
|
||||
icon = R.drawable.ic_bottom_keyboard, active = keyboardShown.value, tag = "bottom-keyboard") { showKeyboard() }))
|
||||
SecondScreenMode.DECK_CONTROLS -> model(swap, deckPanelTabs(context, deckPanel.value, ::selectDeckPanel))
|
||||
SecondScreenMode.DASHBOARD -> model(swap)
|
||||
SecondScreenMode.TERMINAL -> model(listOf(BarExtra(context.getString(R.string.drawer_keyboard), icon = R.drawable.ic_bottom_keyboard,
|
||||
tag = "bottom-keyboard") { terminalPanel?.showKeyboard() }))
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectDeckPanel(panel: DeckPanel) {
|
||||
if (deckPanel.value == panel) return
|
||||
deckPanel.value = panel
|
||||
onDeckPanel(panel)
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
private fun renderDashboard() {
|
||||
val content = dashboard ?: return
|
||||
bar(SecondScreenMode.DASHBOARD) {
|
||||
listOfNotNull(onSwap?.let { BarExtra(context.getString(R.string.swap_screens), icon = R.drawable.ic_bottom_swap, tag = "bottom-swap", onClick = it) })
|
||||
}
|
||||
bar(SecondScreenMode.DASHBOARD)
|
||||
val view = androidx.compose.ui.platform.ComposeView(context).apply { setContent { content() } }
|
||||
dashboardView = view
|
||||
root.addView(view, weightParams())
|
||||
@@ -337,11 +363,7 @@ class SecondScreenPresentation(
|
||||
}
|
||||
|
||||
private fun renderTerminal() {
|
||||
bar(SecondScreenMode.TERMINAL) {
|
||||
listOf(BarExtra(context.getString(R.string.drawer_keyboard), icon = R.drawable.ic_bottom_keyboard, tag = "bottom-keyboard") {
|
||||
terminalPanel?.showKeyboard()
|
||||
})
|
||||
}
|
||||
bar(SecondScreenMode.TERMINAL)
|
||||
val panel = SessionTerminalPanel(context)
|
||||
terminalPanel = panel
|
||||
root.addView(panel, weightParams())
|
||||
|
||||
@@ -316,6 +316,8 @@ class DrawerActions(
|
||||
val unfoldedControls: Boolean? = null,
|
||||
val adaptiveSticks: Boolean? = null,
|
||||
val onAdaptiveSticks: (Boolean) -> Unit = {},
|
||||
val quickButtons: Map<com.droiddeck.launcher.input.InputCommand, Boolean> = emptyMap(),
|
||||
val onQuickButton: (com.droiddeck.launcher.input.InputCommand, Boolean) -> Unit = { _, _ -> },
|
||||
val onUnfoldedControls: (Boolean) -> Unit = {},
|
||||
val unfoldedControlsWithController: Boolean = false,
|
||||
val onUnfoldedControlsWithController: (Boolean) -> Unit = {},
|
||||
@@ -642,6 +644,11 @@ internal fun SessionDrawer(open: Boolean, requestedPage: SessionDrawerPage, cont
|
||||
ToggleRow(host, "adaptive-sticks", stringResource(R.string.ctrl_adaptive), null, on,
|
||||
chipModifier = focus.track(page, "adaptive-sticks"), onChange = a.onAdaptiveSticks)
|
||||
}
|
||||
for ((button, shown) in a.quickButtons) {
|
||||
val key = "quick-${button.name.lowercase()}"
|
||||
ToggleRow(host, key, stringResource(quickButtonLabel(button)), null, shown,
|
||||
chipModifier = focus.track(page, key)) { a.onQuickButton(button, it) }
|
||||
}
|
||||
a.onEditSteamTouch?.let { edit ->
|
||||
ActionRow(stringResource(R.string.osc_steam_layout), stringResource(R.string.osc_steam_layout_hint), stringResource(R.string.ctrl_edit), edit)
|
||||
}
|
||||
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">لمس Steam (تجريبي)</string>
|
||||
<string name="osc_style_next_session">تبدأ عناصر التحكم باللمس من Steam مع جلسة Steam التالية</string>
|
||||
<string name="osc_steam_layout">تخطيط لمس Steam</string>
|
||||
<string name="screen_keys">مفاتيح الشاشة</string>
|
||||
<string name="screen_keys_add">إضافة مفتاح</string>
|
||||
<string name="screen_key_text">نص</string>
|
||||
<string name="screen_key_size">الحجم</string>
|
||||
<string name="screen_key_opacity">العتامة</string>
|
||||
<string name="screen_key_type_button">مفتاح</string>
|
||||
<string name="screen_key_shape_trigger">زناد</string>
|
||||
<string name="screen_key_toggle">تبديل</string>
|
||||
<string name="screen_key_layout_export">تصدير</string>
|
||||
<string name="screen_key_shape_pill">كبسولة</string>
|
||||
<string name="screen_key_shape_round">مستدير</string>
|
||||
<string name="screen_key_shape_circle">دائرة</string>
|
||||
<string name="screen_key_shape_rect">مستطيل</string>
|
||||
<string name="screen_key_bind">مفتاح</string>
|
||||
<string name="screen_key_image">صورة</string>
|
||||
<string name="screen_key_image_clear">مسح</string>
|
||||
<string name="screen_key_layout">التخطيط</string>
|
||||
<string name="screen_key_layout_save">حفظ</string>
|
||||
<string name="osc_steam_layout_hint">انقل عناصر التحكم باللمس لهذه اللعبة أو غيّر حجمها أو أخفها؛ ويتم الحفظ في Steam</string>
|
||||
<string name="mode_controller">وحدة التحكم</string>
|
||||
<string name="mode_controller_hint">كيف يرى Steam وحدة التحكم لديك. يُطبَّق في الجلسة التالية.</string>
|
||||
@@ -776,7 +760,6 @@
|
||||
<string name="drawer_relative_mouse_auto">تلقائي</string>
|
||||
<string name="drawer_relative_mouse_on">تشغيل</string>
|
||||
<string name="drawer_relative_mouse_off">إيقاف</string>
|
||||
<string name="drawer_direct_cursor">المؤشر</string>
|
||||
<string name="drawer_pc_keyboard">لوحة مفاتيح الكمبيوتر</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">الشاشة الثانية</string>
|
||||
@@ -1135,43 +1118,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB من كمبيوتر (كخيار أخير)</string>
|
||||
<string name="wadb_only_if">فقط إذا كان تصحيح الأخطاء اللاسلكي غير متاح.</string>
|
||||
<string name="wadb_computer_group">3 · ADB من كمبيوتر (كخيار أخير)</string>
|
||||
<string name="ctrl_osc_hint">متى تظهر عناصر التحكم باللمس في الجلسة</string>
|
||||
<string name="ctrl_color">اللون</string>
|
||||
<string name="ctrl_color_hint">درجة لون الأزرار على الشاشة</string>
|
||||
<string name="ctrl_custom">مخصّص</string>
|
||||
<string name="ctrl_opacity">العتامة</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">حجم الأزرار</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% هو الحجم القياسي</string>
|
||||
<string name="ctrl_stick_click">ضغط العصا</string>
|
||||
<string name="ctrl_stick_click_hint">انقر مرتين مع الاستمرار على عصا للحصول على L3 أو R3</string>
|
||||
<string name="ctrl_adaptive">عصي تكيّفية</string>
|
||||
<string name="ctrl_rumble">اهتزاز اللعبة</string>
|
||||
<string name="ctrl_dead_zone">المنطقة الميتة لعصا التحكم</string>
|
||||
<string name="ctrl_steam_button">زر Steam</string>
|
||||
<string name="ctrl_qam_button">زر QAM</string>
|
||||
<string name="ctrl_keyboard_button">زر لوحة المفاتيح</string>
|
||||
<string name="ctrl_select_steam">اضغط على Select لفتح قائمة Steam</string>
|
||||
<string name="ctrl_select_steam_hint">بدلًا من View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">أجهزة Joy-Con كوحدات تحكم VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">أثناء تشغيل SteamVR، يصبح كل Joy-Con يدًا. وجّهه إلى الأمام واضغط مطولًا على Home أو Capture لإعادة توسيطه.</string>
|
||||
<string name="setup_animations">الرسوم المتحركة</string>
|
||||
<string name="ctrl_adaptive_hint">تظهر العصي حيث تلمس وتُخفى عند الرفع</string>
|
||||
<string name="ctrl_layout">التخطيط</string>
|
||||
<string name="ctrl_layout_custom">تم حفظ مواضع مخصّصة</string>
|
||||
<string name="ctrl_layout_default">مهيّأ لهذه الشاشة</string>
|
||||
<string name="ctrl_edit">تعديل</string>
|
||||
<string name="ctrl_reset">إعادة ضبط</string>
|
||||
<string name="ctrl_mapping">تعيين الأزرار</string>
|
||||
<string name="ctrl_mapping_default">يرسل كل زر إدخاله الخاص</string>
|
||||
<string name="ctrl_mapping_count">تمت إعادة تعيين %1$d من %2$d أزرار</string>
|
||||
<string name="ctrl_configure">ضبط</string>
|
||||
<string name="ctrl_reset_all">إعادة ضبط وحدة التحكم</string>
|
||||
<string name="ctrl_reset_all_hint">يستعيد كل إعدادات وحدة التحكم والتخطيط</string>
|
||||
<string name="ctrl_mapping_lede">ما يرسله كل زر على الشاشة إلى اللعبة. يؤدي إخفاؤه إلى إزالة الزر.</string>
|
||||
<string name="ctrl_onscreen_buttons">أزرار الشاشة</string>
|
||||
<string name="ctrl_defaults">الافتراضية</string>
|
||||
<string name="ctrl_reset_mapping">إعادة ضبط التعيين</string>
|
||||
<string name="content_android_apps">تطبيقات Android</string>
|
||||
<string name="content_apps_count">%1$d تطبيق</string>
|
||||
<string name="content_no_android_apps">لم يتم العثور على تطبيقات Android قابلة للتشغيل.</string>
|
||||
@@ -1295,15 +1258,8 @@
|
||||
<string name="deck_surface_stick">عصا التحكّم</string>
|
||||
<string name="deck_surface_trackpad">لوحة اللمس</string>
|
||||
<string name="deck_surface_switch">التبديل بين عصا التحكّم ولوحة اللمس</string>
|
||||
<string name="deck_more_controls">المزيد من عناصر تحكّم Deck</string>
|
||||
<string name="deck_panels">اللوحات</string>
|
||||
<string name="deck_close">إغلاق عناصر التحكّم على الشاشة الثانية</string>
|
||||
<string name="deck_open_steam_menu">فتح قائمة Steam</string>
|
||||
<string name="deck_left_upper">يسار · علوي</string>
|
||||
<string name="deck_left_lower">يسار · سفلي</string>
|
||||
<string name="deck_right_upper">يمين · علوي</string>
|
||||
<string name="deck_right_lower">يمين · سفلي</string>
|
||||
<string name="deck_click">نقر</string>
|
||||
<string name="deck_right_trackpad">لوحة اللمس اليمنى</string>
|
||||
<string name="deck_left_trackpad">لوحة اللمس اليسرى</string>
|
||||
<string name="second_trackpad">لوحة اللمس</string>
|
||||
@@ -1903,9 +1859,7 @@
|
||||
<string name="ctrl_target_left">لوحة الاتجاهات لليسار</string>
|
||||
<string name="ctrl_target_right">لوحة الاتجاهات لليمين</string>
|
||||
<string name="ctrl_target_hidden">مخفي</string>
|
||||
<string name="ctrl_editor_drag">اسحب للنقل</string>
|
||||
<string name="ctrl_editor_snap">محاذاة</string>
|
||||
<string name="ctrl_editor_save">حفظ</string>
|
||||
<string name="second_mode_none">لا شيء</string>
|
||||
<string name="second_mode_keyboard_trackpad">لوحة المفاتيح + لوحة اللمس</string>
|
||||
<string name="second_mode_terminal">الوحدة الطرفية</string>
|
||||
@@ -2765,7 +2719,6 @@
|
||||
<string name="gog_achievements_unavailable">الإنجازات غير متوفرة؛ تحقّق من سجلات الجلسة</string>
|
||||
<string name="achievement_unlocked">تم فتح الإنجاز</string>
|
||||
<string name="touch_paste">لصق</string>
|
||||
<string name="touch_dpad">لوحة الاتجاهات</string>
|
||||
<string name="touch_left_stick">العصا اليسرى</string>
|
||||
<string name="touch_right_stick">العصا اليمنى</string>
|
||||
<string name="touch_menu">القائمة</string>
|
||||
@@ -3858,4 +3811,7 @@
|
||||
<string name="addons_none_found">لم يتم العثور على إضافات</string>
|
||||
<string name="addons_unreachable">تعذّر الوصول إلى %1$s</string>
|
||||
<string name="addons_no_file">لا يوجد ملف لإصدار اللعبة هذا</string>
|
||||
<string name="input_reset_positions">إعادة تعيين المواضع</string>
|
||||
<string name="input_show_label">إظهار التسمية</string>
|
||||
<string name="input_layout_import_failed">تعذّر استيراد هذا التخطيط</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Táctil de Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Los controles táctiles de Steam se activan en la próxima sesión de Steam</string>
|
||||
<string name="osc_steam_layout">Disposición táctil de Steam</string>
|
||||
<string name="screen_keys">Teclas en pantalla</string>
|
||||
<string name="screen_keys_add">Agregar tecla</string>
|
||||
<string name="screen_key_text">Texto</string>
|
||||
<string name="screen_key_size">Tamaño</string>
|
||||
<string name="screen_key_opacity">Opacidad</string>
|
||||
<string name="screen_key_type_button">Tecla</string>
|
||||
<string name="screen_key_shape_trigger">Gatillo</string>
|
||||
<string name="screen_key_toggle">Alternar</string>
|
||||
<string name="screen_key_layout_export">Exportar</string>
|
||||
<string name="screen_key_shape_pill">Píldora</string>
|
||||
<string name="screen_key_shape_round">Redondeado</string>
|
||||
<string name="screen_key_shape_circle">Círculo</string>
|
||||
<string name="screen_key_shape_rect">Rectángulo</string>
|
||||
<string name="screen_key_bind">Tecla</string>
|
||||
<string name="screen_key_image">Imagen</string>
|
||||
<string name="screen_key_image_clear">Borrar</string>
|
||||
<string name="screen_key_layout">Disposición</string>
|
||||
<string name="screen_key_layout_save">Guardar</string>
|
||||
<string name="osc_steam_layout_hint">Mueve, cambia de tamaño u oculta los controles táctiles de este juego; se guarda en Steam</string>
|
||||
<string name="mode_controller">Control</string>
|
||||
<string name="mode_controller_hint">Cómo ve Steam tu control. Se aplica en la próxima sesión.</string>
|
||||
@@ -794,7 +778,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automático</string>
|
||||
<string name="drawer_relative_mouse_on">Activado</string>
|
||||
<string name="drawer_relative_mouse_off">Desactivado</string>
|
||||
<string name="drawer_direct_cursor">Cursor</string>
|
||||
<string name="drawer_pc_keyboard">Teclado de PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Segunda pantalla</string>
|
||||
@@ -1144,23 +1127,17 @@
|
||||
<string name="wadb_computer_last">3 · ADB desde una computadora (último recurso)</string>
|
||||
<string name="wadb_only_if">Solo si la Depuración inalámbrica no está disponible.</string>
|
||||
<string name="wadb_computer_group">3 · ADB desde una computadora (último recurso)</string>
|
||||
<string name="ctrl_osc_hint">Cuándo aparecen los controles táctiles en una sesión</string>
|
||||
<string name="ctrl_color">Color</string>
|
||||
<string name="ctrl_color_hint">Tinte de los botones en pantalla</string>
|
||||
<string name="ctrl_custom">Personalizado</string>
|
||||
<string name="ctrl_opacity">Opacidad</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Tamaño de botones</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% es el tamaño estándar</string>
|
||||
<string name="ctrl_stick_click">Clic del stick</string>
|
||||
<string name="ctrl_stick_click_hint">Toca dos veces y mantén un stick para L3 o R3</string>
|
||||
<string name="ctrl_adaptive">Sticks adaptables</string>
|
||||
<string name="ctrl_rumble">Vibración en juegos</string>
|
||||
<string name="ctrl_dead_zone">Zona muerta de la palanca</string>
|
||||
<string name="ctrl_steam_button">Botón Steam</string>
|
||||
<string name="ctrl_qam_button">Botón QAM</string>
|
||||
<string name="ctrl_keyboard_button">Botón de teclado</string>
|
||||
<string name="ctrl_select_steam">Presiona Select para abrir el menú de Steam</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con como controles de RV</string>
|
||||
<string name="ctrl_joycon_vr_hint">Mientras SteamVR está activo, cada Joy-Con es una mano. Apúntalo al frente y mantén Home o Captura para recentrarlo.</string>
|
||||
<string name="hand_camera_prompt_body">Sin ningún mando conectado, la cámara del teléfono rastrea tus manos en realidad virtual: pellizca con el pulgar y el índice para hacer clic, cierra la mano para agarrar y gira la palma hacia ti y pellizca para abrir el menú. Con los mandos Joy-Con emparejados, la cámara rastrea su posición mientras los mandos Joy-Con proporcionan la rotación y las entradas de los botones. Las imágenes se procesan en este dispositivo y nunca se guardan ni se envían.</string>
|
||||
@@ -1206,24 +1183,10 @@
|
||||
<string name="glasses_xreal_connection_failed">La conexión con las XREAL se interrumpió o devolvió una respuesta no compatible. Reintentando…</string>
|
||||
<string name="glasses_xreal_experimental">Compatibilidad experimental con las 1S. Usa el modo Follow y desactiva la estabilización en el menú de las gafas. Aún falta probar en el dispositivo las direcciones del seguimiento y los modos de pantalla.</string>
|
||||
<string name="glasses_pro2_experimental">Seguimiento de cabeza experimental para Pro 2. Los ajustes de brillo y volumen y el cambio de modo de pantalla aún no son compatibles.</string>
|
||||
<string name="ctrl_select_steam_hint">En lugar de View/Select.</string>
|
||||
<string name="setup_animations">Animaciones</string>
|
||||
<string name="ctrl_adaptive_hint">Los sticks aparecen donde tocas y se ocultan al soltar</string>
|
||||
<string name="ctrl_layout">Disposición</string>
|
||||
<string name="ctrl_layout_custom">Posiciones personalizadas guardadas</string>
|
||||
<string name="ctrl_layout_default">Ajustada a esta pantalla</string>
|
||||
<string name="ctrl_edit">Editar</string>
|
||||
<string name="ctrl_reset">Restablecer</string>
|
||||
<string name="ctrl_mapping">Asignación de botones</string>
|
||||
<string name="ctrl_mapping_default">Cada botón envía su propia entrada</string>
|
||||
<string name="ctrl_mapping_count">%1$d de %2$d botones reasignados</string>
|
||||
<string name="ctrl_configure">Configurar</string>
|
||||
<string name="ctrl_reset_all">Restablecer control</string>
|
||||
<string name="ctrl_reset_all_hint">Restaura todos los ajustes del control y la disposición</string>
|
||||
<string name="ctrl_mapping_lede">Lo que cada botón en pantalla envía al juego. Oculto quita el botón.</string>
|
||||
<string name="ctrl_onscreen_buttons">Botones en pantalla</string>
|
||||
<string name="ctrl_defaults">Predeterminados</string>
|
||||
<string name="ctrl_reset_mapping">Restablecer asignación</string>
|
||||
<string name="content_android_apps">Apps de Android</string>
|
||||
<string name="content_apps_count">%1$d apps</string>
|
||||
<string name="content_no_android_apps">No se encontraron apps de Android que se puedan abrir.</string>
|
||||
@@ -1344,15 +1307,8 @@
|
||||
<string name="deck_surface_stick">Stick</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Cambiar entre stick y trackpad</string>
|
||||
<string name="deck_more_controls">Más controles de Deck</string>
|
||||
<string name="deck_panels">PANELES</string>
|
||||
<string name="deck_close">Cerrar controles de la segunda pantalla</string>
|
||||
<string name="deck_open_steam_menu">Abrir menú de Steam</string>
|
||||
<string name="deck_left_upper">Izquierdo · superior</string>
|
||||
<string name="deck_left_lower">Izquierdo · inferior</string>
|
||||
<string name="deck_right_upper">Derecho · superior</string>
|
||||
<string name="deck_right_lower">Derecho · inferior</string>
|
||||
<string name="deck_click">Clic</string>
|
||||
<string name="deck_right_trackpad">Trackpad derecho</string>
|
||||
<string name="deck_left_trackpad">Trackpad izquierdo</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1895,9 +1851,7 @@
|
||||
<string name="ctrl_target_left">Cruceta izquierda</string>
|
||||
<string name="ctrl_target_right">Cruceta derecha</string>
|
||||
<string name="ctrl_target_hidden">Oculto</string>
|
||||
<string name="ctrl_editor_drag">Arrastra para mover</string>
|
||||
<string name="ctrl_editor_snap">Ajustar</string>
|
||||
<string name="ctrl_editor_save">Guardar</string>
|
||||
<string name="second_mode_none">Nada</string>
|
||||
<string name="second_mode_keyboard_trackpad">Teclado + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2702,7 +2656,6 @@
|
||||
<string name="gog_achievements_unavailable">Logros no disponibles; revisa los registros de la sesión</string>
|
||||
<string name="achievement_unlocked">Logro desbloqueado</string>
|
||||
<string name="touch_paste">Pegar</string>
|
||||
<string name="touch_dpad">Pad direccional</string>
|
||||
<string name="touch_left_stick">Stick izquierdo</string>
|
||||
<string name="touch_right_stick">Stick derecho</string>
|
||||
<string name="touch_menu">Menú</string>
|
||||
@@ -3714,4 +3667,7 @@
|
||||
<string name="addons_none_found">No se encontraron complementos</string>
|
||||
<string name="addons_unreachable">No se pudo conectar con %1$s</string>
|
||||
<string name="addons_no_file">No hay archivo para esta versión del juego</string>
|
||||
<string name="input_reset_positions">Restablecer posiciones</string>
|
||||
<string name="input_show_label">Mostrar etiqueta</string>
|
||||
<string name="input_layout_import_failed">No se pudo importar esta disposición</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Докосване в Steam (бета)</string>
|
||||
<string name="osc_style_next_session">Сензорните контроли на Steam ще стартират от следващата сесия на Steam</string>
|
||||
<string name="osc_steam_layout">Разположение на докосването в Steam</string>
|
||||
<string name="screen_keys">Клавиши на екрана</string>
|
||||
<string name="screen_keys_add">Добавяне на клавиш</string>
|
||||
<string name="screen_key_text">Текст</string>
|
||||
<string name="screen_key_size">Размер</string>
|
||||
<string name="screen_key_opacity">Прозрачност</string>
|
||||
<string name="screen_key_type_button">Клавиш</string>
|
||||
<string name="screen_key_shape_trigger">Спускът</string>
|
||||
<string name="screen_key_toggle">Превключване</string>
|
||||
<string name="screen_key_layout_export">Експорт</string>
|
||||
<string name="screen_key_shape_pill">Капсула</string>
|
||||
<string name="screen_key_shape_round">Заоблено</string>
|
||||
<string name="screen_key_shape_circle">Кръг</string>
|
||||
<string name="screen_key_shape_rect">Правоъгълник</string>
|
||||
<string name="screen_key_bind">Клавиш</string>
|
||||
<string name="screen_key_image">Изображение</string>
|
||||
<string name="screen_key_image_clear">Изчистване</string>
|
||||
<string name="screen_key_layout">Разположение</string>
|
||||
<string name="screen_key_layout_save">Запиши</string>
|
||||
<string name="osc_steam_layout_hint">Премествайте, преоразмерявайте или скривайте сензорните контроли на тази игра; записва се в Steam</string>
|
||||
<string name="mode_controller">Контролер</string>
|
||||
<string name="mode_controller_hint">Как Steam разпознава контролера ви. Прилага се от следващата сесия.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Автоматично</string>
|
||||
<string name="drawer_relative_mouse_on">Включено</string>
|
||||
<string name="drawer_relative_mouse_off">Изключено</string>
|
||||
<string name="drawer_direct_cursor">Курсор</string>
|
||||
<string name="drawer_pc_keyboard">Клавиатура за компютър</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Втори екран</string>
|
||||
@@ -1111,43 +1094,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB от компютър (последна възможност)</string>
|
||||
<string name="wadb_only_if">Само ако безжичното отстраняване на грешки не е достъпно.</string>
|
||||
<string name="wadb_computer_group">3 · ADB от компютър (последна възможност)</string>
|
||||
<string name="ctrl_osc_hint">Кога се появяват екранните контроли в сесия</string>
|
||||
<string name="ctrl_color">Цвят</string>
|
||||
<string name="ctrl_color_hint">Оттенък на екранните бутони</string>
|
||||
<string name="ctrl_custom">Персонализиран</string>
|
||||
<string name="ctrl_opacity">Прозрачност</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Размер на бутоните</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% е стандартният размер</string>
|
||||
<string name="ctrl_stick_click">Натискане на стика</string>
|
||||
<string name="ctrl_stick_click_hint">Докоснете двукратно и задръжте стик за L3 или R3</string>
|
||||
<string name="ctrl_adaptive">Адаптивни стикове</string>
|
||||
<string name="ctrl_rumble">Вибрация от играта</string>
|
||||
<string name="ctrl_dead_zone">Мъртва зона на стика</string>
|
||||
<string name="ctrl_steam_button">Бутон Steam</string>
|
||||
<string name="ctrl_qam_button">Бутон QAM</string>
|
||||
<string name="ctrl_keyboard_button">Бутон за клавиатура</string>
|
||||
<string name="ctrl_select_steam">Натиснете Select, за да отворите менюто на Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Вместо View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con като VR контролери</string>
|
||||
<string name="ctrl_joycon_vr_hint">Докато SteamVR работи, всеки Joy-Con става ръка. Насочете го напред и задръжте Home или Capture, за да го центрирате отново.</string>
|
||||
<string name="setup_animations">Анимации</string>
|
||||
<string name="ctrl_adaptive_hint">Стиковете се появяват там, където докоснете, и се скриват при отпускане</string>
|
||||
<string name="ctrl_layout">Разположение</string>
|
||||
<string name="ctrl_layout_custom">Запазени персонализирани позиции</string>
|
||||
<string name="ctrl_layout_default">Нагласено за този екран</string>
|
||||
<string name="ctrl_edit">Редактиране</string>
|
||||
<string name="ctrl_reset">Нулиране</string>
|
||||
<string name="ctrl_mapping">Разпределение на бутоните</string>
|
||||
<string name="ctrl_mapping_default">Всеки бутон изпраща собствения си сигнал</string>
|
||||
<string name="ctrl_mapping_count">%1$d от %2$d бутона преназначени</string>
|
||||
<string name="ctrl_configure">Конфигуриране</string>
|
||||
<string name="ctrl_reset_all">Нулиране на контролера</string>
|
||||
<string name="ctrl_reset_all_hint">Възстановява всички настройки на контролера и разположението</string>
|
||||
<string name="ctrl_mapping_lede">Какво изпраща всеки екранен бутон към играта. „Скрит“ премахва бутона.</string>
|
||||
<string name="ctrl_onscreen_buttons">Екранни бутони</string>
|
||||
<string name="ctrl_defaults">Стандартни настройки</string>
|
||||
<string name="ctrl_reset_mapping">Нулиране на разпределението</string>
|
||||
<string name="content_android_apps">Приложения за Android</string>
|
||||
<string name="content_apps_count">%1$d приложения</string>
|
||||
<string name="content_no_android_apps">Не са намерени приложения за Android за стартиране.</string>
|
||||
@@ -1267,15 +1230,8 @@
|
||||
<string name="deck_surface_stick">Стик</string>
|
||||
<string name="deck_surface_trackpad">Тракпад</string>
|
||||
<string name="deck_surface_switch">Превключване между стик и тракпад</string>
|
||||
<string name="deck_more_controls">Още контроли на Deck</string>
|
||||
<string name="deck_panels">ПАНЕЛИ</string>
|
||||
<string name="deck_close">Затваряне на контролите за втория екран</string>
|
||||
<string name="deck_open_steam_menu">Отваряне на менюто на Steam</string>
|
||||
<string name="deck_left_upper">Ляво · горе</string>
|
||||
<string name="deck_left_lower">Ляво · долу</string>
|
||||
<string name="deck_right_upper">Дясно · горе</string>
|
||||
<string name="deck_right_lower">Дясно · долу</string>
|
||||
<string name="deck_click">Клик</string>
|
||||
<string name="deck_right_trackpad">Десен тракпад</string>
|
||||
<string name="deck_left_trackpad">Ляв тракпад</string>
|
||||
<string name="second_trackpad">Тракпад</string>
|
||||
@@ -1807,9 +1763,7 @@
|
||||
<string name="ctrl_target_left">D-pad наляво</string>
|
||||
<string name="ctrl_target_right">D-pad надясно</string>
|
||||
<string name="ctrl_target_hidden">Скрит</string>
|
||||
<string name="ctrl_editor_drag">Плъзни, за да преместиш</string>
|
||||
<string name="ctrl_editor_snap">Прилепване</string>
|
||||
<string name="ctrl_editor_save">Запазване</string>
|
||||
<string name="second_mode_none">Нищо</string>
|
||||
<string name="second_mode_keyboard_trackpad">Клавиатура + тракпад</string>
|
||||
<string name="second_mode_terminal">Терминал</string>
|
||||
@@ -2657,7 +2611,6 @@
|
||||
<string name="gog_achievements_unavailable">Постиженията не са достъпни; проверете логовете на сесията</string>
|
||||
<string name="achievement_unlocked">Постижение отключено</string>
|
||||
<string name="touch_paste">Поставяне</string>
|
||||
<string name="touch_dpad">Кръстат бутон</string>
|
||||
<string name="touch_left_stick">Ляв стик</string>
|
||||
<string name="touch_right_stick">Десен стик</string>
|
||||
<string name="touch_menu">Меню</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Няма намерени добавки</string>
|
||||
<string name="addons_unreachable">Няма връзка с %1$s</string>
|
||||
<string name="addons_no_file">Няма файл за тази версия на играта</string>
|
||||
<string name="input_reset_positions">Нулиране на позициите</string>
|
||||
<string name="input_show_label">Показване на етикета</string>
|
||||
<string name="input_layout_import_failed">Това разположение не можа да бъде импортирано</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Dotykové ovládání Steamu (beta)</string>
|
||||
<string name="osc_style_next_session">Dotykové ovládání Steamu se spustí od příští relace Steamu</string>
|
||||
<string name="osc_steam_layout">Rozvržení dotykového ovládání Steamu</string>
|
||||
<string name="screen_keys">Klávesy na obrazovce</string>
|
||||
<string name="screen_keys_add">Přidat klávesu</string>
|
||||
<string name="screen_key_text">Text</string>
|
||||
<string name="screen_key_size">Velikost</string>
|
||||
<string name="screen_key_opacity">Průhlednost</string>
|
||||
<string name="screen_key_type_button">Klávesa</string>
|
||||
<string name="screen_key_shape_trigger">Spoušť</string>
|
||||
<string name="screen_key_toggle">Přepínač</string>
|
||||
<string name="screen_key_layout_export">Exportovat</string>
|
||||
<string name="screen_key_shape_pill">Kapsle</string>
|
||||
<string name="screen_key_shape_round">Zaoblené</string>
|
||||
<string name="screen_key_shape_circle">Kruh</string>
|
||||
<string name="screen_key_shape_rect">Obdélník</string>
|
||||
<string name="screen_key_bind">Klávesa</string>
|
||||
<string name="screen_key_image">Obrázek</string>
|
||||
<string name="screen_key_image_clear">Vymazat</string>
|
||||
<string name="screen_key_layout">Rozložení</string>
|
||||
<string name="screen_key_layout_save">Uložit</string>
|
||||
<string name="osc_steam_layout_hint">Přesuňte, změňte velikost nebo skryjte dotykové ovládání této hry; uloží se do Steamu</string>
|
||||
<string name="mode_controller">Ovladač</string>
|
||||
<string name="mode_controller_hint">Jak Steam vidí váš ovladač. Použije se od příští relace.</string>
|
||||
@@ -772,7 +756,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automaticky</string>
|
||||
<string name="drawer_relative_mouse_on">Zapnuto</string>
|
||||
<string name="drawer_relative_mouse_off">Vypnuto</string>
|
||||
<string name="drawer_direct_cursor">Kurzor</string>
|
||||
<string name="drawer_pc_keyboard">Klávesnice PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Druhá obrazovka</string>
|
||||
@@ -1123,43 +1106,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB z počítače (poslední možnost)</string>
|
||||
<string name="wadb_only_if">Jen pokud Bezdrátové ladění není k dispozici.</string>
|
||||
<string name="wadb_computer_group">3 · ADB z počítače (poslední možnost)</string>
|
||||
<string name="ctrl_osc_hint">Kdy se dotykové ovládání zobrazí v relaci</string>
|
||||
<string name="ctrl_color">Barva</string>
|
||||
<string name="ctrl_color_hint">Odstín tlačítek na obrazovce</string>
|
||||
<string name="ctrl_custom">Vlastní</string>
|
||||
<string name="ctrl_opacity">Průhlednost</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Velikost tlačítek</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100 % je standardní velikost</string>
|
||||
<string name="ctrl_stick_click">Kliknutí páčkou</string>
|
||||
<string name="ctrl_stick_click_hint">Dvojitým dotykem a podržením páčky aktivujete L3 nebo R3</string>
|
||||
<string name="ctrl_adaptive">Adaptivní páčky</string>
|
||||
<string name="ctrl_rumble">Vibrace ve hře</string>
|
||||
<string name="ctrl_dead_zone">Mrtvá zóna páčky</string>
|
||||
<string name="ctrl_steam_button">Tlačítko Steam</string>
|
||||
<string name="ctrl_qam_button">Tlačítko QAM</string>
|
||||
<string name="ctrl_keyboard_button">Tlačítko klávesnice</string>
|
||||
<string name="ctrl_select_steam">Otevřít nabídku Steam stisknutím Select</string>
|
||||
<string name="ctrl_select_steam_hint">Místo View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Cony jako ovladače VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">Když běží SteamVR, každý Joy-Con slouží jako ruka. Namiřte ho dopředu a podržením Home nebo Capture ho znovu vycentrujete.</string>
|
||||
<string name="setup_animations">Animace</string>
|
||||
<string name="ctrl_adaptive_hint">Páčky se zobrazí tam, kde se dotknete, a skryjí se po uvolnění</string>
|
||||
<string name="ctrl_layout">Rozložení</string>
|
||||
<string name="ctrl_layout_custom">Uloženy vlastní pozice</string>
|
||||
<string name="ctrl_layout_default">Přizpůsobeno této obrazovce</string>
|
||||
<string name="ctrl_edit">Upravit</string>
|
||||
<string name="ctrl_reset">Obnovit</string>
|
||||
<string name="ctrl_mapping">Mapování tlačítek</string>
|
||||
<string name="ctrl_mapping_default">Každé tlačítko odesílá svůj vlastní vstup</string>
|
||||
<string name="ctrl_mapping_count">%1$d z %2$d tlačítek přemapováno</string>
|
||||
<string name="ctrl_configure">Konfigurovat</string>
|
||||
<string name="ctrl_reset_all">Obnovit ovladač</string>
|
||||
<string name="ctrl_reset_all_hint">Obnoví všechna nastavení ovladače a rozložení</string>
|
||||
<string name="ctrl_mapping_lede">Co každé tlačítko na obrazovce odesílá hře. Skryté tlačítko odstraní.</string>
|
||||
<string name="ctrl_onscreen_buttons">Tlačítka na obrazovce</string>
|
||||
<string name="ctrl_defaults">Výchozí</string>
|
||||
<string name="ctrl_reset_mapping">Obnovit mapování</string>
|
||||
<string name="content_android_apps">Aplikace Android</string>
|
||||
<string name="content_apps_count">%1$d aplikací</string>
|
||||
<string name="content_no_android_apps">Nebyly nalezeny žádné spustitelné aplikace Android.</string>
|
||||
@@ -1281,15 +1244,8 @@
|
||||
<string name="deck_surface_stick">Páčka</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Přepnout mezi páčkou a trackpadem</string>
|
||||
<string name="deck_more_controls">Další ovládání Deck</string>
|
||||
<string name="deck_panels">PANELY</string>
|
||||
<string name="deck_close">Zavřít ovládání druhé obrazovky</string>
|
||||
<string name="deck_open_steam_menu">Otevřít nabídku Steamu</string>
|
||||
<string name="deck_left_upper">Levý · horní</string>
|
||||
<string name="deck_left_lower">Levý · dolní</string>
|
||||
<string name="deck_right_upper">Pravý · horní</string>
|
||||
<string name="deck_right_lower">Pravý · dolní</string>
|
||||
<string name="deck_click">Kliknutí</string>
|
||||
<string name="deck_right_trackpad">Pravý trackpad</string>
|
||||
<string name="deck_left_trackpad">Levý trackpad</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1855,9 +1811,7 @@
|
||||
<string name="ctrl_target_left">D-pad vlevo</string>
|
||||
<string name="ctrl_target_right">D-pad vpravo</string>
|
||||
<string name="ctrl_target_hidden">Skryté</string>
|
||||
<string name="ctrl_editor_drag">Přetažením přesunete</string>
|
||||
<string name="ctrl_editor_snap">Přichytit</string>
|
||||
<string name="ctrl_editor_save">Uložit</string>
|
||||
<string name="second_mode_none">Žádný</string>
|
||||
<string name="second_mode_keyboard_trackpad">Klávesnice + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminál</string>
|
||||
@@ -2711,7 +2665,6 @@
|
||||
<string name="gog_achievements_unavailable">Achievementy nejsou k dispozici; zkontrolujte protokoly relace</string>
|
||||
<string name="achievement_unlocked">Achievement odemčen</string>
|
||||
<string name="touch_paste">Vložit</string>
|
||||
<string name="touch_dpad">Křížový ovladač</string>
|
||||
<string name="touch_left_stick">Levá páčka</string>
|
||||
<string name="touch_right_stick">Pravá páčka</string>
|
||||
<string name="touch_menu">Nabídka</string>
|
||||
@@ -3780,4 +3733,7 @@
|
||||
<string name="addons_none_found">Nenalezeny žádné doplňky</string>
|
||||
<string name="addons_unreachable">Nelze se připojit k %1$s</string>
|
||||
<string name="addons_no_file">Pro tuto verzi hry není k dispozici soubor</string>
|
||||
<string name="input_reset_positions">Obnovit pozice</string>
|
||||
<string name="input_show_label">Zobrazit popisek</string>
|
||||
<string name="input_layout_import_failed">Toto rozložení nelze importovat</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam-berøring (beta)</string>
|
||||
<string name="osc_style_next_session">Steams berøringskontroller starter med næste Steam-session</string>
|
||||
<string name="osc_steam_layout">Steam-berøringslayout</string>
|
||||
<string name="screen_keys">Skærmtaster</string>
|
||||
<string name="screen_keys_add">Tilføj tast</string>
|
||||
<string name="screen_key_text">Tekst</string>
|
||||
<string name="screen_key_size">Størrelse</string>
|
||||
<string name="screen_key_opacity">Gennemsigtighed</string>
|
||||
<string name="screen_key_type_button">Tast</string>
|
||||
<string name="screen_key_shape_trigger">Udløser</string>
|
||||
<string name="screen_key_toggle">Skift</string>
|
||||
<string name="screen_key_layout_export">Eksportér</string>
|
||||
<string name="screen_key_shape_pill">Kapsel</string>
|
||||
<string name="screen_key_shape_round">Afrundet</string>
|
||||
<string name="screen_key_shape_circle">Cirkel</string>
|
||||
<string name="screen_key_shape_rect">Rektangel</string>
|
||||
<string name="screen_key_bind">Tast</string>
|
||||
<string name="screen_key_image">Billede</string>
|
||||
<string name="screen_key_image_clear">Ryd</string>
|
||||
<string name="screen_key_layout">Layout</string>
|
||||
<string name="screen_key_layout_save">Gem</string>
|
||||
<string name="osc_steam_layout_hint">Flyt, tilpas størrelsen på eller skjul dette spils berøringskontroller; gemmes til Steam</string>
|
||||
<string name="mode_controller">Controller</string>
|
||||
<string name="mode_controller_hint">Hvordan Steam ser din controller. Gælder fra næste session.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatisk</string>
|
||||
<string name="drawer_relative_mouse_on">Til</string>
|
||||
<string name="drawer_relative_mouse_off">Fra</string>
|
||||
<string name="drawer_direct_cursor">Markør</string>
|
||||
<string name="drawer_pc_keyboard">PC-tastatur</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Anden skærm</string>
|
||||
@@ -1111,43 +1094,23 @@
|
||||
<string name="wadb_computer_last">3 · Computer-ADB (sidste udvej)</string>
|
||||
<string name="wadb_only_if">Kun hvis Trådløs fejlretning ikke er tilgængelig.</string>
|
||||
<string name="wadb_computer_group">3 · Computer-ADB (sidste udvej)</string>
|
||||
<string name="ctrl_osc_hint">Hvornår berøringskontrollerne vises i en session</string>
|
||||
<string name="ctrl_color">Farve</string>
|
||||
<string name="ctrl_color_hint">Farvetone for knapperne på skærmen</string>
|
||||
<string name="ctrl_custom">Brugerdefineret</string>
|
||||
<string name="ctrl_opacity">Gennemsigtighed</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Knapstørrelse</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% er standardstørrelsen</string>
|
||||
<string name="ctrl_stick_click">Stick-klik</string>
|
||||
<string name="ctrl_stick_click_hint">Dobbelttryk og hold en stick nede for L3 eller R3</string>
|
||||
<string name="ctrl_adaptive">Adaptive styrepinde</string>
|
||||
<string name="ctrl_rumble">Spilvibration</string>
|
||||
<string name="ctrl_dead_zone">Dødzone for styrepind</string>
|
||||
<string name="ctrl_steam_button">Steam-knap</string>
|
||||
<string name="ctrl_qam_button">QAM-knap</string>
|
||||
<string name="ctrl_keyboard_button">Tastaturknap</string>
|
||||
<string name="ctrl_select_steam">Tryk på Select for at åbne Steam-menuen</string>
|
||||
<string name="ctrl_select_steam_hint">I stedet for View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Cons som VR-controllere</string>
|
||||
<string name="ctrl_joycon_vr_hint">Mens SteamVR kører, bliver hver Joy-Con en hånd. Peg den fremad, og hold Home eller Capture nede for at centrere den igen.</string>
|
||||
<string name="setup_animations">Animationer</string>
|
||||
<string name="ctrl_adaptive_hint">Sticks vises, hvor du rører skærmen, og skjules, når du slipper</string>
|
||||
<string name="ctrl_layout">Layout</string>
|
||||
<string name="ctrl_layout_custom">Brugerdefinerede positioner gemt</string>
|
||||
<string name="ctrl_layout_default">Tilpasset denne skærm</string>
|
||||
<string name="ctrl_edit">Rediger</string>
|
||||
<string name="ctrl_reset">Nulstil</string>
|
||||
<string name="ctrl_mapping">Knapmapning</string>
|
||||
<string name="ctrl_mapping_default">Hver knap sender sit eget input</string>
|
||||
<string name="ctrl_mapping_count">%1$d af %2$d knapper ommappet</string>
|
||||
<string name="ctrl_configure">Konfigurer</string>
|
||||
<string name="ctrl_reset_all">Nulstil controller</string>
|
||||
<string name="ctrl_reset_all_hint">Gendanner alle controllerindstillinger og layoutet</string>
|
||||
<string name="ctrl_mapping_lede">Hvad hver knap på skærmen sender til spillet. Skjult fjerner knappen.</string>
|
||||
<string name="ctrl_onscreen_buttons">Knapper på skærmen</string>
|
||||
<string name="ctrl_defaults">Standarder</string>
|
||||
<string name="ctrl_reset_mapping">Nulstil mapning</string>
|
||||
<string name="content_android_apps">Android-apps</string>
|
||||
<string name="content_apps_count">%1$d apps</string>
|
||||
<string name="content_no_android_apps">Ingen Android-apps, der kan startes, fundet.</string>
|
||||
@@ -1267,15 +1230,8 @@
|
||||
<string name="deck_surface_stick">Stick</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Skift mellem stick og trackpad</string>
|
||||
<string name="deck_more_controls">Flere Deck-kontroller</string>
|
||||
<string name="deck_panels">PANELER</string>
|
||||
<string name="deck_close">Luk kontrollerne til den anden skærm</string>
|
||||
<string name="deck_open_steam_menu">Åbn Steam-menuen</string>
|
||||
<string name="deck_left_upper">Venstre · øverst</string>
|
||||
<string name="deck_left_lower">Venstre · nederst</string>
|
||||
<string name="deck_right_upper">Højre · øverst</string>
|
||||
<string name="deck_right_lower">Højre · nederst</string>
|
||||
<string name="deck_click">Klik</string>
|
||||
<string name="deck_right_trackpad">Højre trackpad</string>
|
||||
<string name="deck_left_trackpad">Venstre trackpad</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1807,9 +1763,7 @@
|
||||
<string name="ctrl_target_left">D-pad venstre</string>
|
||||
<string name="ctrl_target_right">D-pad højre</string>
|
||||
<string name="ctrl_target_hidden">Skjult</string>
|
||||
<string name="ctrl_editor_drag">Træk for at flytte</string>
|
||||
<string name="ctrl_editor_snap">Fastgør</string>
|
||||
<string name="ctrl_editor_save">Gem</string>
|
||||
<string name="second_mode_none">Ingen</string>
|
||||
<string name="second_mode_keyboard_trackpad">Tastatur + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2657,7 +2611,6 @@
|
||||
<string name="gog_achievements_unavailable">Bedrifter ikke tilgængelige; se sessionslogs</string>
|
||||
<string name="achievement_unlocked">Bedrift låst op</string>
|
||||
<string name="touch_paste">Indsæt</string>
|
||||
<string name="touch_dpad">Styrekryds</string>
|
||||
<string name="touch_left_stick">Venstre stick</string>
|
||||
<string name="touch_right_stick">Højre stick</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Ingen tilføjelser fundet</string>
|
||||
<string name="addons_unreachable">Kunne ikke nå %1$s</string>
|
||||
<string name="addons_no_file">Ingen fil til denne spilversion</string>
|
||||
<string name="input_reset_positions">Nulstil placeringer</string>
|
||||
<string name="input_show_label">Vis etiket</string>
|
||||
<string name="input_layout_import_failed">Dette layout kunne ikke importeres</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam-Touch (Beta)</string>
|
||||
<string name="osc_style_next_session">Steams Touch-Steuerung startet mit der nächsten Steam-Sitzung</string>
|
||||
<string name="osc_steam_layout">Steam-Touch-Layout</string>
|
||||
<string name="screen_keys">Bildschirmtasten</string>
|
||||
<string name="screen_keys_add">Taste hinzufügen</string>
|
||||
<string name="screen_key_text">Text</string>
|
||||
<string name="screen_key_size">Größe</string>
|
||||
<string name="screen_key_opacity">Deckkraft</string>
|
||||
<string name="screen_key_type_button">Taste</string>
|
||||
<string name="screen_key_shape_trigger">Trigger</string>
|
||||
<string name="screen_key_toggle">Umschalten</string>
|
||||
<string name="screen_key_layout_export">Exportieren</string>
|
||||
<string name="screen_key_shape_pill">Kapsel</string>
|
||||
<string name="screen_key_shape_round">Rund</string>
|
||||
<string name="screen_key_shape_circle">Kreis</string>
|
||||
<string name="screen_key_shape_rect">Rechteck</string>
|
||||
<string name="screen_key_bind">Taste</string>
|
||||
<string name="screen_key_image">Bild</string>
|
||||
<string name="screen_key_image_clear">Entfernen</string>
|
||||
<string name="screen_key_layout">Layout</string>
|
||||
<string name="screen_key_layout_save">Speichern</string>
|
||||
<string name="osc_steam_layout_hint">Touch-Steuerung dieses Spiels verschieben, skalieren oder ausblenden; wird in Steam gespeichert</string>
|
||||
<string name="mode_controller">Controller</string>
|
||||
<string name="mode_controller_hint">Wie Steam deinen Controller erkennt. Gilt ab der nächsten Sitzung.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatisch</string>
|
||||
<string name="drawer_relative_mouse_on">An</string>
|
||||
<string name="drawer_relative_mouse_off">Aus</string>
|
||||
<string name="drawer_direct_cursor">Zeiger</string>
|
||||
<string name="drawer_pc_keyboard">PC-Tastatur</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Zweiter Bildschirm</string>
|
||||
@@ -1103,43 +1086,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB am Computer (letzter Ausweg)</string>
|
||||
<string name="wadb_only_if">Nur wenn „Debugging über WLAN“ nicht verfügbar ist.</string>
|
||||
<string name="wadb_computer_group">3 · ADB am Computer (letzter Ausweg)</string>
|
||||
<string name="ctrl_osc_hint">Wann die Touch-Steuerung in einer Sitzung erscheint</string>
|
||||
<string name="ctrl_color">Farbe</string>
|
||||
<string name="ctrl_color_hint">Farbton der Bildschirmtasten</string>
|
||||
<string name="ctrl_custom">Benutzerdefiniert</string>
|
||||
<string name="ctrl_opacity">Deckkraft</string>
|
||||
<string name="ctrl_percent">%1$d %%</string>
|
||||
<string name="ctrl_size">Tastengröße</string>
|
||||
<string name="ctrl_size_hint" formatted="false">Standardgröße: 100 %</string>
|
||||
<string name="ctrl_stick_click">Stick-Klick</string>
|
||||
<string name="ctrl_stick_click_hint">Doppeltippen und Stick halten für L3 oder R3</string>
|
||||
<string name="ctrl_adaptive">Adaptive Sticks</string>
|
||||
<string name="ctrl_rumble">Spielvibration</string>
|
||||
<string name="ctrl_dead_zone">Stick-Totzone</string>
|
||||
<string name="ctrl_steam_button">Steam-Taste</string>
|
||||
<string name="ctrl_qam_button">QAM-Taste</string>
|
||||
<string name="ctrl_keyboard_button">Tastatur-Taste</string>
|
||||
<string name="ctrl_select_steam">Mit Select das Steam-Menü öffnen</string>
|
||||
<string name="ctrl_select_steam_hint">Statt View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Cons als VR-Controller</string>
|
||||
<string name="ctrl_joycon_vr_hint">Während SteamVR läuft, wird jeder Joy-Con zu einer Hand. Richte ihn nach vorn und halte HOME oder Capture gedrückt, um ihn neu auszurichten.</string>
|
||||
<string name="setup_animations">Animationen</string>
|
||||
<string name="ctrl_adaptive_hint">Sticks erscheinen dort, wo du tippst, und verschwinden beim Loslassen</string>
|
||||
<string name="ctrl_layout">Layout</string>
|
||||
<string name="ctrl_layout_custom">Eigene Positionen gespeichert</string>
|
||||
<string name="ctrl_layout_default">An diesen Bildschirm angepasst</string>
|
||||
<string name="ctrl_edit">Bearbeiten</string>
|
||||
<string name="ctrl_reset">Zurücksetzen</string>
|
||||
<string name="ctrl_mapping">Tastenbelegung</string>
|
||||
<string name="ctrl_mapping_default">Jede Taste sendet ihre eigene Eingabe</string>
|
||||
<string name="ctrl_mapping_count">%1$d von %2$d Tasten neu belegt</string>
|
||||
<string name="ctrl_configure">Konfigurieren</string>
|
||||
<string name="ctrl_reset_all">Controller zurücksetzen</string>
|
||||
<string name="ctrl_reset_all_hint">Stellt alle Controller-Einstellungen und das Layout wieder her</string>
|
||||
<string name="ctrl_mapping_lede">Was jede Bildschirmtaste an das Spiel sendet. „Ausgeblendet“ entfernt die Taste.</string>
|
||||
<string name="ctrl_onscreen_buttons">Bildschirmtasten</string>
|
||||
<string name="ctrl_defaults">Standardwerte</string>
|
||||
<string name="ctrl_reset_mapping">Belegung zurücksetzen</string>
|
||||
<string name="content_android_apps">Android-Apps</string>
|
||||
<string name="content_apps_count">%1$d Apps</string>
|
||||
<string name="content_no_android_apps">Keine startbaren Android-Apps gefunden.</string>
|
||||
@@ -1259,15 +1222,8 @@
|
||||
<string name="deck_surface_stick">Stick</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Zwischen Stick und Trackpad wechseln</string>
|
||||
<string name="deck_more_controls">Weitere Deck-Steuerelemente</string>
|
||||
<string name="deck_panels">BEREICHE</string>
|
||||
<string name="deck_close">Steuerung auf dem Zweitbildschirm schließen</string>
|
||||
<string name="deck_open_steam_menu">Steam-Menü öffnen</string>
|
||||
<string name="deck_left_upper">Links · oben</string>
|
||||
<string name="deck_left_lower">Links · unten</string>
|
||||
<string name="deck_right_upper">Rechts · oben</string>
|
||||
<string name="deck_right_lower">Rechts · unten</string>
|
||||
<string name="deck_click">Klick</string>
|
||||
<string name="deck_right_trackpad">Rechtes Trackpad</string>
|
||||
<string name="deck_left_trackpad">Linkes Trackpad</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1799,9 +1755,7 @@
|
||||
<string name="ctrl_target_left">Steuerkreuz links</string>
|
||||
<string name="ctrl_target_right">Steuerkreuz rechts</string>
|
||||
<string name="ctrl_target_hidden">Ausgeblendet</string>
|
||||
<string name="ctrl_editor_drag">Zum Verschieben ziehen</string>
|
||||
<string name="ctrl_editor_snap">Einrasten</string>
|
||||
<string name="ctrl_editor_save">Speichern</string>
|
||||
<string name="second_mode_none">Nichts</string>
|
||||
<string name="second_mode_keyboard_trackpad">Tastatur + Trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2646,7 +2600,6 @@
|
||||
<string name="gog_achievements_unavailable">Erfolge nicht verfügbar; Sitzungsprotokolle prüfen</string>
|
||||
<string name="achievement_unlocked">Erfolg freigeschaltet</string>
|
||||
<string name="touch_paste">Einfügen</string>
|
||||
<string name="touch_dpad">Richtungstasten</string>
|
||||
<string name="touch_left_stick">Linker Stick</string>
|
||||
<string name="touch_right_stick">Rechter Stick</string>
|
||||
<string name="touch_menu">Menü</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Keine Addons gefunden</string>
|
||||
<string name="addons_unreachable">%1$s ist nicht erreichbar</string>
|
||||
<string name="addons_no_file">Keine Datei für diese Spielversion</string>
|
||||
<string name="input_reset_positions">Positionen zurücksetzen</string>
|
||||
<string name="input_show_label">Beschriftung anzeigen</string>
|
||||
<string name="input_layout_import_failed">Dieses Layout konnte nicht importiert werden</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Αφή Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Τα χειριστήρια αφής του Steam ξεκινούν από την επόμενη συνεδρία Steam</string>
|
||||
<string name="osc_steam_layout">Διάταξη αφής Steam</string>
|
||||
<string name="screen_keys">Πλήκτρα οθόνης</string>
|
||||
<string name="screen_keys_add">Προσθήκη πλήκτρου</string>
|
||||
<string name="screen_key_text">Κείμενο</string>
|
||||
<string name="screen_key_size">Μέγεθος</string>
|
||||
<string name="screen_key_opacity">Διαφάνεια</string>
|
||||
<string name="screen_key_type_button">Πλήκτρο</string>
|
||||
<string name="screen_key_shape_trigger">Σκανδάλη</string>
|
||||
<string name="screen_key_toggle">Εναλλαγή</string>
|
||||
<string name="screen_key_layout_export">Εξαγωγή</string>
|
||||
<string name="screen_key_shape_pill">Κάψουλα</string>
|
||||
<string name="screen_key_shape_round">Στρογγυλεμένο</string>
|
||||
<string name="screen_key_shape_circle">Κύκλος</string>
|
||||
<string name="screen_key_shape_rect">Ορθογώνιο</string>
|
||||
<string name="screen_key_bind">Πλήκτρο</string>
|
||||
<string name="screen_key_image">Εικόνα</string>
|
||||
<string name="screen_key_image_clear">Εκκαθάριση</string>
|
||||
<string name="screen_key_layout">Διάταξη</string>
|
||||
<string name="screen_key_layout_save">Αποθήκευση</string>
|
||||
<string name="osc_steam_layout_hint">Μετακινήστε, αλλάξτε μέγεθος ή αποκρύψτε τα χειριστήρια αφής αυτού του παιχνιδιού· αποθηκεύεται στο Steam</string>
|
||||
<string name="mode_controller">Χειριστήριο</string>
|
||||
<string name="mode_controller_hint">Πώς βλέπει το Steam το χειριστήριό σας. Εφαρμόζεται στην επόμενη συνεδρία.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Αυτόματα</string>
|
||||
<string name="drawer_relative_mouse_on">Ενεργό</string>
|
||||
<string name="drawer_relative_mouse_off">Ανενεργό</string>
|
||||
<string name="drawer_direct_cursor">Δείκτης</string>
|
||||
<string name="drawer_pc_keyboard">Πληκτρολόγιο PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Δεύτερη οθόνη</string>
|
||||
@@ -1111,43 +1094,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB υπολογιστή (τελευταία λύση)</string>
|
||||
<string name="wadb_only_if">Μόνο αν ο Ασύρματος εντοπισμός σφαλμάτων δεν είναι διαθέσιμος.</string>
|
||||
<string name="wadb_computer_group">3 · ADB υπολογιστή (τελευταία λύση)</string>
|
||||
<string name="ctrl_osc_hint">Όταν εμφανίζονται τα χειριστήρια αφής σε μια συνεδρία</string>
|
||||
<string name="ctrl_color">Χρώμα</string>
|
||||
<string name="ctrl_color_hint">Απόχρωση των κουμπιών οθόνης</string>
|
||||
<string name="ctrl_custom">Προσαρμοσμένο</string>
|
||||
<string name="ctrl_opacity">Διαφάνεια</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Μέγεθος κουμπιών</string>
|
||||
<string name="ctrl_size_hint" formatted="false">Το 100% είναι το κανονικό μέγεθος</string>
|
||||
<string name="ctrl_stick_click">Κλικ μοχλού</string>
|
||||
<string name="ctrl_stick_click_hint">Πατήστε δύο φορές και κρατήστε έναν μοχλό για L3 ή R3</string>
|
||||
<string name="ctrl_adaptive">Προσαρμοστικοί μοχλοί</string>
|
||||
<string name="ctrl_rumble">Κραδασμός παιχνιδιού</string>
|
||||
<string name="ctrl_dead_zone">Νεκρή ζώνη μοχλού</string>
|
||||
<string name="ctrl_steam_button">Κουμπί Steam</string>
|
||||
<string name="ctrl_qam_button">Κουμπί QAM</string>
|
||||
<string name="ctrl_keyboard_button">Κουμπί πληκτρολογίου</string>
|
||||
<string name="ctrl_select_steam">Πατήστε Select για να ανοίξετε το μενού Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Αντί για View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con ως χειριστήρια VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">Όσο εκτελείται το SteamVR, κάθε Joy-Con γίνεται χέρι. Στρέψτε το μπροστά και κρατήστε πατημένο το Home ή το Capture για να το επανακεντράρετε.</string>
|
||||
<string name="setup_animations">Κινήσεις</string>
|
||||
<string name="ctrl_adaptive_hint">Οι μοχλοί εμφανίζονται όπου αγγίζετε και εξαφανίζονται όταν αφήνετε</string>
|
||||
<string name="ctrl_layout">Διάταξη</string>
|
||||
<string name="ctrl_layout_custom">Αποθηκεύτηκαν προσαρμοσμένες θέσεις</string>
|
||||
<string name="ctrl_layout_default">Προσαρμοσμένο σε αυτή την οθόνη</string>
|
||||
<string name="ctrl_edit">Επεξεργασία</string>
|
||||
<string name="ctrl_reset">Επαναφορά</string>
|
||||
<string name="ctrl_mapping">Αντιστοίχιση κουμπιών</string>
|
||||
<string name="ctrl_mapping_default">Κάθε κουμπί στέλνει τη δική του είσοδο</string>
|
||||
<string name="ctrl_mapping_count">%1$d από %2$d κουμπιά επαναντιστοιχίστηκαν</string>
|
||||
<string name="ctrl_configure">Διαμόρφωση</string>
|
||||
<string name="ctrl_reset_all">Επαναφορά χειριστηρίου</string>
|
||||
<string name="ctrl_reset_all_hint">Επαναφέρει όλες τις ρυθμίσεις χειριστηρίου και τη διάταξη</string>
|
||||
<string name="ctrl_mapping_lede">Τι στέλνει κάθε κουμπί οθόνης στο παιχνίδι. Το Κρυμμένο αφαιρεί το κουμπί.</string>
|
||||
<string name="ctrl_onscreen_buttons">Κουμπιά οθόνης</string>
|
||||
<string name="ctrl_defaults">Προεπιλογές</string>
|
||||
<string name="ctrl_reset_mapping">Επαναφορά αντιστοίχισης</string>
|
||||
<string name="content_android_apps">Εφαρμογές Android</string>
|
||||
<string name="content_apps_count">%1$d εφαρμογές</string>
|
||||
<string name="content_no_android_apps">Δεν βρέθηκαν εφαρμογές Android για εκκίνηση.</string>
|
||||
@@ -1267,15 +1230,8 @@
|
||||
<string name="deck_surface_stick">Μοχλός</string>
|
||||
<string name="deck_surface_trackpad">Πινακίδα αφής</string>
|
||||
<string name="deck_surface_switch">Εναλλαγή μεταξύ μοχλού και πινακίδας αφής</string>
|
||||
<string name="deck_more_controls">Περισσότερα χειριστήρια Deck</string>
|
||||
<string name="deck_panels">ΠΙΝΑΚΕΣ</string>
|
||||
<string name="deck_close">Κλείσιμο χειριστηρίων δεύτερης οθόνης</string>
|
||||
<string name="deck_open_steam_menu">Άνοιγμα μενού Steam</string>
|
||||
<string name="deck_left_upper">Αριστερά · πάνω</string>
|
||||
<string name="deck_left_lower">Αριστερά · κάτω</string>
|
||||
<string name="deck_right_upper">Δεξιά · πάνω</string>
|
||||
<string name="deck_right_lower">Δεξιά · κάτω</string>
|
||||
<string name="deck_click">Κλικ</string>
|
||||
<string name="deck_right_trackpad">Δεξιά πινακίδα αφής</string>
|
||||
<string name="deck_left_trackpad">Αριστερή πινακίδα αφής</string>
|
||||
<string name="second_trackpad">Πινακίδα αφής</string>
|
||||
@@ -1807,9 +1763,7 @@
|
||||
<string name="ctrl_target_left">D-pad αριστερά</string>
|
||||
<string name="ctrl_target_right">D-pad δεξιά</string>
|
||||
<string name="ctrl_target_hidden">Κρυφό</string>
|
||||
<string name="ctrl_editor_drag">Σύρετε για μετακίνηση</string>
|
||||
<string name="ctrl_editor_snap">Προσκόλληση</string>
|
||||
<string name="ctrl_editor_save">Αποθήκευση</string>
|
||||
<string name="second_mode_none">Κανένα</string>
|
||||
<string name="second_mode_keyboard_trackpad">Πληκτρολόγιο + πινακίδα αφής</string>
|
||||
<string name="second_mode_terminal">Τερματικό</string>
|
||||
@@ -2657,7 +2611,6 @@
|
||||
<string name="gog_achievements_unavailable">Τα επιτεύγματα δεν είναι διαθέσιμα· ελέγξτε τα αρχεία καταγραφής της συνεδρίας</string>
|
||||
<string name="achievement_unlocked">Το επίτευγμα ξεκλειδώθηκε</string>
|
||||
<string name="touch_paste">Επικόλληση</string>
|
||||
<string name="touch_dpad">Σταυρός κατεύθυνσης</string>
|
||||
<string name="touch_left_stick">Αριστερό στικ</string>
|
||||
<string name="touch_right_stick">Δεξί στικ</string>
|
||||
<string name="touch_menu">Μενού</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Δεν βρέθηκαν πρόσθετα</string>
|
||||
<string name="addons_unreachable">Δεν ήταν δυνατή η σύνδεση με %1$s</string>
|
||||
<string name="addons_no_file">Δεν υπάρχει αρχείο για αυτή την έκδοση του παιχνιδιού</string>
|
||||
<string name="input_reset_positions">Επαναφορά θέσεων</string>
|
||||
<string name="input_show_label">Εμφάνιση ετικέτας</string>
|
||||
<string name="input_layout_import_failed">Δεν ήταν δυνατή η εισαγωγή αυτής της διάταξης</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Táctil de Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Los controles táctiles de Steam se activan en la próxima sesión de Steam</string>
|
||||
<string name="osc_steam_layout">Disposición táctil de Steam</string>
|
||||
<string name="screen_keys">Teclas en pantalla</string>
|
||||
<string name="screen_keys_add">Añadir tecla</string>
|
||||
<string name="screen_key_text">Texto</string>
|
||||
<string name="screen_key_size">Tamaño</string>
|
||||
<string name="screen_key_opacity">Opacidad</string>
|
||||
<string name="screen_key_type_button">Tecla</string>
|
||||
<string name="screen_key_shape_trigger">Gatillo</string>
|
||||
<string name="screen_key_toggle">Alternar</string>
|
||||
<string name="screen_key_layout_export">Exportar</string>
|
||||
<string name="screen_key_shape_pill">Píldora</string>
|
||||
<string name="screen_key_shape_round">Redondeado</string>
|
||||
<string name="screen_key_shape_circle">Círculo</string>
|
||||
<string name="screen_key_shape_rect">Rectángulo</string>
|
||||
<string name="screen_key_bind">Tecla</string>
|
||||
<string name="screen_key_image">Imagen</string>
|
||||
<string name="screen_key_image_clear">Borrar</string>
|
||||
<string name="screen_key_layout">Disposición</string>
|
||||
<string name="screen_key_layout_save">Guardar</string>
|
||||
<string name="osc_steam_layout_hint">Mueve, cambia de tamaño u oculta los controles táctiles de este juego; se guarda en Steam</string>
|
||||
<string name="mode_controller">Mando</string>
|
||||
<string name="mode_controller_hint">Cómo ve Steam tu mando. Se aplica en la próxima sesión.</string>
|
||||
@@ -770,7 +754,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automático</string>
|
||||
<string name="drawer_relative_mouse_on">Activado</string>
|
||||
<string name="drawer_relative_mouse_off">Desactivado</string>
|
||||
<string name="drawer_direct_cursor">Cursor</string>
|
||||
<string name="drawer_pc_keyboard">Teclado de PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Segunda pantalla</string>
|
||||
@@ -1117,43 +1100,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB desde ordenador (último recurso)</string>
|
||||
<string name="wadb_only_if">Solo si la Depuración inalámbrica no está disponible.</string>
|
||||
<string name="wadb_computer_group">3 · ADB desde ordenador (último recurso)</string>
|
||||
<string name="ctrl_osc_hint">Cuándo aparecen los controles táctiles en una sesión</string>
|
||||
<string name="ctrl_color">Color</string>
|
||||
<string name="ctrl_color_hint">Tinte de los botones en pantalla</string>
|
||||
<string name="ctrl_custom">Personalizado</string>
|
||||
<string name="ctrl_opacity">Opacidad</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Tamaño de botones</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% es el tamaño estándar</string>
|
||||
<string name="ctrl_stick_click">Clic del stick</string>
|
||||
<string name="ctrl_stick_click_hint">Toca dos veces y mantén un stick para L3 o R3</string>
|
||||
<string name="ctrl_adaptive">Sticks adaptables</string>
|
||||
<string name="ctrl_rumble">Vibración en juegos</string>
|
||||
<string name="ctrl_dead_zone">Zona muerta de la palanca</string>
|
||||
<string name="ctrl_steam_button">Botón Steam</string>
|
||||
<string name="ctrl_qam_button">Botón QAM</string>
|
||||
<string name="ctrl_keyboard_button">Botón de teclado</string>
|
||||
<string name="ctrl_select_steam">Pulsa Select para abrir el menú de Steam</string>
|
||||
<string name="ctrl_select_steam_hint">En lugar de View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con como mandos de RV</string>
|
||||
<string name="ctrl_joycon_vr_hint">Mientras SteamVR está activo, cada Joy-Con es una mano. Apúntalo al frente y mantén Home o Captura para recentrarlo.</string>
|
||||
<string name="setup_animations">Animaciones</string>
|
||||
<string name="ctrl_adaptive_hint">Los sticks aparecen donde tocas y se ocultan al soltar</string>
|
||||
<string name="ctrl_layout">Disposición</string>
|
||||
<string name="ctrl_layout_custom">Posiciones personalizadas guardadas</string>
|
||||
<string name="ctrl_layout_default">Ajustada a esta pantalla</string>
|
||||
<string name="ctrl_edit">Editar</string>
|
||||
<string name="ctrl_reset">Restablecer</string>
|
||||
<string name="ctrl_mapping">Asignación de botones</string>
|
||||
<string name="ctrl_mapping_default">Cada botón envía su propia entrada</string>
|
||||
<string name="ctrl_mapping_count">%1$d de %2$d botones reasignados</string>
|
||||
<string name="ctrl_configure">Configurar</string>
|
||||
<string name="ctrl_reset_all">Restablecer mando</string>
|
||||
<string name="ctrl_reset_all_hint">Restaura todos los ajustes del mando y la disposición</string>
|
||||
<string name="ctrl_mapping_lede">Lo que cada botón en pantalla envía al juego. Oculto quita el botón.</string>
|
||||
<string name="ctrl_onscreen_buttons">Botones en pantalla</string>
|
||||
<string name="ctrl_defaults">Predeterminados</string>
|
||||
<string name="ctrl_reset_mapping">Restablecer asignación</string>
|
||||
<string name="content_android_apps">Apps de Android</string>
|
||||
<string name="content_apps_count">%1$d apps</string>
|
||||
<string name="content_no_android_apps">No se encontraron apps de Android que se puedan abrir.</string>
|
||||
@@ -1274,15 +1237,8 @@
|
||||
<string name="deck_surface_stick">Stick</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Cambiar entre stick y trackpad</string>
|
||||
<string name="deck_more_controls">Más controles de Deck</string>
|
||||
<string name="deck_panels">PANELES</string>
|
||||
<string name="deck_close">Cerrar controles de la segunda pantalla</string>
|
||||
<string name="deck_open_steam_menu">Abrir menú de Steam</string>
|
||||
<string name="deck_left_upper">Izquierdo · superior</string>
|
||||
<string name="deck_left_lower">Izquierdo · inferior</string>
|
||||
<string name="deck_right_upper">Derecho · superior</string>
|
||||
<string name="deck_right_lower">Derecho · inferior</string>
|
||||
<string name="deck_click">Clic</string>
|
||||
<string name="deck_right_trackpad">Trackpad derecho</string>
|
||||
<string name="deck_left_trackpad">Trackpad izquierdo</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1831,9 +1787,7 @@
|
||||
<string name="ctrl_target_left">Cruceta izquierda</string>
|
||||
<string name="ctrl_target_right">Cruceta derecha</string>
|
||||
<string name="ctrl_target_hidden">Oculto</string>
|
||||
<string name="ctrl_editor_drag">Arrastra para mover</string>
|
||||
<string name="ctrl_editor_snap">Ajustar</string>
|
||||
<string name="ctrl_editor_save">Guardar</string>
|
||||
<string name="second_mode_none">Nada</string>
|
||||
<string name="second_mode_keyboard_trackpad">Teclado + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2681,7 +2635,6 @@
|
||||
<string name="gog_achievements_unavailable">Logros no disponibles; revisa los registros de la sesión</string>
|
||||
<string name="achievement_unlocked">Logro desbloqueado</string>
|
||||
<string name="touch_paste">Pegar</string>
|
||||
<string name="touch_dpad">Pad direccional</string>
|
||||
<string name="touch_left_stick">Stick izquierdo</string>
|
||||
<string name="touch_right_stick">Stick derecho</string>
|
||||
<string name="touch_menu">Menú</string>
|
||||
@@ -3741,4 +3694,7 @@
|
||||
<string name="addons_none_found">No se han encontrado complementos</string>
|
||||
<string name="addons_unreachable">No se pudo conectar con %1$s</string>
|
||||
<string name="addons_no_file">No hay ningún archivo para esta versión del juego</string>
|
||||
<string name="input_reset_positions">Restablecer posiciones</string>
|
||||
<string name="input_show_label">Mostrar etiqueta</string>
|
||||
<string name="input_layout_import_failed">No se ha podido importar esta disposición</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam-kosketus (beta)</string>
|
||||
<string name="osc_style_next_session">Steamin kosketusohjaimet otetaan käyttöön seuraavassa Steam-istunnossa</string>
|
||||
<string name="osc_steam_layout">Steamin kosketusasettelu</string>
|
||||
<string name="screen_keys">Näytön näppäimet</string>
|
||||
<string name="screen_keys_add">Lisää näppäin</string>
|
||||
<string name="screen_key_text">Teksti</string>
|
||||
<string name="screen_key_size">Koko</string>
|
||||
<string name="screen_key_opacity">Peittävyys</string>
|
||||
<string name="screen_key_type_button">Näppäin</string>
|
||||
<string name="screen_key_shape_trigger">Liipaisin</string>
|
||||
<string name="screen_key_toggle">Vaihda</string>
|
||||
<string name="screen_key_layout_export">Vie</string>
|
||||
<string name="screen_key_shape_pill">Kapseli</string>
|
||||
<string name="screen_key_shape_round">Pyöristetty</string>
|
||||
<string name="screen_key_shape_circle">Ympyrä</string>
|
||||
<string name="screen_key_shape_rect">Suorakaide</string>
|
||||
<string name="screen_key_bind">Näppäin</string>
|
||||
<string name="screen_key_image">Kuva</string>
|
||||
<string name="screen_key_image_clear">Tyhjennä</string>
|
||||
<string name="screen_key_layout">Asettelu</string>
|
||||
<string name="screen_key_layout_save">Tallenna</string>
|
||||
<string name="osc_steam_layout_hint">Siirrä, muuta kokoa tai piilota tämän pelin kosketusohjaimet; tallennetaan Steamiin</string>
|
||||
<string name="mode_controller">Ohjain</string>
|
||||
<string name="mode_controller_hint">Miten Steam näkee ohjaimesi. Tulee voimaan seuraavassa istunnossa.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automaattinen</string>
|
||||
<string name="drawer_relative_mouse_on">Päällä</string>
|
||||
<string name="drawer_relative_mouse_off">Pois</string>
|
||||
<string name="drawer_direct_cursor">Osoitin</string>
|
||||
<string name="drawer_pc_keyboard">PC-näppäimistö</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Toinen näyttö</string>
|
||||
@@ -1111,43 +1094,23 @@
|
||||
<string name="wadb_computer_last">3 · Tietokoneen ADB (viimeinen keino)</string>
|
||||
<string name="wadb_only_if">Vain jos Langaton virheenkorjaus ei ole käytettävissä.</string>
|
||||
<string name="wadb_computer_group">3 · Tietokoneen ADB (viimeinen keino)</string>
|
||||
<string name="ctrl_osc_hint">Kun kosketusohjaimet näkyvät istunnossa</string>
|
||||
<string name="ctrl_color">Väri</string>
|
||||
<string name="ctrl_color_hint">Näytön painikkeiden sävy</string>
|
||||
<string name="ctrl_custom">Mukautettu</string>
|
||||
<string name="ctrl_opacity">Peittävyys</string>
|
||||
<string name="ctrl_percent">%1$d %%</string>
|
||||
<string name="ctrl_size">Painikkeiden koko</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% on vakiokoko</string>
|
||||
<string name="ctrl_stick_click">Sauvan napsautus</string>
|
||||
<string name="ctrl_stick_click_hint">Kaksoisnapauta ja pidä sauvaa pohjassa saadaksesi L3:n tai R3:n</string>
|
||||
<string name="ctrl_adaptive">Mukautuvat sauvat</string>
|
||||
<string name="ctrl_rumble">Pelin tärinä</string>
|
||||
<string name="ctrl_dead_zone">Ohjaussauvan kuollut alue</string>
|
||||
<string name="ctrl_steam_button">Steam-painike</string>
|
||||
<string name="ctrl_qam_button">QAM-painike</string>
|
||||
<string name="ctrl_keyboard_button">Näppäimistöpainike</string>
|
||||
<string name="ctrl_select_steam">Avaa Steam-valikko Select-painikkeella</string>
|
||||
<string name="ctrl_select_steam_hint">View/Select-painikkeen sijaan.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Conit VR-ohjaimina</string>
|
||||
<string name="ctrl_joycon_vr_hint">Kun SteamVR on käynnissä, jokainen Joy-Con toimii kätenä. Osoita sillä eteenpäin ja pidä Home- tai Capture-painiketta pohjassa keskittääksesi sen uudelleen.</string>
|
||||
<string name="setup_animations">Animaatiot</string>
|
||||
<string name="ctrl_adaptive_hint">Sauvat tulevat näkyviin siihen, mihin kosketat, ja piiloutuvat, kun vapautat</string>
|
||||
<string name="ctrl_layout">Asettelu</string>
|
||||
<string name="ctrl_layout_custom">Mukautetut sijainnit tallennettu</string>
|
||||
<string name="ctrl_layout_default">Sovitettu tähän näyttöön</string>
|
||||
<string name="ctrl_edit">Muokkaa</string>
|
||||
<string name="ctrl_reset">Palauta</string>
|
||||
<string name="ctrl_mapping">Painikkeiden kartoitus</string>
|
||||
<string name="ctrl_mapping_default">Jokainen painike lähettää oman syötteensä</string>
|
||||
<string name="ctrl_mapping_count">%1$d/%2$d painiketta uudelleenkartoitettu</string>
|
||||
<string name="ctrl_configure">Määritä</string>
|
||||
<string name="ctrl_reset_all">Palauta ohjain</string>
|
||||
<string name="ctrl_reset_all_hint">Palauttaa kaikki ohjaimen asetukset ja asettelun</string>
|
||||
<string name="ctrl_mapping_lede">Mitä mikä näytön painike lähettää pelille. Piilotettu poistaa painikkeen.</string>
|
||||
<string name="ctrl_onscreen_buttons">Näytön painikkeet</string>
|
||||
<string name="ctrl_defaults">Oletukset</string>
|
||||
<string name="ctrl_reset_mapping">Palauta kartoitus</string>
|
||||
<string name="content_android_apps">Android-sovellukset</string>
|
||||
<string name="content_apps_count">%1$d sovellusta</string>
|
||||
<string name="content_no_android_apps">Käynnistettäviä Android-sovelluksia ei löytynyt.</string>
|
||||
@@ -1267,15 +1230,8 @@
|
||||
<string name="deck_surface_stick">Tatti</string>
|
||||
<string name="deck_surface_trackpad">Kosketuslevy</string>
|
||||
<string name="deck_surface_switch">Vaihda tatin ja kosketuslevyn välillä</string>
|
||||
<string name="deck_more_controls">Lisää Deck-ohjaimia</string>
|
||||
<string name="deck_panels">PANEELIT</string>
|
||||
<string name="deck_close">Sulje toisen näytön ohjaimet</string>
|
||||
<string name="deck_open_steam_menu">Avaa Steam-valikko</string>
|
||||
<string name="deck_left_upper">Vasen · ylä</string>
|
||||
<string name="deck_left_lower">Vasen · ala</string>
|
||||
<string name="deck_right_upper">Oikea · ylä</string>
|
||||
<string name="deck_right_lower">Oikea · ala</string>
|
||||
<string name="deck_click">Napsautus</string>
|
||||
<string name="deck_right_trackpad">Oikea kosketuslevy</string>
|
||||
<string name="deck_left_trackpad">Vasen kosketuslevy</string>
|
||||
<string name="second_trackpad">Kosketuslevy</string>
|
||||
@@ -1807,9 +1763,7 @@
|
||||
<string name="ctrl_target_left">D-padi vasen</string>
|
||||
<string name="ctrl_target_right">D-padi oikea</string>
|
||||
<string name="ctrl_target_hidden">Piilotettu</string>
|
||||
<string name="ctrl_editor_drag">Vedä siirtääksesi</string>
|
||||
<string name="ctrl_editor_snap">Kohdistus</string>
|
||||
<string name="ctrl_editor_save">Tallenna</string>
|
||||
<string name="second_mode_none">Ei mitään</string>
|
||||
<string name="second_mode_keyboard_trackpad">Näppäimistö + kosketuslevy</string>
|
||||
<string name="second_mode_terminal">Pääte</string>
|
||||
@@ -2657,7 +2611,6 @@
|
||||
<string name="gog_achievements_unavailable">Saavutukset ei käytettävissä; tarkista istunnon lokit</string>
|
||||
<string name="achievement_unlocked">Saavutus avattu</string>
|
||||
<string name="touch_paste">Liitä</string>
|
||||
<string name="touch_dpad">Ristiohjain</string>
|
||||
<string name="touch_left_stick">Vasen tatti</string>
|
||||
<string name="touch_right_stick">Oikea tatti</string>
|
||||
<string name="touch_menu">Valikko</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Lisäosia ei löytynyt</string>
|
||||
<string name="addons_unreachable">Yhteyttä palveluun %1$s ei saatu</string>
|
||||
<string name="addons_no_file">Tälle peliversiolle ei ole tiedostoa</string>
|
||||
<string name="input_reset_positions">Palauta sijainnit</string>
|
||||
<string name="input_show_label">Näytä nimi</string>
|
||||
<string name="input_layout_import_failed">Tätä asettelua ei voitu tuoda</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Tactile Steam (bêta)</string>
|
||||
<string name="osc_style_next_session">Les commandes tactiles de Steam s\'activeront à la prochaine session Steam</string>
|
||||
<string name="osc_steam_layout">Disposition tactile Steam</string>
|
||||
<string name="screen_keys">Touches à l\'écran</string>
|
||||
<string name="screen_keys_add">Ajouter une touche</string>
|
||||
<string name="screen_key_text">Texte</string>
|
||||
<string name="screen_key_size">Taille</string>
|
||||
<string name="screen_key_opacity">Opacité</string>
|
||||
<string name="screen_key_type_button">Touche</string>
|
||||
<string name="screen_key_shape_trigger">Gâchette</string>
|
||||
<string name="screen_key_toggle">Basculer</string>
|
||||
<string name="screen_key_layout_export">Exporter</string>
|
||||
<string name="screen_key_shape_pill">Pilule</string>
|
||||
<string name="screen_key_shape_round">Arrondi</string>
|
||||
<string name="screen_key_shape_circle">Cercle</string>
|
||||
<string name="screen_key_shape_rect">Rectangle</string>
|
||||
<string name="screen_key_bind">Touche</string>
|
||||
<string name="screen_key_image">Image</string>
|
||||
<string name="screen_key_image_clear">Effacer</string>
|
||||
<string name="screen_key_layout">Disposition</string>
|
||||
<string name="screen_key_layout_save">Enregistrer</string>
|
||||
<string name="osc_steam_layout_hint">Déplacez, redimensionnez ou masquez les commandes tactiles de ce jeu ; enregistré dans Steam</string>
|
||||
<string name="mode_controller">Manette</string>
|
||||
<string name="mode_controller_hint">Comment Steam reconnaît votre manette. Prendra effet à la prochaine session.</string>
|
||||
@@ -770,7 +754,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatique</string>
|
||||
<string name="drawer_relative_mouse_on">Activé</string>
|
||||
<string name="drawer_relative_mouse_off">Désactivé</string>
|
||||
<string name="drawer_direct_cursor">Curseur</string>
|
||||
<string name="drawer_pc_keyboard">Clavier PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Deuxième écran</string>
|
||||
@@ -1117,43 +1100,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB sur PC (en dernier recours)</string>
|
||||
<string name="wadb_only_if">À utiliser uniquement si le débogage sans fil n\'est pas disponible.</string>
|
||||
<string name="wadb_computer_group">3 · ADB sur PC (en dernier recours)</string>
|
||||
<string name="ctrl_osc_hint">Lors de l\'affichage des commandes à l\'écran en session</string>
|
||||
<string name="ctrl_color">Couleur</string>
|
||||
<string name="ctrl_color_hint">Teinte des boutons à l\'écran</string>
|
||||
<string name="ctrl_custom">Personnalisée</string>
|
||||
<string name="ctrl_opacity">Opacité</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Taille des boutons</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100 % correspond à la taille standard</string>
|
||||
<string name="ctrl_stick_click">Clic du joystick</string>
|
||||
<string name="ctrl_stick_click_hint">Double-cliquez et maintenez le joystick pour déclencher L3 ou R3</string>
|
||||
<string name="ctrl_adaptive">Joystick adaptatif</string>
|
||||
<string name="ctrl_rumble">Vibration du jeu</string>
|
||||
<string name="ctrl_dead_zone">Zone morte du stick</string>
|
||||
<string name="ctrl_steam_button">Bouton Steam</string>
|
||||
<string name="ctrl_qam_button">Bouton QAM</string>
|
||||
<string name="ctrl_keyboard_button">Bouton clavier</string>
|
||||
<string name="ctrl_select_steam">Appuyez sur Select pour ouvrir le menu Steam</string>
|
||||
<string name="ctrl_select_steam_hint">À la place de View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con comme manettes VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">Pendant que SteamVR tourne, chaque Joy-Con devient une main. Pointez-le devant vous et maintenez Home ou Capture pour le recentrer.</string>
|
||||
<string name="setup_animations">Animations</string>
|
||||
<string name="ctrl_adaptive_hint">Le joystick apparaîtra là où vous touchez et se masquera une fois relâché</string>
|
||||
<string name="ctrl_layout">Disposition</string>
|
||||
<string name="ctrl_layout_custom">Position personnalisée enregistrée</string>
|
||||
<string name="ctrl_layout_default">Adapté à cet écran</string>
|
||||
<string name="ctrl_edit">Modifier</string>
|
||||
<string name="ctrl_reset">Réinitialiser</string>
|
||||
<string name="ctrl_mapping">Mappage des boutons</string>
|
||||
<string name="ctrl_mapping_default">Chaque bouton envoie l\'entrée d\'origine correspondante</string>
|
||||
<string name="ctrl_mapping_count">%1$d/%2$d boutons remappés</string>
|
||||
<string name="ctrl_configure">Configurer</string>
|
||||
<string name="ctrl_reset_all">Réinitialiser la manette</string>
|
||||
<string name="ctrl_reset_all_hint">Restaurer tous les paramètres et dispositions de la manette</string>
|
||||
<string name="ctrl_mapping_lede">Définissez l\'entrée que chaque bouton à l\'écran envoie au jeu. « Masquer » supprimera ce bouton.</string>
|
||||
<string name="ctrl_onscreen_buttons">Boutons à l\'écran</string>
|
||||
<string name="ctrl_defaults">Valeurs par défaut</string>
|
||||
<string name="ctrl_reset_mapping">Réinitialiser le mappage</string>
|
||||
<string name="content_android_apps">Applications Android</string>
|
||||
<string name="content_apps_count">%1$d applications</string>
|
||||
<string name="content_no_android_apps">Aucune application Android lançable trouvée.</string>
|
||||
@@ -1274,15 +1237,8 @@
|
||||
<string name="deck_surface_stick">Joystick</string>
|
||||
<string name="deck_surface_trackpad">Pavé tactile</string>
|
||||
<string name="deck_surface_switch">Basculer entre joystick et pavé tactile</string>
|
||||
<string name="deck_more_controls">Plus de commandes Deck</string>
|
||||
<string name="deck_panels">PANNEAUX</string>
|
||||
<string name="deck_close">Fermer les commandes du deuxième écran</string>
|
||||
<string name="deck_open_steam_menu">Ouvrir le menu Steam</string>
|
||||
<string name="deck_left_upper">Gauche · Haut</string>
|
||||
<string name="deck_left_lower">Gauche · Bas</string>
|
||||
<string name="deck_right_upper">Droite · Haut</string>
|
||||
<string name="deck_right_lower">Droite · Bas</string>
|
||||
<string name="deck_click">Cliquer</string>
|
||||
<string name="deck_right_trackpad">Pavé tactile droit</string>
|
||||
<string name="deck_left_trackpad">Pavé tactile gauche</string>
|
||||
<string name="second_trackpad">Pavé tactile</string>
|
||||
@@ -1831,9 +1787,7 @@
|
||||
<string name="ctrl_target_left">Croix gauche</string>
|
||||
<string name="ctrl_target_right">Croix droite</string>
|
||||
<string name="ctrl_target_hidden">Masqué</string>
|
||||
<string name="ctrl_editor_drag">Faites glisser pour déplacer</string>
|
||||
<string name="ctrl_editor_snap">Aimanter</string>
|
||||
<string name="ctrl_editor_save">Enregistrer</string>
|
||||
<string name="second_mode_none">Aucun</string>
|
||||
<string name="second_mode_keyboard_trackpad">Clavier + pavé tactile</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2681,7 +2635,6 @@
|
||||
<string name="gog_achievements_unavailable">Succès indisponibles ; consultez les journaux de session</string>
|
||||
<string name="achievement_unlocked">Succès débloqué</string>
|
||||
<string name="touch_paste">Coller</string>
|
||||
<string name="touch_dpad">Pavé directionnel</string>
|
||||
<string name="touch_left_stick">Stick gauche</string>
|
||||
<string name="touch_right_stick">Stick droit</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3741,4 +3694,7 @@
|
||||
<string name="addons_none_found">Aucun addon trouvé</string>
|
||||
<string name="addons_unreachable">Impossible de joindre %1$s</string>
|
||||
<string name="addons_no_file">Aucun fichier pour cette version du jeu</string>
|
||||
<string name="input_reset_positions">Réinitialiser les positions</string>
|
||||
<string name="input_show_label">Afficher le libellé</string>
|
||||
<string name="input_layout_import_failed">Impossible d’importer cette disposition</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam टच (बीटा)</string>
|
||||
<string name="osc_style_next_session">Steam के टच कंट्रोल अगले Steam सेशन से शुरू होंगे</string>
|
||||
<string name="osc_steam_layout">Steam टच लेआउट</string>
|
||||
<string name="screen_keys">स्क्रीन कुंजियाँ</string>
|
||||
<string name="screen_keys_add">कुंजी जोड़ें</string>
|
||||
<string name="screen_key_text">टेक्स्ट</string>
|
||||
<string name="screen_key_size">आकार</string>
|
||||
<string name="screen_key_opacity">ओपैसिटी</string>
|
||||
<string name="screen_key_type_button">कुंजी</string>
|
||||
<string name="screen_key_shape_trigger">ट्रिगर</string>
|
||||
<string name="screen_key_toggle">टॉगल</string>
|
||||
<string name="screen_key_layout_export">निर्यात</string>
|
||||
<string name="screen_key_shape_pill">कैप्सूल</string>
|
||||
<string name="screen_key_shape_round">गोल</string>
|
||||
<string name="screen_key_shape_circle">वृत्त</string>
|
||||
<string name="screen_key_shape_rect">आयत</string>
|
||||
<string name="screen_key_bind">कुंजी</string>
|
||||
<string name="screen_key_image">छवि</string>
|
||||
<string name="screen_key_image_clear">हटाएं</string>
|
||||
<string name="screen_key_layout">लेआउट</string>
|
||||
<string name="screen_key_layout_save">सेव करें</string>
|
||||
<string name="osc_steam_layout_hint">इस गेम के टच कंट्रोल को घुमाएं, आकार बदलें या छिपाएं; Steam में सेव होता है</string>
|
||||
<string name="mode_controller">कंट्रोलर</string>
|
||||
<string name="mode_controller_hint">Steam आपके कंट्रोलर को किस तरह पहचानता है। अगले सेशन से लागू होता है।</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">स्वचालित</string>
|
||||
<string name="drawer_relative_mouse_on">चालू</string>
|
||||
<string name="drawer_relative_mouse_off">बंद</string>
|
||||
<string name="drawer_direct_cursor">कर्सर</string>
|
||||
<string name="drawer_pc_keyboard">पीसी कीबोर्ड</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">दूसरी स्क्रीन</string>
|
||||
@@ -1111,43 +1094,23 @@
|
||||
<string name="wadb_computer_last">3 · कंप्यूटर ADB (आख़िरी विकल्प)</string>
|
||||
<string name="wadb_only_if">सिर्फ़ तब जब वायरलेस डीबगिंग उपलब्ध न हो।</string>
|
||||
<string name="wadb_computer_group">3 · कंप्यूटर ADB (आख़िरी विकल्प)</string>
|
||||
<string name="ctrl_osc_hint">सेशन में टच कंट्रोल कब दिखते हैं</string>
|
||||
<string name="ctrl_color">रंग</string>
|
||||
<string name="ctrl_color_hint">ऑन-स्क्रीन बटन का रंग</string>
|
||||
<string name="ctrl_custom">कस्टम</string>
|
||||
<string name="ctrl_opacity">ओपैसिटी</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">बटन का आकार</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% मानक आकार है</string>
|
||||
<string name="ctrl_stick_click">स्टिक क्लिक</string>
|
||||
<string name="ctrl_stick_click_hint">L3 या R3 के लिए किसी स्टिक को डबल-टैप करके दबाए रखें</string>
|
||||
<string name="ctrl_adaptive">एडैप्टिव स्टिक</string>
|
||||
<string name="ctrl_rumble">गेम वाइब्रेशन</string>
|
||||
<string name="ctrl_dead_zone">स्टिक का डेड ज़ोन</string>
|
||||
<string name="ctrl_steam_button">Steam बटन</string>
|
||||
<string name="ctrl_qam_button">QAM बटन</string>
|
||||
<string name="ctrl_keyboard_button">कीबोर्ड बटन</string>
|
||||
<string name="ctrl_select_steam">Steam मेनू खोलने के लिए Select दबाएं</string>
|
||||
<string name="ctrl_select_steam_hint">View/Select के बदले।</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con को VR कंट्रोलर की तरह</string>
|
||||
<string name="ctrl_joycon_vr_hint">SteamVR चलते समय हर Joy-Con एक हाथ बन जाता है। उसे सामने की ओर करें और फिर से केंद्रित करने के लिए Home या Capture दबाए रखें।</string>
|
||||
<string name="setup_animations">एनिमेशन</string>
|
||||
<string name="ctrl_adaptive_hint">आप जहां टच करें वहां स्टिक दिखते हैं और छोड़ने पर छिप जाते हैं</string>
|
||||
<string name="ctrl_layout">लेआउट</string>
|
||||
<string name="ctrl_layout_custom">कस्टम पोज़िशन सेव हैं</string>
|
||||
<string name="ctrl_layout_default">इस स्क्रीन के हिसाब से फ़िट किया गया</string>
|
||||
<string name="ctrl_edit">संपादित करें</string>
|
||||
<string name="ctrl_reset">रीसेट करें</string>
|
||||
<string name="ctrl_mapping">बटन मैपिंग</string>
|
||||
<string name="ctrl_mapping_default">हर बटन अपना इनपुट भेजता है</string>
|
||||
<string name="ctrl_mapping_count">%2$d में से %1$d बटन रीमैप किए गए</string>
|
||||
<string name="ctrl_configure">कॉन्फ़िगर करें</string>
|
||||
<string name="ctrl_reset_all">कंट्रोलर रीसेट करें</string>
|
||||
<string name="ctrl_reset_all_hint">सभी कंट्रोलर सेटिंग और लेआउट वापस लाता है</string>
|
||||
<string name="ctrl_mapping_lede">हर ऑन-स्क्रीन बटन गेम को क्या भेजता है। Hidden बटन हटा देता है।</string>
|
||||
<string name="ctrl_onscreen_buttons">ऑन-स्क्रीन बटन</string>
|
||||
<string name="ctrl_defaults">डिफ़ॉल्ट</string>
|
||||
<string name="ctrl_reset_mapping">मैपिंग रीसेट करें</string>
|
||||
<string name="content_android_apps">Android ऐप</string>
|
||||
<string name="content_apps_count">%1$d ऐप</string>
|
||||
<string name="content_no_android_apps">लॉन्च करने लायक कोई Android ऐप नहीं मिला।</string>
|
||||
@@ -1267,15 +1230,8 @@
|
||||
<string name="deck_surface_stick">स्टिक</string>
|
||||
<string name="deck_surface_trackpad">ट्रैकपैड</string>
|
||||
<string name="deck_surface_switch">स्टिक और ट्रैकपैड के बीच बदलें</string>
|
||||
<string name="deck_more_controls">और Deck कंट्रोल</string>
|
||||
<string name="deck_panels">पैनल</string>
|
||||
<string name="deck_close">दूसरी स्क्रीन के कंट्रोल बंद करें</string>
|
||||
<string name="deck_open_steam_menu">Steam मेनू खोलें</string>
|
||||
<string name="deck_left_upper">बायां · ऊपर</string>
|
||||
<string name="deck_left_lower">बायां · नीचे</string>
|
||||
<string name="deck_right_upper">दायां · ऊपर</string>
|
||||
<string name="deck_right_lower">दायां · नीचे</string>
|
||||
<string name="deck_click">क्लिक</string>
|
||||
<string name="deck_right_trackpad">दायां ट्रैकपैड</string>
|
||||
<string name="deck_left_trackpad">बायां ट्रैकपैड</string>
|
||||
<string name="second_trackpad">ट्रैकपैड</string>
|
||||
@@ -1807,9 +1763,7 @@
|
||||
<string name="ctrl_target_left">D-pad बायां</string>
|
||||
<string name="ctrl_target_right">D-pad दायां</string>
|
||||
<string name="ctrl_target_hidden">छिपा हुआ</string>
|
||||
<string name="ctrl_editor_drag">ले जाने के लिए ड्रैग करें</string>
|
||||
<string name="ctrl_editor_snap">स्नैप</string>
|
||||
<string name="ctrl_editor_save">सेव करें</string>
|
||||
<string name="second_mode_none">कोई नहीं</string>
|
||||
<string name="second_mode_keyboard_trackpad">कीबोर्ड + ट्रैकपैड</string>
|
||||
<string name="second_mode_terminal">टर्मिनल</string>
|
||||
@@ -2657,7 +2611,6 @@
|
||||
<string name="gog_achievements_unavailable">उपलब्धियां उपलब्ध नहीं; सेशन लॉग देखें</string>
|
||||
<string name="achievement_unlocked">उपलब्धि अनलॉक हुई</string>
|
||||
<string name="touch_paste">पेस्ट करें</string>
|
||||
<string name="touch_dpad">डी-पैड</string>
|
||||
<string name="touch_left_stick">बायां स्टिक</string>
|
||||
<string name="touch_right_stick">दायां स्टिक</string>
|
||||
<string name="touch_menu">मेन्यू</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">कोई ऐडऑन नहीं मिला</string>
|
||||
<string name="addons_unreachable">%1$s तक नहीं पहुँच सके</string>
|
||||
<string name="addons_no_file">गेम के इस संस्करण के लिए कोई फ़ाइल नहीं है</string>
|
||||
<string name="input_reset_positions">स्थितियाँ रीसेट करें</string>
|
||||
<string name="input_show_label">लेबल दिखाएँ</string>
|
||||
<string name="input_layout_import_failed">यह लेआउट इम्पोर्ट नहीं किया जा सका</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam érintés (béta)</string>
|
||||
<string name="osc_style_next_session">A Steam érintésvezérlői a következő Steam-munkamenettől lépnek életbe</string>
|
||||
<string name="osc_steam_layout">Steam érintéskiosztás</string>
|
||||
<string name="screen_keys">Képernyőgombok</string>
|
||||
<string name="screen_keys_add">Gomb hozzáadása</string>
|
||||
<string name="screen_key_text">Szöveg</string>
|
||||
<string name="screen_key_size">Méret</string>
|
||||
<string name="screen_key_opacity">Átlátszatlanság</string>
|
||||
<string name="screen_key_type_button">Gomb</string>
|
||||
<string name="screen_key_shape_trigger">Ravasz</string>
|
||||
<string name="screen_key_toggle">Váltás</string>
|
||||
<string name="screen_key_layout_export">Exportálás</string>
|
||||
<string name="screen_key_shape_pill">Kapszula</string>
|
||||
<string name="screen_key_shape_round">Lekerekített</string>
|
||||
<string name="screen_key_shape_circle">Kör</string>
|
||||
<string name="screen_key_shape_rect">Téglalap</string>
|
||||
<string name="screen_key_bind">Billentyű</string>
|
||||
<string name="screen_key_image">Kép</string>
|
||||
<string name="screen_key_image_clear">Törlés</string>
|
||||
<string name="screen_key_layout">Elrendezés</string>
|
||||
<string name="screen_key_layout_save">Mentés</string>
|
||||
<string name="osc_steam_layout_hint">Mozgassa, méretezze vagy rejtse el a játék érintésvezérlőit; a Steamben mentve</string>
|
||||
<string name="mode_controller">Kontroller</string>
|
||||
<string name="mode_controller_hint">Hogyan látja a Steam a kontrollerét. A következő munkamenettől érvényes.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatikus</string>
|
||||
<string name="drawer_relative_mouse_on">Be</string>
|
||||
<string name="drawer_relative_mouse_off">Ki</string>
|
||||
<string name="drawer_direct_cursor">Kurzor</string>
|
||||
<string name="drawer_pc_keyboard">PC-billentyűzet</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Második képernyő</string>
|
||||
@@ -1111,43 +1094,23 @@
|
||||
<string name="wadb_computer_last">3 · Számítógépes ADB (végső megoldás)</string>
|
||||
<string name="wadb_only_if">Csak ha a vezeték nélküli hibakeresés nem elérhető.</string>
|
||||
<string name="wadb_computer_group">3 · Számítógépes ADB (végső megoldás)</string>
|
||||
<string name="ctrl_osc_hint">Mikor jelennek meg az érintésvezérlők egy munkamenetben</string>
|
||||
<string name="ctrl_color">Szín</string>
|
||||
<string name="ctrl_color_hint">A képernyőn megjelenő gombok árnyalata</string>
|
||||
<string name="ctrl_custom">Egyéni</string>
|
||||
<string name="ctrl_opacity">Átlátszatlanság</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Gombméret</string>
|
||||
<string name="ctrl_size_hint" formatted="false">A 100% az alapértelmezett méret</string>
|
||||
<string name="ctrl_stick_click">Kar kattintása</string>
|
||||
<string name="ctrl_stick_click_hint">Koppintson duplán, és tartsa lenyomva a kart az L3 vagy R3 érdekében</string>
|
||||
<string name="ctrl_adaptive">Adaptív karok</string>
|
||||
<string name="ctrl_rumble">Játékvibráció</string>
|
||||
<string name="ctrl_dead_zone">Kar holtzónája</string>
|
||||
<string name="ctrl_steam_button">Steam gomb</string>
|
||||
<string name="ctrl_qam_button">QAM gomb</string>
|
||||
<string name="ctrl_keyboard_button">Billentyűzet gomb</string>
|
||||
<string name="ctrl_select_steam">Nyomja meg a Select gombot a Steam-menü megnyitásához</string>
|
||||
<string name="ctrl_select_steam_hint">A View/Select helyett.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Conok VR-kontrollerként</string>
|
||||
<string name="ctrl_joycon_vr_hint">Amíg a SteamVR fut, minden Joy-Con egy kéz lesz. Irányítsa előre, és tartsa lenyomva a Home vagy a Capture gombot az újraközpontosításhoz.</string>
|
||||
<string name="setup_animations">Animációk</string>
|
||||
<string name="ctrl_adaptive_hint">A karok ott jelennek meg, ahol megérinti őket, és elengedéskor elrejtőznek</string>
|
||||
<string name="ctrl_layout">Elrendezés</string>
|
||||
<string name="ctrl_layout_custom">Egyéni pozíciók mentve</string>
|
||||
<string name="ctrl_layout_default">Ehhez a képernyőhöz illesztve</string>
|
||||
<string name="ctrl_edit">Szerkesztés</string>
|
||||
<string name="ctrl_reset">Visszaállítás</string>
|
||||
<string name="ctrl_mapping">Gombkiosztás</string>
|
||||
<string name="ctrl_mapping_default">Minden gomb a saját bemenetét küldi</string>
|
||||
<string name="ctrl_mapping_count">%1$d/%2$d gomb átkiosztva</string>
|
||||
<string name="ctrl_configure">Beállítás</string>
|
||||
<string name="ctrl_reset_all">Kontroller visszaállítása</string>
|
||||
<string name="ctrl_reset_all_hint">Visszaállítja az összes kontrollerbeállítást és az elrendezést</string>
|
||||
<string name="ctrl_mapping_lede">Mit küld a játéknak az egyes képernyőgombok. A Rejtett eltávolítja a gombot.</string>
|
||||
<string name="ctrl_onscreen_buttons">Képernyőgombok</string>
|
||||
<string name="ctrl_defaults">Alapértelmezések</string>
|
||||
<string name="ctrl_reset_mapping">Kiosztás visszaállítása</string>
|
||||
<string name="content_android_apps">Android-alkalmazások</string>
|
||||
<string name="content_apps_count">%1$d alkalmazás</string>
|
||||
<string name="content_no_android_apps">Nem található indítható Android-alkalmazás.</string>
|
||||
@@ -1267,15 +1230,8 @@
|
||||
<string name="deck_surface_stick">Kar</string>
|
||||
<string name="deck_surface_trackpad">Érintőpad</string>
|
||||
<string name="deck_surface_switch">Váltás a kar és az érintőpad között</string>
|
||||
<string name="deck_more_controls">További Deck-vezérlők</string>
|
||||
<string name="deck_panels">PANELEK</string>
|
||||
<string name="deck_close">Második képernyős vezérlők bezárása</string>
|
||||
<string name="deck_open_steam_menu">Steam-menü megnyitása</string>
|
||||
<string name="deck_left_upper">Bal · felső</string>
|
||||
<string name="deck_left_lower">Bal · alsó</string>
|
||||
<string name="deck_right_upper">Jobb · felső</string>
|
||||
<string name="deck_right_lower">Jobb · alsó</string>
|
||||
<string name="deck_click">Kattintás</string>
|
||||
<string name="deck_right_trackpad">Jobb érintőpad</string>
|
||||
<string name="deck_left_trackpad">Bal érintőpad</string>
|
||||
<string name="second_trackpad">Érintőpad</string>
|
||||
@@ -1807,9 +1763,7 @@
|
||||
<string name="ctrl_target_left">D-pad balra</string>
|
||||
<string name="ctrl_target_right">D-pad jobbra</string>
|
||||
<string name="ctrl_target_hidden">Rejtett</string>
|
||||
<string name="ctrl_editor_drag">Húzza a mozgatáshoz</string>
|
||||
<string name="ctrl_editor_snap">Rögzítés</string>
|
||||
<string name="ctrl_editor_save">Mentés</string>
|
||||
<string name="second_mode_none">Nincs</string>
|
||||
<string name="second_mode_keyboard_trackpad">Billentyűzet + érintőpad</string>
|
||||
<string name="second_mode_terminal">Terminál</string>
|
||||
@@ -2657,7 +2611,6 @@
|
||||
<string name="gog_achievements_unavailable">Eredmények nem elérhetők; nézd meg a munkamenet-naplókat</string>
|
||||
<string name="achievement_unlocked">Eredmény feloldva</string>
|
||||
<string name="touch_paste">Beillesztés</string>
|
||||
<string name="touch_dpad">Iránykereszt</string>
|
||||
<string name="touch_left_stick">Bal kar</string>
|
||||
<string name="touch_right_stick">Jobb kar</string>
|
||||
<string name="touch_menu">Menü</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Nem található kiegészítő</string>
|
||||
<string name="addons_unreachable">A(z) %1$s nem érhető el</string>
|
||||
<string name="addons_no_file">Nincs fájl ehhez a játékverzióhoz</string>
|
||||
<string name="input_reset_positions">Pozíciók visszaállítása</string>
|
||||
<string name="input_show_label">Címke megjelenítése</string>
|
||||
<string name="input_layout_import_failed">Ez az elrendezés nem importálható</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Sentuhan Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Kontrol sentuh Steam dimulai pada sesi Steam berikutnya</string>
|
||||
<string name="osc_steam_layout">Tata letak sentuh Steam</string>
|
||||
<string name="screen_keys">Tombol layar</string>
|
||||
<string name="screen_keys_add">Tambah tombol</string>
|
||||
<string name="screen_key_text">Teks</string>
|
||||
<string name="screen_key_size">Ukuran</string>
|
||||
<string name="screen_key_opacity">Opasitas</string>
|
||||
<string name="screen_key_type_button">Tombol</string>
|
||||
<string name="screen_key_shape_trigger">Pemicu</string>
|
||||
<string name="screen_key_toggle">Alih</string>
|
||||
<string name="screen_key_layout_export">Ekspor</string>
|
||||
<string name="screen_key_shape_pill">Kapsul</string>
|
||||
<string name="screen_key_shape_round">Membulat</string>
|
||||
<string name="screen_key_shape_circle">Lingkaran</string>
|
||||
<string name="screen_key_shape_rect">Persegi panjang</string>
|
||||
<string name="screen_key_bind">Tombol</string>
|
||||
<string name="screen_key_image">Gambar</string>
|
||||
<string name="screen_key_image_clear">Hapus</string>
|
||||
<string name="screen_key_layout">Tata letak</string>
|
||||
<string name="screen_key_layout_save">Simpan</string>
|
||||
<string name="osc_steam_layout_hint">Pindahkan, ubah ukuran, atau sembunyikan kontrol sentuh gim ini; disimpan ke Steam</string>
|
||||
<string name="mode_controller">Pengontrol</string>
|
||||
<string name="mode_controller_hint">Cara Steam mendeteksi pengontrol Anda. Berlaku pada sesi berikutnya.</string>
|
||||
@@ -766,7 +750,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Otomatis</string>
|
||||
<string name="drawer_relative_mouse_on">Aktif</string>
|
||||
<string name="drawer_relative_mouse_off">Nonaktif</string>
|
||||
<string name="drawer_direct_cursor">Kursor</string>
|
||||
<string name="drawer_pc_keyboard">Keyboard PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Layar kedua</string>
|
||||
@@ -1105,43 +1088,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB komputer (upaya terakhir)</string>
|
||||
<string name="wadb_only_if">Hanya jika Debugging nirkabel tidak tersedia.</string>
|
||||
<string name="wadb_computer_group">3 · ADB komputer (upaya terakhir)</string>
|
||||
<string name="ctrl_osc_hint">Saat kontrol sentuh muncul dalam sesi</string>
|
||||
<string name="ctrl_color">Warna</string>
|
||||
<string name="ctrl_color_hint">Warna tombol di layar</string>
|
||||
<string name="ctrl_custom">Khusus</string>
|
||||
<string name="ctrl_opacity">Opasitas</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Ukuran tombol</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% adalah ukuran standar</string>
|
||||
<string name="ctrl_stick_click">Klik stik</string>
|
||||
<string name="ctrl_stick_click_hint">Ketuk dua kali dan tahan sebuah stik untuk L3 atau R3</string>
|
||||
<string name="ctrl_adaptive">Stik adaptif</string>
|
||||
<string name="ctrl_rumble">Getaran gim</string>
|
||||
<string name="ctrl_dead_zone">Zona mati stik</string>
|
||||
<string name="ctrl_steam_button">Tombol Steam</string>
|
||||
<string name="ctrl_qam_button">Tombol QAM</string>
|
||||
<string name="ctrl_keyboard_button">Tombol keyboard</string>
|
||||
<string name="ctrl_select_steam">Tekan Select untuk membuka menu Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Bukan View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con sebagai pengontrol VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">Saat SteamVR berjalan, setiap Joy-Con menjadi tangan. Arahkan ke depan lalu tahan Home atau Capture untuk memusatkannya kembali.</string>
|
||||
<string name="setup_animations">Animasi</string>
|
||||
<string name="ctrl_adaptive_hint">Stik muncul di tempat Anda menyentuh dan tersembunyi saat dilepas</string>
|
||||
<string name="ctrl_layout">Tata letak</string>
|
||||
<string name="ctrl_layout_custom">Posisi khusus disimpan</string>
|
||||
<string name="ctrl_layout_default">Disesuaikan dengan layar ini</string>
|
||||
<string name="ctrl_edit">Edit</string>
|
||||
<string name="ctrl_reset">Reset</string>
|
||||
<string name="ctrl_mapping">Pemetaan tombol</string>
|
||||
<string name="ctrl_mapping_default">Setiap tombol mengirim input-nya sendiri</string>
|
||||
<string name="ctrl_mapping_count">%1$d dari %2$d tombol dipetakan ulang</string>
|
||||
<string name="ctrl_configure">Konfigurasi</string>
|
||||
<string name="ctrl_reset_all">Reset pengontrol</string>
|
||||
<string name="ctrl_reset_all_hint">Mengembalikan semua setelan pengontrol dan tata letak</string>
|
||||
<string name="ctrl_mapping_lede">Apa yang dikirim setiap tombol di layar ke gim. Tersembunyi menghapus tombol tersebut.</string>
|
||||
<string name="ctrl_onscreen_buttons">Tombol di layar</string>
|
||||
<string name="ctrl_defaults">Default</string>
|
||||
<string name="ctrl_reset_mapping">Reset pemetaan</string>
|
||||
<string name="content_android_apps">Aplikasi Android</string>
|
||||
<string name="content_apps_count">%1$d aplikasi</string>
|
||||
<string name="content_no_android_apps">Tidak ada aplikasi Android yang dapat dijalankan.</string>
|
||||
@@ -1260,15 +1223,8 @@
|
||||
<string name="deck_surface_stick">Stik</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Beralih antara stik dan trackpad</string>
|
||||
<string name="deck_more_controls">Kontrol Deck lainnya</string>
|
||||
<string name="deck_panels">PANEL</string>
|
||||
<string name="deck_close">Tutup kontrol layar kedua</string>
|
||||
<string name="deck_open_steam_menu">Buka menu Steam</string>
|
||||
<string name="deck_left_upper">Kiri · atas</string>
|
||||
<string name="deck_left_lower">Kiri · bawah</string>
|
||||
<string name="deck_right_upper">Kanan · atas</string>
|
||||
<string name="deck_right_lower">Kanan · bawah</string>
|
||||
<string name="deck_click">Klik</string>
|
||||
<string name="deck_right_trackpad">Trackpad kanan</string>
|
||||
<string name="deck_left_trackpad">Trackpad kiri</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1783,9 +1739,7 @@
|
||||
<string name="ctrl_target_left">D-pad kiri</string>
|
||||
<string name="ctrl_target_right">D-pad kanan</string>
|
||||
<string name="ctrl_target_hidden">Tersembunyi</string>
|
||||
<string name="ctrl_editor_drag">Seret untuk memindahkan</string>
|
||||
<string name="ctrl_editor_snap">Ratakan</string>
|
||||
<string name="ctrl_editor_save">Simpan</string>
|
||||
<string name="second_mode_none">Tidak ada</string>
|
||||
<string name="second_mode_keyboard_trackpad">Keyboard + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2630,7 +2584,6 @@
|
||||
<string name="gog_achievements_unavailable">Pencapaian tidak tersedia; periksa log sesi</string>
|
||||
<string name="achievement_unlocked">Pencapaian terbuka</string>
|
||||
<string name="touch_paste">Tempel</string>
|
||||
<string name="touch_dpad">Tombol arah</string>
|
||||
<string name="touch_left_stick">Stik kiri</string>
|
||||
<string name="touch_right_stick">Stik kanan</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3672,4 +3625,7 @@
|
||||
<string name="addons_none_found">Tidak ada addon ditemukan</string>
|
||||
<string name="addons_unreachable">Tidak dapat menjangkau %1$s</string>
|
||||
<string name="addons_no_file">Tidak ada file untuk versi game ini</string>
|
||||
<string name="input_reset_positions">Atur ulang posisi</string>
|
||||
<string name="input_show_label">Tampilkan label</string>
|
||||
<string name="input_layout_import_failed">Tata letak ini tidak dapat diimpor</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Touch di Steam (beta)</string>
|
||||
<string name="osc_style_next_session">I controlli touch di Steam partono dalla prossima sessione Steam</string>
|
||||
<string name="osc_steam_layout">Layout touch di Steam</string>
|
||||
<string name="screen_keys">Tasti a schermo</string>
|
||||
<string name="screen_keys_add">Aggiungi tasto</string>
|
||||
<string name="screen_key_text">Testo</string>
|
||||
<string name="screen_key_size">Dimensione</string>
|
||||
<string name="screen_key_opacity">Opacità</string>
|
||||
<string name="screen_key_type_button">Tasto</string>
|
||||
<string name="screen_key_shape_trigger">Grilletto</string>
|
||||
<string name="screen_key_toggle">Attiva</string>
|
||||
<string name="screen_key_layout_export">Esporta</string>
|
||||
<string name="screen_key_shape_pill">Capsula</string>
|
||||
<string name="screen_key_shape_round">Arrotondato</string>
|
||||
<string name="screen_key_shape_circle">Cerchio</string>
|
||||
<string name="screen_key_shape_rect">Rettangolo</string>
|
||||
<string name="screen_key_bind">Tasto</string>
|
||||
<string name="screen_key_image">Immagine</string>
|
||||
<string name="screen_key_image_clear">Cancella</string>
|
||||
<string name="screen_key_layout">Layout</string>
|
||||
<string name="screen_key_layout_save">Salva</string>
|
||||
<string name="osc_steam_layout_hint">Sposta, ridimensiona o nascondi i controlli touch di questo gioco; vengono salvati su Steam</string>
|
||||
<string name="mode_controller">Controller</string>
|
||||
<string name="mode_controller_hint">Come Steam vede il tuo controller. Si applica dalla prossima sessione.</string>
|
||||
@@ -770,7 +754,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatico</string>
|
||||
<string name="drawer_relative_mouse_on">Attivo</string>
|
||||
<string name="drawer_relative_mouse_off">Disattivato</string>
|
||||
<string name="drawer_direct_cursor">Cursore</string>
|
||||
<string name="drawer_pc_keyboard">Tastiera PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Secondo schermo</string>
|
||||
@@ -1109,43 +1092,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB da computer (ultima risorsa)</string>
|
||||
<string name="wadb_only_if">Solo se il Debug wireless non è disponibile.</string>
|
||||
<string name="wadb_computer_group">3 · ADB da computer (ultima risorsa)</string>
|
||||
<string name="ctrl_osc_hint">Quando i controlli touch appaiono in una sessione</string>
|
||||
<string name="ctrl_color">Colore</string>
|
||||
<string name="ctrl_color_hint">Tonalità dei tasti sullo schermo</string>
|
||||
<string name="ctrl_custom">Personalizzato</string>
|
||||
<string name="ctrl_opacity">Opacità</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Dimensione dei tasti</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% è la dimensione standard</string>
|
||||
<string name="ctrl_stick_click">Clic levetta</string>
|
||||
<string name="ctrl_stick_click_hint">Tocca due volte e tieni premuta una levetta per L3 o R3</string>
|
||||
<string name="ctrl_adaptive">Levette adattive</string>
|
||||
<string name="ctrl_rumble">Vibrazione di gioco</string>
|
||||
<string name="ctrl_dead_zone">Zona morta dello stick</string>
|
||||
<string name="ctrl_steam_button">Tasto Steam</string>
|
||||
<string name="ctrl_qam_button">Tasto QAM</string>
|
||||
<string name="ctrl_keyboard_button">Tasto tastiera</string>
|
||||
<string name="ctrl_select_steam">Premi Select per aprire il menu Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Invece di View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con come controller VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">Mentre SteamVR è in esecuzione, ogni Joy-Con diventa una mano. Puntalo in avanti e tieni premuto Home o Capture per ricentrarlo.</string>
|
||||
<string name="setup_animations">Animazioni</string>
|
||||
<string name="ctrl_adaptive_hint">Le levette appaiono dove tocchi e si nascondono al rilascio</string>
|
||||
<string name="ctrl_layout">Layout</string>
|
||||
<string name="ctrl_layout_custom">Posizioni personalizzate salvate</string>
|
||||
<string name="ctrl_layout_default">Adattato a questo schermo</string>
|
||||
<string name="ctrl_edit">Modifica</string>
|
||||
<string name="ctrl_reset">Ripristina</string>
|
||||
<string name="ctrl_mapping">Mappatura dei tasti</string>
|
||||
<string name="ctrl_mapping_default">Ogni tasto invia il proprio input</string>
|
||||
<string name="ctrl_mapping_count">%1$d di %2$d tasti rimappati</string>
|
||||
<string name="ctrl_configure">Configura</string>
|
||||
<string name="ctrl_reset_all">Ripristina controller</string>
|
||||
<string name="ctrl_reset_all_hint">Ripristina tutte le impostazioni del controller e il layout</string>
|
||||
<string name="ctrl_mapping_lede">Cosa invia al gioco ciascun tasto sullo schermo. Nascosto rimuove il tasto.</string>
|
||||
<string name="ctrl_onscreen_buttons">Tasti sullo schermo</string>
|
||||
<string name="ctrl_defaults">Predefiniti</string>
|
||||
<string name="ctrl_reset_mapping">Ripristina mappatura</string>
|
||||
<string name="content_android_apps">App Android</string>
|
||||
<string name="content_apps_count">%1$d app</string>
|
||||
<string name="content_no_android_apps">Nessuna app Android avviabile trovata.</string>
|
||||
@@ -1266,15 +1229,8 @@
|
||||
<string name="deck_surface_stick">Levetta</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Alterna tra levetta e trackpad</string>
|
||||
<string name="deck_more_controls">Altri controlli Deck</string>
|
||||
<string name="deck_panels">PANNELLI</string>
|
||||
<string name="deck_close">Chiudi i controlli sul secondo schermo</string>
|
||||
<string name="deck_open_steam_menu">Apri il menu Steam</string>
|
||||
<string name="deck_left_upper">Sinistra · in alto</string>
|
||||
<string name="deck_left_lower">Sinistra · in basso</string>
|
||||
<string name="deck_right_upper">Destra · in alto</string>
|
||||
<string name="deck_right_lower">Destra · in basso</string>
|
||||
<string name="deck_click">Clic</string>
|
||||
<string name="deck_right_trackpad">Trackpad destro</string>
|
||||
<string name="deck_left_trackpad">Trackpad sinistro</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1823,9 +1779,7 @@
|
||||
<string name="ctrl_target_left">Croce sinistra</string>
|
||||
<string name="ctrl_target_right">Croce destra</string>
|
||||
<string name="ctrl_target_hidden">Nascosto</string>
|
||||
<string name="ctrl_editor_drag">Trascina per spostare</string>
|
||||
<string name="ctrl_editor_snap">Aggancia</string>
|
||||
<string name="ctrl_editor_save">Salva</string>
|
||||
<string name="second_mode_none">Nessuno</string>
|
||||
<string name="second_mode_keyboard_trackpad">Tastiera + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminale</string>
|
||||
@@ -2673,7 +2627,6 @@
|
||||
<string name="gog_achievements_unavailable">Obiettivi non disponibili; controlla i log della sessione</string>
|
||||
<string name="achievement_unlocked">Obiettivo sbloccato</string>
|
||||
<string name="touch_paste">Incolla</string>
|
||||
<string name="touch_dpad">Croce direzionale</string>
|
||||
<string name="touch_left_stick">Stick sinistro</string>
|
||||
<string name="touch_right_stick">Stick destro</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3741,4 +3694,7 @@
|
||||
<string name="addons_none_found">Nessun addon trovato</string>
|
||||
<string name="addons_unreachable">Impossibile raggiungere %1$s</string>
|
||||
<string name="addons_no_file">Nessun file per questa versione del gioco</string>
|
||||
<string name="input_reset_positions">Ripristina posizioni</string>
|
||||
<string name="input_show_label">Mostra etichetta</string>
|
||||
<string name="input_layout_import_failed">Impossibile importare questo layout</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steamタッチ(ベータ版)</string>
|
||||
<string name="osc_style_next_session">Steamのタッチコントロールは次回のSteamセッションから有効になります</string>
|
||||
<string name="osc_steam_layout">Steamタッチのレイアウト</string>
|
||||
<string name="screen_keys">画面のキー</string>
|
||||
<string name="screen_keys_add">キーを追加</string>
|
||||
<string name="screen_key_text">テキスト</string>
|
||||
<string name="screen_key_size">サイズ</string>
|
||||
<string name="screen_key_opacity">不透明度</string>
|
||||
<string name="screen_key_type_button">キー</string>
|
||||
<string name="screen_key_shape_trigger">トリガー</string>
|
||||
<string name="screen_key_toggle">トグル</string>
|
||||
<string name="screen_key_layout_export">エクスポート</string>
|
||||
<string name="screen_key_shape_pill">カプセル</string>
|
||||
<string name="screen_key_shape_round">角丸</string>
|
||||
<string name="screen_key_shape_circle">円</string>
|
||||
<string name="screen_key_shape_rect">四角</string>
|
||||
<string name="screen_key_bind">キー</string>
|
||||
<string name="screen_key_image">画像</string>
|
||||
<string name="screen_key_image_clear">クリア</string>
|
||||
<string name="screen_key_layout">レイアウト</string>
|
||||
<string name="screen_key_layout_save">保存</string>
|
||||
<string name="osc_steam_layout_hint">このゲームのタッチコントロールを移動、サイズ変更、非表示にします。Steamに保存されます</string>
|
||||
<string name="mode_controller">コントローラー</string>
|
||||
<string name="mode_controller_hint">Steamがコントローラーを認識する方法。次回のセッションで有効になります。</string>
|
||||
@@ -766,7 +750,6 @@
|
||||
<string name="drawer_relative_mouse_auto">自動</string>
|
||||
<string name="drawer_relative_mouse_on">オン</string>
|
||||
<string name="drawer_relative_mouse_off">オフ</string>
|
||||
<string name="drawer_direct_cursor">カーソル</string>
|
||||
<string name="drawer_pc_keyboard">PCキーボード</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">セカンドスクリーン</string>
|
||||
@@ -1105,43 +1088,23 @@
|
||||
<string name="wadb_computer_last">3 · PC ADB(最終手段)</string>
|
||||
<string name="wadb_only_if">ワイヤレスデバッグが利用できない場合にのみ使用してください。</string>
|
||||
<string name="wadb_computer_group">3 · PC ADB(最終手段)</string>
|
||||
<string name="ctrl_osc_hint">セッション中に画面コントローラーを表示する場合</string>
|
||||
<string name="ctrl_color">色</string>
|
||||
<string name="ctrl_color_hint">画面ボタンの色調</string>
|
||||
<string name="ctrl_custom">カスタム</string>
|
||||
<string name="ctrl_opacity">不透明度</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">ボタンのサイズ</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% が標準サイズです</string>
|
||||
<string name="ctrl_stick_click">スティッククリック</string>
|
||||
<string name="ctrl_stick_click_hint">スティックをダブルタップして長押しすると、L3またはR3がトリガーされます</string>
|
||||
<string name="ctrl_adaptive">アダプティブスティック</string>
|
||||
<string name="ctrl_rumble">ゲームの振動</string>
|
||||
<string name="ctrl_dead_zone">スティックのデッドゾーン</string>
|
||||
<string name="ctrl_steam_button">Steamボタン</string>
|
||||
<string name="ctrl_qam_button">QAMボタン</string>
|
||||
<string name="ctrl_keyboard_button">キーボードボタン</string>
|
||||
<string name="ctrl_select_steam">Selectを押してSteamメニューを開く</string>
|
||||
<string name="ctrl_select_steam_hint">View/Selectの代わり。</string>
|
||||
<string name="ctrl_joycon_vr">Joy-ConをVRコントローラーとして使う</string>
|
||||
<string name="ctrl_joycon_vr_hint">SteamVRの実行中は各Joy-Conが手になります。前に向けてHOMEボタンかキャプチャーボタンを長押しすると、向きを合わせ直します。</string>
|
||||
<string name="setup_animations">アニメーション</string>
|
||||
<string name="ctrl_adaptive_hint">スティックは触れた位置に表示され、離すと非表示になります</string>
|
||||
<string name="ctrl_layout">レイアウト</string>
|
||||
<string name="ctrl_layout_custom">カスタム位置を保存済み</string>
|
||||
<string name="ctrl_layout_default">この画面に最適化済み</string>
|
||||
<string name="ctrl_edit">編集</string>
|
||||
<string name="ctrl_reset">リセット</string>
|
||||
<string name="ctrl_mapping">キーマッピング</string>
|
||||
<string name="ctrl_mapping_default">各ボタンは対応する元の入力を送信します</string>
|
||||
<string name="ctrl_mapping_count">%1$d/%2$d 個のボタンを再マッピング済み</string>
|
||||
<string name="ctrl_configure">設定</string>
|
||||
<string name="ctrl_reset_all">コントローラーをリセット</string>
|
||||
<string name="ctrl_reset_all_hint">すべてのコントローラー設定とレイアウトを復元</string>
|
||||
<string name="ctrl_mapping_lede">各画面ボタンがゲームに送信する入力を設定します。「非表示」にするとそのボタンが削除されます。</string>
|
||||
<string name="ctrl_onscreen_buttons">画面ボタン</string>
|
||||
<string name="ctrl_defaults">デフォルト</string>
|
||||
<string name="ctrl_reset_mapping">マッピングをリセット</string>
|
||||
<string name="content_android_apps">Androidアプリ</string>
|
||||
<string name="content_apps_count">%1$d 個のアプリ</string>
|
||||
<string name="content_no_android_apps">起動可能なAndroidアプリが見つかりませんでした。</string>
|
||||
@@ -1260,15 +1223,8 @@
|
||||
<string name="deck_surface_stick">スティック</string>
|
||||
<string name="deck_surface_trackpad">トラックパッド</string>
|
||||
<string name="deck_surface_switch">スティックとトラックパッドを切り替え</string>
|
||||
<string name="deck_more_controls">その他のDeckコントロール</string>
|
||||
<string name="deck_panels">パネル</string>
|
||||
<string name="deck_close">セカンドスクリーンコントロールを閉じる</string>
|
||||
<string name="deck_open_steam_menu">Steamメニューを開く</string>
|
||||
<string name="deck_left_upper">左 · 上</string>
|
||||
<string name="deck_left_lower">左 · 下</string>
|
||||
<string name="deck_right_upper">右 · 上</string>
|
||||
<string name="deck_right_lower">右 · 下</string>
|
||||
<string name="deck_click">クリック</string>
|
||||
<string name="deck_right_trackpad">右トラックパッド</string>
|
||||
<string name="deck_left_trackpad">左トラックパッド</string>
|
||||
<string name="second_trackpad">トラックパッド</string>
|
||||
@@ -1783,9 +1739,7 @@
|
||||
<string name="ctrl_target_left">十字キー左</string>
|
||||
<string name="ctrl_target_right">十字キー右</string>
|
||||
<string name="ctrl_target_hidden">非表示</string>
|
||||
<string name="ctrl_editor_drag">ドラッグして移動</string>
|
||||
<string name="ctrl_editor_snap">スナップ</string>
|
||||
<string name="ctrl_editor_save">保存</string>
|
||||
<string name="second_mode_none">なし</string>
|
||||
<string name="second_mode_keyboard_trackpad">キーボード + トラックパッド</string>
|
||||
<string name="second_mode_terminal">ターミナル</string>
|
||||
@@ -2630,7 +2584,6 @@
|
||||
<string name="gog_achievements_unavailable">実績を利用できません。セッションログを確認してください</string>
|
||||
<string name="achievement_unlocked">実績を解除しました</string>
|
||||
<string name="touch_paste">貼り付け</string>
|
||||
<string name="touch_dpad">十字キー</string>
|
||||
<string name="touch_left_stick">左スティック</string>
|
||||
<string name="touch_right_stick">右スティック</string>
|
||||
<string name="touch_menu">メニュー</string>
|
||||
@@ -3672,4 +3625,7 @@
|
||||
<string name="addons_none_found">アドオンが見つかりません</string>
|
||||
<string name="addons_unreachable">%1$s に接続できませんでした</string>
|
||||
<string name="addons_no_file">このゲームバージョン用のファイルがありません</string>
|
||||
<string name="input_reset_positions">位置をリセット</string>
|
||||
<string name="input_show_label">ラベルを表示</string>
|
||||
<string name="input_layout_import_failed">このレイアウトをインポートできませんでした</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam 터치(베타)</string>
|
||||
<string name="osc_style_next_session">Steam 터치 컨트롤은 다음 Steam 세션부터 적용됩니다</string>
|
||||
<string name="osc_steam_layout">Steam 터치 레이아웃</string>
|
||||
<string name="screen_keys">화면 키</string>
|
||||
<string name="screen_keys_add">키 추가</string>
|
||||
<string name="screen_key_text">텍스트</string>
|
||||
<string name="screen_key_size">크기</string>
|
||||
<string name="screen_key_opacity">불투명도</string>
|
||||
<string name="screen_key_type_button">키</string>
|
||||
<string name="screen_key_shape_trigger">트리거</string>
|
||||
<string name="screen_key_toggle">토글</string>
|
||||
<string name="screen_key_layout_export">내보내기</string>
|
||||
<string name="screen_key_shape_pill">캡슐</string>
|
||||
<string name="screen_key_shape_round">둥근 모서리</string>
|
||||
<string name="screen_key_shape_circle">원</string>
|
||||
<string name="screen_key_shape_rect">사각형</string>
|
||||
<string name="screen_key_bind">키</string>
|
||||
<string name="screen_key_image">이미지</string>
|
||||
<string name="screen_key_image_clear">지우기</string>
|
||||
<string name="screen_key_layout">레이아웃</string>
|
||||
<string name="screen_key_layout_save">저장</string>
|
||||
<string name="osc_steam_layout_hint">이 게임의 터치 컨트롤을 옮기거나 크기를 바꾸거나 숨깁니다. Steam에 저장됩니다</string>
|
||||
<string name="mode_controller">컨트롤러</string>
|
||||
<string name="mode_controller_hint">Steam이 컨트롤러를 인식하는 방식입니다. 다음 세션에 적용됩니다.</string>
|
||||
@@ -766,7 +750,6 @@
|
||||
<string name="drawer_relative_mouse_auto">자동</string>
|
||||
<string name="drawer_relative_mouse_on">켜기</string>
|
||||
<string name="drawer_relative_mouse_off">끄기</string>
|
||||
<string name="drawer_direct_cursor">커서</string>
|
||||
<string name="drawer_pc_keyboard">PC 키보드</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">보조 화면</string>
|
||||
@@ -1105,43 +1088,23 @@
|
||||
<string name="wadb_computer_last">3 · PC ADB(최후의 수단)</string>
|
||||
<string name="wadb_only_if">무선 디버깅을 사용할 수 없을 때만 사용하세요.</string>
|
||||
<string name="wadb_computer_group">3 · PC ADB(최후의 수단)</string>
|
||||
<string name="ctrl_osc_hint">세션에서 화면 컨트롤을 표시할 때</string>
|
||||
<string name="ctrl_color">색상</string>
|
||||
<string name="ctrl_color_hint">화면 버튼의 색조</string>
|
||||
<string name="ctrl_custom">사용자 정의</string>
|
||||
<string name="ctrl_opacity">불투명도</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">버튼 크기</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100%가 표준 크기입니다</string>
|
||||
<string name="ctrl_stick_click">스틱 클릭</string>
|
||||
<string name="ctrl_stick_click_hint">스틱을 두 번 탭한 후 길게 누르면 L3 또는 R3이 입력됩니다</string>
|
||||
<string name="ctrl_adaptive">적응형 스틱</string>
|
||||
<string name="ctrl_rumble">게임 진동</string>
|
||||
<string name="ctrl_dead_zone">스틱 데드존</string>
|
||||
<string name="ctrl_steam_button">Steam 버튼</string>
|
||||
<string name="ctrl_qam_button">QAM 버튼</string>
|
||||
<string name="ctrl_keyboard_button">키보드 버튼</string>
|
||||
<string name="ctrl_select_steam">Select를 눌러 Steam 메뉴 열기</string>
|
||||
<string name="ctrl_select_steam_hint">View/Select 대신.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con을 VR 컨트롤러로 사용</string>
|
||||
<string name="ctrl_joycon_vr_hint">SteamVR이 실행되는 동안 각 Joy-Con이 손이 됩니다. 앞을 향하게 한 채 HOME 또는 캡처 버튼을 길게 누르면 다시 가운데로 맞춥니다.</string>
|
||||
<string name="setup_animations">애니메이션</string>
|
||||
<string name="ctrl_adaptive_hint">스틱이 터치한 위치에 나타나며 손을 떼면 숨겨집니다</string>
|
||||
<string name="ctrl_layout">레이아웃</string>
|
||||
<string name="ctrl_layout_custom">사용자 정의 위치 저장됨</string>
|
||||
<string name="ctrl_layout_default">이 화면에 맞게 조정됨</string>
|
||||
<string name="ctrl_edit">편집</string>
|
||||
<string name="ctrl_reset">초기화</string>
|
||||
<string name="ctrl_mapping">키 매핑</string>
|
||||
<string name="ctrl_mapping_default">각 버튼은 해당하는 원본 입력을 전송합니다</string>
|
||||
<string name="ctrl_mapping_count">%1$d/%2$d개 버튼 다시 매핑됨</string>
|
||||
<string name="ctrl_configure">구성</string>
|
||||
<string name="ctrl_reset_all">컨트롤러 초기화</string>
|
||||
<string name="ctrl_reset_all_hint">모든 컨트롤러 설정 및 레이아웃 복원</string>
|
||||
<string name="ctrl_mapping_lede">각 화면 버튼이 게임에 전송할 입력을 설정합니다. \"숨기기\"를 선택하면 해당 버튼이 제거됩니다.</string>
|
||||
<string name="ctrl_onscreen_buttons">화면 버튼</string>
|
||||
<string name="ctrl_defaults">기본값</string>
|
||||
<string name="ctrl_reset_mapping">매핑 초기화</string>
|
||||
<string name="content_android_apps">Android 앱</string>
|
||||
<string name="content_apps_count">%1$d개 앱</string>
|
||||
<string name="content_no_android_apps">실행 가능한 Android 앱을 찾을 수 없습니다.</string>
|
||||
@@ -1260,15 +1223,8 @@
|
||||
<string name="deck_surface_stick">스틱</string>
|
||||
<string name="deck_surface_trackpad">터치패드</string>
|
||||
<string name="deck_surface_switch">스틱과 터치패드 간 전환</string>
|
||||
<string name="deck_more_controls">Deck 컨트롤 더 보기</string>
|
||||
<string name="deck_panels">패널</string>
|
||||
<string name="deck_close">보조 화면 컨트롤 닫기</string>
|
||||
<string name="deck_open_steam_menu">Steam 메뉴 열기</string>
|
||||
<string name="deck_left_upper">왼쪽 · 위</string>
|
||||
<string name="deck_left_lower">왼쪽 · 아래</string>
|
||||
<string name="deck_right_upper">오른쪽 · 위</string>
|
||||
<string name="deck_right_lower">오른쪽 · 아래</string>
|
||||
<string name="deck_click">클릭</string>
|
||||
<string name="deck_right_trackpad">오른쪽 터치패드</string>
|
||||
<string name="deck_left_trackpad">왼쪽 터치패드</string>
|
||||
<string name="second_trackpad">터치패드</string>
|
||||
@@ -1783,9 +1739,7 @@
|
||||
<string name="ctrl_target_left">방향 패드 왼쪽</string>
|
||||
<string name="ctrl_target_right">방향 패드 오른쪽</string>
|
||||
<string name="ctrl_target_hidden">숨김</string>
|
||||
<string name="ctrl_editor_drag">드래그하여 이동</string>
|
||||
<string name="ctrl_editor_snap">맞춤</string>
|
||||
<string name="ctrl_editor_save">저장</string>
|
||||
<string name="second_mode_none">없음</string>
|
||||
<string name="second_mode_keyboard_trackpad">키보드 + 터치패드</string>
|
||||
<string name="second_mode_terminal">터미널</string>
|
||||
@@ -2630,7 +2584,6 @@
|
||||
<string name="gog_achievements_unavailable">도전 과제를 사용할 수 없습니다. 세션 로그를 확인하세요</string>
|
||||
<string name="achievement_unlocked">도전 과제 잠금 해제됨</string>
|
||||
<string name="touch_paste">붙여넣기</string>
|
||||
<string name="touch_dpad">방향패드</string>
|
||||
<string name="touch_left_stick">왼쪽 스틱</string>
|
||||
<string name="touch_right_stick">오른쪽 스틱</string>
|
||||
<string name="touch_menu">메뉴</string>
|
||||
@@ -3672,4 +3625,7 @@
|
||||
<string name="addons_none_found">애드온을 찾을 수 없음</string>
|
||||
<string name="addons_unreachable">%1$s에 연결할 수 없습니다</string>
|
||||
<string name="addons_no_file">이 게임 버전용 파일이 없습니다</string>
|
||||
<string name="input_reset_positions">위치 초기화</string>
|
||||
<string name="input_show_label">라벨 표시</string>
|
||||
<string name="input_layout_import_failed">이 레이아웃을 가져올 수 없습니다</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Sentuhan Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Kawalan sentuh Steam bermula pada sesi Steam seterusnya</string>
|
||||
<string name="osc_steam_layout">Susun atur sentuh Steam</string>
|
||||
<string name="screen_keys">Kekunci skrin</string>
|
||||
<string name="screen_keys_add">Tambah kekunci</string>
|
||||
<string name="screen_key_text">Teks</string>
|
||||
<string name="screen_key_size">Saiz</string>
|
||||
<string name="screen_key_opacity">Kelegapan</string>
|
||||
<string name="screen_key_type_button">Kekunci</string>
|
||||
<string name="screen_key_shape_trigger">Pencetus</string>
|
||||
<string name="screen_key_toggle">Togol</string>
|
||||
<string name="screen_key_layout_export">Eksport</string>
|
||||
<string name="screen_key_shape_pill">Kapsul</string>
|
||||
<string name="screen_key_shape_round">Bulat</string>
|
||||
<string name="screen_key_shape_circle">Bulatan</string>
|
||||
<string name="screen_key_shape_rect">Segi empat</string>
|
||||
<string name="screen_key_bind">Kekunci</string>
|
||||
<string name="screen_key_image">Imej</string>
|
||||
<string name="screen_key_image_clear">Kosongkan</string>
|
||||
<string name="screen_key_layout">Susun atur</string>
|
||||
<string name="screen_key_layout_save">Simpan</string>
|
||||
<string name="osc_steam_layout_hint">Gerakkan, ubah saiz atau sembunyikan kawalan sentuh permainan ini; disimpan ke Steam</string>
|
||||
<string name="mode_controller">Pengawal</string>
|
||||
<string name="mode_controller_hint">Cara Steam mengesan pengawal anda. Berkuat kuasa pada sesi seterusnya.</string>
|
||||
@@ -766,7 +750,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatik</string>
|
||||
<string name="drawer_relative_mouse_on">Hidup</string>
|
||||
<string name="drawer_relative_mouse_off">Mati</string>
|
||||
<string name="drawer_direct_cursor">Kursor</string>
|
||||
<string name="drawer_pc_keyboard">Papan kekunci PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Skrin kedua</string>
|
||||
@@ -1105,43 +1088,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB komputer (pilihan akhir)</string>
|
||||
<string name="wadb_only_if">Hanya jika Debugging Wayarles tidak tersedia.</string>
|
||||
<string name="wadb_computer_group">3 · ADB komputer (pilihan akhir)</string>
|
||||
<string name="ctrl_osc_hint">Bila kawalan sentuh muncul dalam sesi</string>
|
||||
<string name="ctrl_color">Warna</string>
|
||||
<string name="ctrl_color_hint">Rona butang pada skrin</string>
|
||||
<string name="ctrl_custom">Tersuai</string>
|
||||
<string name="ctrl_opacity">Kelegapan</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Saiz butang</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% ialah saiz standard</string>
|
||||
<string name="ctrl_stick_click">Klik stik</string>
|
||||
<string name="ctrl_stick_click_hint">Ketik dua kali dan tahan stik untuk L3 atau R3</string>
|
||||
<string name="ctrl_adaptive">Stik adaptif</string>
|
||||
<string name="ctrl_rumble">Getaran permainan</string>
|
||||
<string name="ctrl_dead_zone">Zon mati kayu bedik</string>
|
||||
<string name="ctrl_steam_button">Butang Steam</string>
|
||||
<string name="ctrl_qam_button">Butang QAM</string>
|
||||
<string name="ctrl_keyboard_button">Butang papan kekunci</string>
|
||||
<string name="ctrl_select_steam">Tekan Select untuk membuka menu Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Sebagai ganti View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con sebagai pengawal VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">Semasa SteamVR berjalan, setiap Joy-Con menjadi tangan. Halakan ke hadapan dan tahan Home atau Capture untuk memusatkannya semula.</string>
|
||||
<string name="setup_animations">Animasi</string>
|
||||
<string name="ctrl_adaptive_hint">Stik muncul di tempat anda sentuh dan tersembunyi apabila dilepaskan</string>
|
||||
<string name="ctrl_layout">Susun atur</string>
|
||||
<string name="ctrl_layout_custom">Kedudukan tersuai disimpan</string>
|
||||
<string name="ctrl_layout_default">Disesuaikan dengan skrin ini</string>
|
||||
<string name="ctrl_edit">Sunting</string>
|
||||
<string name="ctrl_reset">Tetapkan semula</string>
|
||||
<string name="ctrl_mapping">Pemetaan butang</string>
|
||||
<string name="ctrl_mapping_default">Setiap butang menghantar inputnya sendiri</string>
|
||||
<string name="ctrl_mapping_count">%1$d daripada %2$d butang dipetakan semula</string>
|
||||
<string name="ctrl_configure">Konfigurasikan</string>
|
||||
<string name="ctrl_reset_all">Tetapkan semula pengawal</string>
|
||||
<string name="ctrl_reset_all_hint">Memulihkan semua tetapan pengawal dan susun atur</string>
|
||||
<string name="ctrl_mapping_lede">Apa yang setiap butang pada skrin hantar kepada permainan. Tersembunyi mengalih keluar butang itu.</string>
|
||||
<string name="ctrl_onscreen_buttons">Butang pada skrin</string>
|
||||
<string name="ctrl_defaults">Lalai</string>
|
||||
<string name="ctrl_reset_mapping">Tetapkan semula pemetaan</string>
|
||||
<string name="content_android_apps">Apl Android</string>
|
||||
<string name="content_apps_count">%1$d apl</string>
|
||||
<string name="content_no_android_apps">Tiada apl Android boleh dilancarkan dijumpai.</string>
|
||||
@@ -1260,15 +1223,8 @@
|
||||
<string name="deck_surface_stick">Stik</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Tukar antara stik dan trackpad</string>
|
||||
<string name="deck_more_controls">Lagi kawalan Deck</string>
|
||||
<string name="deck_panels">PANEL</string>
|
||||
<string name="deck_close">Tutup kawalan skrin kedua</string>
|
||||
<string name="deck_open_steam_menu">Buka menu Steam</string>
|
||||
<string name="deck_left_upper">Kiri · atas</string>
|
||||
<string name="deck_left_lower">Kiri · bawah</string>
|
||||
<string name="deck_right_upper">Kanan · atas</string>
|
||||
<string name="deck_right_lower">Kanan · bawah</string>
|
||||
<string name="deck_click">Klik</string>
|
||||
<string name="deck_right_trackpad">Trackpad kanan</string>
|
||||
<string name="deck_left_trackpad">Trackpad kiri</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1783,9 +1739,7 @@
|
||||
<string name="ctrl_target_left">D-pad kiri</string>
|
||||
<string name="ctrl_target_right">D-pad kanan</string>
|
||||
<string name="ctrl_target_hidden">Tersembunyi</string>
|
||||
<string name="ctrl_editor_drag">Seret untuk alih</string>
|
||||
<string name="ctrl_editor_snap">Lekat</string>
|
||||
<string name="ctrl_editor_save">Simpan</string>
|
||||
<string name="second_mode_none">Tiada</string>
|
||||
<string name="second_mode_keyboard_trackpad">Papan kekunci + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2630,7 +2584,6 @@
|
||||
<string name="gog_achievements_unavailable">Pencapaian tidak tersedia; semak log sesi</string>
|
||||
<string name="achievement_unlocked">Pencapaian dibuka kunci</string>
|
||||
<string name="touch_paste">Tampal</string>
|
||||
<string name="touch_dpad">Pad arah</string>
|
||||
<string name="touch_left_stick">Kayu bedik kiri</string>
|
||||
<string name="touch_right_stick">Kayu bedik kanan</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3672,4 +3625,7 @@
|
||||
<string name="addons_none_found">Tiada addon ditemui</string>
|
||||
<string name="addons_unreachable">Tidak dapat mencapai %1$s</string>
|
||||
<string name="addons_no_file">Tiada fail untuk versi permainan ini</string>
|
||||
<string name="input_reset_positions">Tetapkan semula kedudukan</string>
|
||||
<string name="input_show_label">Tunjukkan label</string>
|
||||
<string name="input_layout_import_failed">Susun atur ini tidak dapat diimport</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam-berøring (beta)</string>
|
||||
<string name="osc_style_next_session">Steams berøringskontroller starter med neste Steam-sesjon</string>
|
||||
<string name="osc_steam_layout">Steam-berøringslayout</string>
|
||||
<string name="screen_keys">Skjermtaster</string>
|
||||
<string name="screen_keys_add">Legg til tast</string>
|
||||
<string name="screen_key_text">Tekst</string>
|
||||
<string name="screen_key_size">Størrelse</string>
|
||||
<string name="screen_key_opacity">Opasitet</string>
|
||||
<string name="screen_key_type_button">Tast</string>
|
||||
<string name="screen_key_shape_trigger">Utløser</string>
|
||||
<string name="screen_key_toggle">Veksle</string>
|
||||
<string name="screen_key_layout_export">Eksporter</string>
|
||||
<string name="screen_key_shape_pill">Kapsel</string>
|
||||
<string name="screen_key_shape_round">Avrundet</string>
|
||||
<string name="screen_key_shape_circle">Sirkel</string>
|
||||
<string name="screen_key_shape_rect">Rektangel</string>
|
||||
<string name="screen_key_bind">Tast</string>
|
||||
<string name="screen_key_image">Bilde</string>
|
||||
<string name="screen_key_image_clear">Fjern</string>
|
||||
<string name="screen_key_layout">Oppsett</string>
|
||||
<string name="screen_key_layout_save">Lagre</string>
|
||||
<string name="osc_steam_layout_hint">Flytt, endre størrelse på eller skjul dette spillets berøringskontroller; lagres til Steam</string>
|
||||
<string name="mode_controller">Kontroller</string>
|
||||
<string name="mode_controller_hint">Hvordan Steam ser kontrolleren din. Gjelder fra neste sesjon.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatisk</string>
|
||||
<string name="drawer_relative_mouse_on">På</string>
|
||||
<string name="drawer_relative_mouse_off">Av</string>
|
||||
<string name="drawer_direct_cursor">Peker</string>
|
||||
<string name="drawer_pc_keyboard">PC-tastatur</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Andre skjerm</string>
|
||||
@@ -1111,43 +1094,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB fra datamaskin (siste utvei)</string>
|
||||
<string name="wadb_only_if">Bare hvis trådløs feilsøking ikke er tilgjengelig.</string>
|
||||
<string name="wadb_computer_group">3 · ADB fra datamaskin (siste utvei)</string>
|
||||
<string name="ctrl_osc_hint">Når skjermkontrollene vises i en sesjon</string>
|
||||
<string name="ctrl_color">Farge</string>
|
||||
<string name="ctrl_color_hint">Fargetone på skjermknappene</string>
|
||||
<string name="ctrl_custom">Egendefinert</string>
|
||||
<string name="ctrl_opacity">Opasitet</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Knappestørrelse</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% er standardstørrelsen</string>
|
||||
<string name="ctrl_stick_click">Stikke-klikk</string>
|
||||
<string name="ctrl_stick_click_hint">Dobbelttrykk og hold en stikke for L3 eller R3</string>
|
||||
<string name="ctrl_adaptive">Adaptive stikker</string>
|
||||
<string name="ctrl_rumble">Spillvibrasjon</string>
|
||||
<string name="ctrl_dead_zone">Dødsone for styrespak</string>
|
||||
<string name="ctrl_steam_button">Steam-knapp</string>
|
||||
<string name="ctrl_qam_button">QAM-knapp</string>
|
||||
<string name="ctrl_keyboard_button">Tastatur-knapp</string>
|
||||
<string name="ctrl_select_steam">Trykk på Select for å åpne Steam-menyen</string>
|
||||
<string name="ctrl_select_steam_hint">I stedet for View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con som VR-kontrollere</string>
|
||||
<string name="ctrl_joycon_vr_hint">Mens SteamVR kjører, blir hver Joy-Con en hånd. Pek den fremover og hold inne Home eller Capture for å sentrere den på nytt.</string>
|
||||
<string name="setup_animations">Animasjoner</string>
|
||||
<string name="ctrl_adaptive_hint">Stikker vises der du trykker og skjules når du slipper</string>
|
||||
<string name="ctrl_layout">Oppsett</string>
|
||||
<string name="ctrl_layout_custom">Egendefinerte posisjoner lagret</string>
|
||||
<string name="ctrl_layout_default">Tilpasset denne skjermen</string>
|
||||
<string name="ctrl_edit">Rediger</string>
|
||||
<string name="ctrl_reset">Nullstill</string>
|
||||
<string name="ctrl_mapping">Knappetilordning</string>
|
||||
<string name="ctrl_mapping_default">Hver knapp sender sin egen inndata</string>
|
||||
<string name="ctrl_mapping_count">%1$d av %2$d knapper omtilordnet</string>
|
||||
<string name="ctrl_configure">Konfigurer</string>
|
||||
<string name="ctrl_reset_all">Nullstill kontroller</string>
|
||||
<string name="ctrl_reset_all_hint">Gjenoppretter alle kontrollerinnstillinger og oppsettet</string>
|
||||
<string name="ctrl_mapping_lede">Hva hver skjermknapp sender til spillet. Skjult fjerner knappen.</string>
|
||||
<string name="ctrl_onscreen_buttons">Skjermknapper</string>
|
||||
<string name="ctrl_defaults">Standardverdier</string>
|
||||
<string name="ctrl_reset_mapping">Nullstill tilordning</string>
|
||||
<string name="content_android_apps">Android-apper</string>
|
||||
<string name="content_apps_count">%1$d apper</string>
|
||||
<string name="content_no_android_apps">Fant ingen startbare Android-apper.</string>
|
||||
@@ -1267,15 +1230,8 @@
|
||||
<string name="deck_surface_stick">Stikke</string>
|
||||
<string name="deck_surface_trackpad">Styreflate</string>
|
||||
<string name="deck_surface_switch">Bytt mellom stikke og styreflate</string>
|
||||
<string name="deck_more_controls">Flere Deck-kontroller</string>
|
||||
<string name="deck_panels">PANELER</string>
|
||||
<string name="deck_close">Lukk kontroller for andre skjerm</string>
|
||||
<string name="deck_open_steam_menu">Åpne Steam-menyen</string>
|
||||
<string name="deck_left_upper">Venstre · øvre</string>
|
||||
<string name="deck_left_lower">Venstre · nedre</string>
|
||||
<string name="deck_right_upper">Høyre · øvre</string>
|
||||
<string name="deck_right_lower">Høyre · nedre</string>
|
||||
<string name="deck_click">Klikk</string>
|
||||
<string name="deck_right_trackpad">Høyre styreflate</string>
|
||||
<string name="deck_left_trackpad">Venstre styreflate</string>
|
||||
<string name="second_trackpad">Styreflate</string>
|
||||
@@ -1807,9 +1763,7 @@
|
||||
<string name="ctrl_target_left">D-pad venstre</string>
|
||||
<string name="ctrl_target_right">D-pad høyre</string>
|
||||
<string name="ctrl_target_hidden">Skjult</string>
|
||||
<string name="ctrl_editor_drag">Dra for å flytte</string>
|
||||
<string name="ctrl_editor_snap">Fest</string>
|
||||
<string name="ctrl_editor_save">Lagre</string>
|
||||
<string name="second_mode_none">Ingen</string>
|
||||
<string name="second_mode_keyboard_trackpad">Tastatur + styreflate</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2657,7 +2611,6 @@
|
||||
<string name="gog_achievements_unavailable">Prestasjoner ikke tilgjengelig; sjekk sesjonsloggene</string>
|
||||
<string name="achievement_unlocked">Prestasjon låst opp</string>
|
||||
<string name="touch_paste">Lim inn</string>
|
||||
<string name="touch_dpad">Styrekors</string>
|
||||
<string name="touch_left_stick">Venstre stikke</string>
|
||||
<string name="touch_right_stick">Høyre stikke</string>
|
||||
<string name="touch_menu">Meny</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Fant ingen tillegg</string>
|
||||
<string name="addons_unreachable">Fikk ikke kontakt med %1$s</string>
|
||||
<string name="addons_no_file">Ingen fil for denne spillversjonen</string>
|
||||
<string name="input_reset_positions">Tilbakestill plasseringer</string>
|
||||
<string name="input_show_label">Vis etikett</string>
|
||||
<string name="input_layout_import_failed">Kunne ikke importere dette oppsettet</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam-aanraakbediening (bèta)</string>
|
||||
<string name="osc_style_next_session">De aanraakbediening van Steam start bij de volgende Steam-sessie</string>
|
||||
<string name="osc_steam_layout">Steam-aanraakindeling</string>
|
||||
<string name="screen_keys">Schermtoetsen</string>
|
||||
<string name="screen_keys_add">Toets toevoegen</string>
|
||||
<string name="screen_key_text">Tekst</string>
|
||||
<string name="screen_key_size">Grootte</string>
|
||||
<string name="screen_key_opacity">Transparantie</string>
|
||||
<string name="screen_key_type_button">Toets</string>
|
||||
<string name="screen_key_shape_trigger">Trigger</string>
|
||||
<string name="screen_key_toggle">Schakelen</string>
|
||||
<string name="screen_key_layout_export">Exporteren</string>
|
||||
<string name="screen_key_shape_pill">Capsule</string>
|
||||
<string name="screen_key_shape_round">Afgerond</string>
|
||||
<string name="screen_key_shape_circle">Cirkel</string>
|
||||
<string name="screen_key_shape_rect">Rechthoek</string>
|
||||
<string name="screen_key_bind">Toets</string>
|
||||
<string name="screen_key_image">Afbeelding</string>
|
||||
<string name="screen_key_image_clear">Wissen</string>
|
||||
<string name="screen_key_layout">Indeling</string>
|
||||
<string name="screen_key_layout_save">Opslaan</string>
|
||||
<string name="osc_steam_layout_hint">Verplaats, schaal of verberg de aanraakbediening van deze game; opgeslagen in Steam</string>
|
||||
<string name="mode_controller">Controller</string>
|
||||
<string name="mode_controller_hint">Hoe Steam je controller ziet. Geldt vanaf de volgende sessie.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatisch</string>
|
||||
<string name="drawer_relative_mouse_on">Aan</string>
|
||||
<string name="drawer_relative_mouse_off">Uit</string>
|
||||
<string name="drawer_direct_cursor">Cursor</string>
|
||||
<string name="drawer_pc_keyboard">Pc-toetsenbord</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Tweede scherm</string>
|
||||
@@ -1111,43 +1094,23 @@
|
||||
<string name="wadb_computer_last">3 · Computer-ADB (laatste redmiddel)</string>
|
||||
<string name="wadb_only_if">Alleen als Draadloos debuggen niet beschikbaar is.</string>
|
||||
<string name="wadb_computer_group">3 · Computer-ADB (laatste redmiddel)</string>
|
||||
<string name="ctrl_osc_hint">Wanneer de aanraakbediening in een sessie verschijnt</string>
|
||||
<string name="ctrl_color">Kleur</string>
|
||||
<string name="ctrl_color_hint">Tint van de knoppen op het scherm</string>
|
||||
<string name="ctrl_custom">Aangepast</string>
|
||||
<string name="ctrl_opacity">Transparantie</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Knopgrootte</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% is de standaardgrootte</string>
|
||||
<string name="ctrl_stick_click">Stickklik</string>
|
||||
<string name="ctrl_stick_click_hint">Dubbeltik en houd een stick ingedrukt voor L3 of R3</string>
|
||||
<string name="ctrl_adaptive">Adaptieve sticks</string>
|
||||
<string name="ctrl_rumble">Trillen in games</string>
|
||||
<string name="ctrl_dead_zone">Dode zone van stick</string>
|
||||
<string name="ctrl_steam_button">Steam-knop</string>
|
||||
<string name="ctrl_qam_button">QAM-knop</string>
|
||||
<string name="ctrl_keyboard_button">Toetsenbordknop</string>
|
||||
<string name="ctrl_select_steam">Druk op Select om het Steam-menu te openen</string>
|
||||
<string name="ctrl_select_steam_hint">In plaats van View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Cons als VR-controllers</string>
|
||||
<string name="ctrl_joycon_vr_hint">Zolang SteamVR draait, wordt elke Joy-Con een hand. Richt hem naar voren en houd Home of Capture ingedrukt om hem opnieuw te centreren.</string>
|
||||
<string name="setup_animations">Animaties</string>
|
||||
<string name="ctrl_adaptive_hint">Sticks verschijnen waar je aanraakt en verdwijnen als je loslaat</string>
|
||||
<string name="ctrl_layout">Indeling</string>
|
||||
<string name="ctrl_layout_custom">Aangepaste posities opgeslagen</string>
|
||||
<string name="ctrl_layout_default">Aangepast aan dit scherm</string>
|
||||
<string name="ctrl_edit">Bewerken</string>
|
||||
<string name="ctrl_reset">Resetten</string>
|
||||
<string name="ctrl_mapping">Knoppenindeling</string>
|
||||
<string name="ctrl_mapping_default">Elke knop stuurt zijn eigen invoer</string>
|
||||
<string name="ctrl_mapping_count">%1$d van %2$d knoppen opnieuw toegewezen</string>
|
||||
<string name="ctrl_configure">Configureren</string>
|
||||
<string name="ctrl_reset_all">Controller resetten</string>
|
||||
<string name="ctrl_reset_all_hint">Herstelt alle controllerinstellingen en de indeling</string>
|
||||
<string name="ctrl_mapping_lede">Wat elke schermknop naar de game stuurt. Verborgen verwijdert de knop.</string>
|
||||
<string name="ctrl_onscreen_buttons">Schermknoppen</string>
|
||||
<string name="ctrl_defaults">Standaardinstellingen</string>
|
||||
<string name="ctrl_reset_mapping">Indeling resetten</string>
|
||||
<string name="content_android_apps">Android-apps</string>
|
||||
<string name="content_apps_count">%1$d apps</string>
|
||||
<string name="content_no_android_apps">Geen startbare Android-apps gevonden.</string>
|
||||
@@ -1267,15 +1230,8 @@
|
||||
<string name="deck_surface_stick">Stick</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Wisselen tussen stick en trackpad</string>
|
||||
<string name="deck_more_controls">Meer Deck-bediening</string>
|
||||
<string name="deck_panels">PANELEN</string>
|
||||
<string name="deck_close">Bediening op tweede scherm sluiten</string>
|
||||
<string name="deck_open_steam_menu">Steam-menu openen</string>
|
||||
<string name="deck_left_upper">Links · boven</string>
|
||||
<string name="deck_left_lower">Links · onder</string>
|
||||
<string name="deck_right_upper">Rechts · boven</string>
|
||||
<string name="deck_right_lower">Rechts · onder</string>
|
||||
<string name="deck_click">Klik</string>
|
||||
<string name="deck_right_trackpad">Rechtertrackpad</string>
|
||||
<string name="deck_left_trackpad">Linkertrackpad</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1807,9 +1763,7 @@
|
||||
<string name="ctrl_target_left">D-pad links</string>
|
||||
<string name="ctrl_target_right">D-pad rechts</string>
|
||||
<string name="ctrl_target_hidden">Verborgen</string>
|
||||
<string name="ctrl_editor_drag">Sleep om te verplaatsen</string>
|
||||
<string name="ctrl_editor_snap">Uitlijnen</string>
|
||||
<string name="ctrl_editor_save">Opslaan</string>
|
||||
<string name="second_mode_none">Geen</string>
|
||||
<string name="second_mode_keyboard_trackpad">Toetsenbord + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2657,7 +2611,6 @@
|
||||
<string name="gog_achievements_unavailable">Prestaties niet beschikbaar; controleer sessielogs</string>
|
||||
<string name="achievement_unlocked">Prestatie ontgrendeld</string>
|
||||
<string name="touch_paste">Plakken</string>
|
||||
<string name="touch_dpad">Richtingstoetsen</string>
|
||||
<string name="touch_left_stick">Linkerstick</string>
|
||||
<string name="touch_right_stick">Rechterstick</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Geen add-ons gevonden</string>
|
||||
<string name="addons_unreachable">Kan %1$s niet bereiken</string>
|
||||
<string name="addons_no_file">Geen bestand voor deze gameversie</string>
|
||||
<string name="input_reset_positions">Posities herstellen</string>
|
||||
<string name="input_show_label">Label tonen</string>
|
||||
<string name="input_layout_import_failed">Deze indeling kan niet worden geïmporteerd</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Dotyk Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Sterowanie dotykowe Steam zacznie działać od następnej sesji Steam</string>
|
||||
<string name="osc_steam_layout">Układ dotykowy Steam</string>
|
||||
<string name="screen_keys">Klawisze ekranu</string>
|
||||
<string name="screen_keys_add">Dodaj klawisz</string>
|
||||
<string name="screen_key_text">Tekst</string>
|
||||
<string name="screen_key_size">Rozmiar</string>
|
||||
<string name="screen_key_opacity">Przezroczystość</string>
|
||||
<string name="screen_key_type_button">Klawisz</string>
|
||||
<string name="screen_key_shape_trigger">Spust</string>
|
||||
<string name="screen_key_toggle">Przełącznik</string>
|
||||
<string name="screen_key_layout_export">Eksportuj</string>
|
||||
<string name="screen_key_shape_pill">Kapsułka</string>
|
||||
<string name="screen_key_shape_round">Zaokrąglony</string>
|
||||
<string name="screen_key_shape_circle">Koło</string>
|
||||
<string name="screen_key_shape_rect">Prostokąt</string>
|
||||
<string name="screen_key_bind">Klawisz</string>
|
||||
<string name="screen_key_image">Obraz</string>
|
||||
<string name="screen_key_image_clear">Wyczyść</string>
|
||||
<string name="screen_key_layout">Układ</string>
|
||||
<string name="screen_key_layout_save">Zapisz</string>
|
||||
<string name="osc_steam_layout_hint">Przesuwaj, zmieniaj rozmiar lub ukrywaj sterowanie dotykowe tej gry; zapisywane w Steam</string>
|
||||
<string name="mode_controller">Kontroler</string>
|
||||
<string name="mode_controller_hint">Jak Steam widzi Twój kontroler. Działa od następnej sesji.</string>
|
||||
@@ -772,7 +756,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatycznie</string>
|
||||
<string name="drawer_relative_mouse_on">Włączone</string>
|
||||
<string name="drawer_relative_mouse_off">Wyłączone</string>
|
||||
<string name="drawer_direct_cursor">Kursor</string>
|
||||
<string name="drawer_pc_keyboard">Klawiatura PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Drugi ekran</string>
|
||||
@@ -1123,43 +1106,23 @@
|
||||
<string name="wadb_computer_last">3 · Komputer z ADB (ostatnia opcja)</string>
|
||||
<string name="wadb_only_if">Tylko jeśli debugowanie bezprzewodowe jest niedostępne.</string>
|
||||
<string name="wadb_computer_group">3 · Komputer z ADB (ostatnia opcja)</string>
|
||||
<string name="ctrl_osc_hint">Gdy w sesji pojawiają się sterowanie dotykowe</string>
|
||||
<string name="ctrl_color">Kolor</string>
|
||||
<string name="ctrl_color_hint">Odcień przycisków na ekranie</string>
|
||||
<string name="ctrl_custom">Własny</string>
|
||||
<string name="ctrl_opacity">Przezroczystość</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Rozmiar przycisków</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% to rozmiar standardowy</string>
|
||||
<string name="ctrl_stick_click">Kliknięcie gałki</string>
|
||||
<string name="ctrl_stick_click_hint">Dotknij dwukrotnie i przytrzymaj gałkę, aby uzyskać L3 lub R3</string>
|
||||
<string name="ctrl_adaptive">Adaptacyjne gałki</string>
|
||||
<string name="ctrl_rumble">Wibracje gry</string>
|
||||
<string name="ctrl_dead_zone">Martwa strefa drążka</string>
|
||||
<string name="ctrl_steam_button">Przycisk Steam</string>
|
||||
<string name="ctrl_qam_button">Przycisk QAM</string>
|
||||
<string name="ctrl_keyboard_button">Przycisk klawiatury</string>
|
||||
<string name="ctrl_select_steam">Naciśnij Select, aby otworzyć menu Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Zamiast View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Cony jako kontrolery VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">Gdy działa SteamVR, każdy Joy-Con staje się dłonią. Skieruj go przed siebie i przytrzymaj Home lub Capture, aby go wyśrodkować.</string>
|
||||
<string name="setup_animations">Animacje</string>
|
||||
<string name="ctrl_adaptive_hint">Gałki pojawiają się tam, gdzie dotykasz, i chowają się po puszczeniu</string>
|
||||
<string name="ctrl_layout">Układ</string>
|
||||
<string name="ctrl_layout_custom">Zapisano własne pozycje</string>
|
||||
<string name="ctrl_layout_default">Dopasowany do tego ekranu</string>
|
||||
<string name="ctrl_edit">Edytuj</string>
|
||||
<string name="ctrl_reset">Resetuj</string>
|
||||
<string name="ctrl_mapping">Mapowanie przycisków</string>
|
||||
<string name="ctrl_mapping_default">Każdy przycisk wysyła własny sygnał</string>
|
||||
<string name="ctrl_mapping_count">Zmapowano %1$d z %2$d przycisków</string>
|
||||
<string name="ctrl_configure">Skonfiguruj</string>
|
||||
<string name="ctrl_reset_all">Resetuj kontroler</string>
|
||||
<string name="ctrl_reset_all_hint">Przywraca wszystkie ustawienia kontrolera i układ</string>
|
||||
<string name="ctrl_mapping_lede">Co wysyła do gry każdy przycisk na ekranie. Ukryty usuwa przycisk.</string>
|
||||
<string name="ctrl_onscreen_buttons">Przyciski na ekranie</string>
|
||||
<string name="ctrl_defaults">Domyślne</string>
|
||||
<string name="ctrl_reset_mapping">Resetuj mapowanie</string>
|
||||
<string name="content_android_apps">Aplikacje Android</string>
|
||||
<string name="content_apps_count">%1$d aplikacji</string>
|
||||
<string name="content_no_android_apps">Nie znaleziono żadnych aplikacji Android do uruchomienia.</string>
|
||||
@@ -1281,15 +1244,8 @@
|
||||
<string name="deck_surface_stick">Gałka</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Przełącz między gałką a trackpadem</string>
|
||||
<string name="deck_more_controls">Więcej sterowania Deck</string>
|
||||
<string name="deck_panels">PANELE</string>
|
||||
<string name="deck_close">Zamknij sterowanie na drugim ekranie</string>
|
||||
<string name="deck_open_steam_menu">Otwórz menu Steam</string>
|
||||
<string name="deck_left_upper">Lewy · górny</string>
|
||||
<string name="deck_left_lower">Lewy · dolny</string>
|
||||
<string name="deck_right_upper">Prawy · górny</string>
|
||||
<string name="deck_right_lower">Prawy · dolny</string>
|
||||
<string name="deck_click">Kliknięcie</string>
|
||||
<string name="deck_right_trackpad">Prawy trackpad</string>
|
||||
<string name="deck_left_trackpad">Lewy trackpad</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1855,9 +1811,7 @@
|
||||
<string name="ctrl_target_left">Krzyżak w lewo</string>
|
||||
<string name="ctrl_target_right">Krzyżak w prawo</string>
|
||||
<string name="ctrl_target_hidden">Ukryty</string>
|
||||
<string name="ctrl_editor_drag">Przeciągnij, aby przenieść</string>
|
||||
<string name="ctrl_editor_snap">Przyciąganie</string>
|
||||
<string name="ctrl_editor_save">Zapisz</string>
|
||||
<string name="second_mode_none">Brak</string>
|
||||
<string name="second_mode_keyboard_trackpad">Klawiatura + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2711,7 +2665,6 @@
|
||||
<string name="gog_achievements_unavailable">Osiągnięcia niedostępne; sprawdź dzienniki sesji</string>
|
||||
<string name="achievement_unlocked">Osiągnięcie odblokowane</string>
|
||||
<string name="touch_paste">Wklej</string>
|
||||
<string name="touch_dpad">Krzyżak</string>
|
||||
<string name="touch_left_stick">Lewy drążek</string>
|
||||
<string name="touch_right_stick">Prawy drążek</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3780,4 +3733,7 @@
|
||||
<string name="addons_none_found">Nie znaleziono dodatków</string>
|
||||
<string name="addons_unreachable">Nie można połączyć się z %1$s</string>
|
||||
<string name="addons_no_file">Brak pliku dla tej wersji gry</string>
|
||||
<string name="input_reset_positions">Resetuj położenie</string>
|
||||
<string name="input_show_label">Pokaż etykietę</string>
|
||||
<string name="input_layout_import_failed">Nie można zaimportować tego układu</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Controlos táteis do Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Os controlos táteis do Steam começam na próxima sessão do Steam</string>
|
||||
<string name="osc_steam_layout">Esquema tátil do Steam</string>
|
||||
<string name="screen_keys">Teclas no ecrã</string>
|
||||
<string name="screen_keys_add">Adicionar tecla</string>
|
||||
<string name="screen_key_text">Texto</string>
|
||||
<string name="screen_key_size">Tamanho</string>
|
||||
<string name="screen_key_opacity">Opacidade</string>
|
||||
<string name="screen_key_type_button">Tecla</string>
|
||||
<string name="screen_key_shape_trigger">Gatilho</string>
|
||||
<string name="screen_key_toggle">Alternar</string>
|
||||
<string name="screen_key_layout_export">Exportar</string>
|
||||
<string name="screen_key_shape_pill">Cápsula</string>
|
||||
<string name="screen_key_shape_round">Arredondado</string>
|
||||
<string name="screen_key_shape_circle">Círculo</string>
|
||||
<string name="screen_key_shape_rect">Retângulo</string>
|
||||
<string name="screen_key_bind">Tecla</string>
|
||||
<string name="screen_key_image">Imagem</string>
|
||||
<string name="screen_key_image_clear">Limpar</string>
|
||||
<string name="screen_key_layout">Esquema</string>
|
||||
<string name="screen_key_layout_save">Guardar</string>
|
||||
<string name="osc_steam_layout_hint">Mova, redimensione ou oculte os controlos táteis deste jogo; é guardado no Steam</string>
|
||||
<string name="mode_controller">Comando</string>
|
||||
<string name="mode_controller_hint">Como o Steam vê o seu comando. Aplica-se na próxima sessão.</string>
|
||||
@@ -770,7 +754,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automático</string>
|
||||
<string name="drawer_relative_mouse_on">Ativado</string>
|
||||
<string name="drawer_relative_mouse_off">Desativado</string>
|
||||
<string name="drawer_direct_cursor">Cursor</string>
|
||||
<string name="drawer_pc_keyboard">Teclado de PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Segundo ecrã</string>
|
||||
@@ -1109,43 +1092,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB num computador (último recurso)</string>
|
||||
<string name="wadb_only_if">Apenas se a Depuração sem fios não estiver disponível.</string>
|
||||
<string name="wadb_computer_group">3 · ADB num computador (último recurso)</string>
|
||||
<string name="ctrl_osc_hint">Quando os controlos táteis aparecem numa sessão</string>
|
||||
<string name="ctrl_color">Cor</string>
|
||||
<string name="ctrl_color_hint">Tonalidade dos botões no ecrã</string>
|
||||
<string name="ctrl_custom">Personalizada</string>
|
||||
<string name="ctrl_opacity">Opacidade</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Tamanho dos botões</string>
|
||||
<string name="ctrl_size_hint" formatted="false">O tamanho padrão é 100%</string>
|
||||
<string name="ctrl_stick_click">Clique do analógico</string>
|
||||
<string name="ctrl_stick_click_hint">Toque duas vezes num analógico e mantenha para L3 ou R3</string>
|
||||
<string name="ctrl_adaptive">Analógicos adaptáveis</string>
|
||||
<string name="ctrl_rumble">Vibração do jogo</string>
|
||||
<string name="ctrl_dead_zone">Zona morta do manípulo</string>
|
||||
<string name="ctrl_steam_button">Botão Steam</string>
|
||||
<string name="ctrl_qam_button">Botão QAM</string>
|
||||
<string name="ctrl_keyboard_button">Botão do teclado</string>
|
||||
<string name="ctrl_select_steam">Premir Select para abrir o menu do Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Em vez de View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con como comandos de RV</string>
|
||||
<string name="ctrl_joycon_vr_hint">Enquanto o SteamVR está a correr, cada Joy-Con torna-se uma mão. Aponte-o para a frente e mantenha Home ou Capture premido para o recentrar.</string>
|
||||
<string name="setup_animations">Animações</string>
|
||||
<string name="ctrl_adaptive_hint">Os analógicos aparecem onde tocar e ocultam-se ao soltar</string>
|
||||
<string name="ctrl_layout">Esquema</string>
|
||||
<string name="ctrl_layout_custom">Posições personalizadas guardadas</string>
|
||||
<string name="ctrl_layout_default">Ajustado a este ecrã</string>
|
||||
<string name="ctrl_edit">Editar</string>
|
||||
<string name="ctrl_reset">Repor</string>
|
||||
<string name="ctrl_mapping">Mapeamento de botões</string>
|
||||
<string name="ctrl_mapping_default">Cada botão envia a sua própria entrada</string>
|
||||
<string name="ctrl_mapping_count">%1$d de %2$d botões remapeados</string>
|
||||
<string name="ctrl_configure">Configurar</string>
|
||||
<string name="ctrl_reset_all">Repor comando</string>
|
||||
<string name="ctrl_reset_all_hint">Restaura todas as definições do comando e o esquema</string>
|
||||
<string name="ctrl_mapping_lede">O que cada botão no ecrã envia para o jogo. Oculto remove o botão.</string>
|
||||
<string name="ctrl_onscreen_buttons">Botões no ecrã</string>
|
||||
<string name="ctrl_defaults">Valores padrão</string>
|
||||
<string name="ctrl_reset_mapping">Repor mapeamento</string>
|
||||
<string name="content_android_apps">Apps Android</string>
|
||||
<string name="content_apps_count">%1$d apps</string>
|
||||
<string name="content_no_android_apps">Não foram encontradas apps Android para iniciar.</string>
|
||||
@@ -1266,15 +1229,8 @@
|
||||
<string name="deck_surface_stick">Joystick</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Alternar entre joystick e trackpad</string>
|
||||
<string name="deck_more_controls">Mais controlos do Deck</string>
|
||||
<string name="deck_panels">PAINÉIS</string>
|
||||
<string name="deck_close">Fechar controlos do segundo ecrã</string>
|
||||
<string name="deck_open_steam_menu">Abrir menu Steam</string>
|
||||
<string name="deck_left_upper">Esquerda · superior</string>
|
||||
<string name="deck_left_lower">Esquerda · inferior</string>
|
||||
<string name="deck_right_upper">Direita · superior</string>
|
||||
<string name="deck_right_lower">Direita · inferior</string>
|
||||
<string name="deck_click">Clique</string>
|
||||
<string name="deck_right_trackpad">Trackpad direito</string>
|
||||
<string name="deck_left_trackpad">Trackpad esquerdo</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1823,9 +1779,7 @@
|
||||
<string name="ctrl_target_left">Direcional para a esquerda</string>
|
||||
<string name="ctrl_target_right">Direcional para a direita</string>
|
||||
<string name="ctrl_target_hidden">Oculto</string>
|
||||
<string name="ctrl_editor_drag">Arraste para mover</string>
|
||||
<string name="ctrl_editor_snap">Encaixar</string>
|
||||
<string name="ctrl_editor_save">Guardar</string>
|
||||
<string name="second_mode_none">Nenhum</string>
|
||||
<string name="second_mode_keyboard_trackpad">Teclado + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2673,7 +2627,6 @@
|
||||
<string name="gog_achievements_unavailable">Conquistas indisponíveis; verifica os registos da sessão</string>
|
||||
<string name="achievement_unlocked">Conquista desbloqueada</string>
|
||||
<string name="touch_paste">Colar</string>
|
||||
<string name="touch_dpad">Direcional</string>
|
||||
<string name="touch_left_stick">Stick esquerdo</string>
|
||||
<string name="touch_right_stick">Stick direito</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3741,4 +3694,7 @@
|
||||
<string name="addons_none_found">Nenhum addon encontrado</string>
|
||||
<string name="addons_unreachable">Não foi possível contactar %1$s</string>
|
||||
<string name="addons_no_file">Não há ficheiro para esta versão do jogo</string>
|
||||
<string name="input_reset_positions">Repor posições</string>
|
||||
<string name="input_show_label">Mostrar etiqueta</string>
|
||||
<string name="input_layout_import_failed">Não foi possível importar este esquema</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Toque da Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Os controles de toque da Steam começam na próxima sessão da Steam</string>
|
||||
<string name="osc_steam_layout">Layout de toque da Steam</string>
|
||||
<string name="screen_keys">Teclas na tela</string>
|
||||
<string name="screen_keys_add">Adicionar tecla</string>
|
||||
<string name="screen_key_text">Texto</string>
|
||||
<string name="screen_key_size">Tamanho</string>
|
||||
<string name="screen_key_opacity">Opacidade</string>
|
||||
<string name="screen_key_type_button">Tecla</string>
|
||||
<string name="screen_key_shape_trigger">Gatilho</string>
|
||||
<string name="screen_key_toggle">Alternar</string>
|
||||
<string name="screen_key_layout_export">Exportar</string>
|
||||
<string name="screen_key_shape_pill">Cápsula</string>
|
||||
<string name="screen_key_shape_round">Arredondado</string>
|
||||
<string name="screen_key_shape_circle">Círculo</string>
|
||||
<string name="screen_key_shape_rect">Retângulo</string>
|
||||
<string name="screen_key_bind">Tecla</string>
|
||||
<string name="screen_key_image">Imagem</string>
|
||||
<string name="screen_key_image_clear">Limpar</string>
|
||||
<string name="screen_key_layout">Layout</string>
|
||||
<string name="screen_key_layout_save">Salvar</string>
|
||||
<string name="osc_steam_layout_hint">Mova, redimensione ou oculte os controles de toque deste jogo; salvo na Steam</string>
|
||||
<string name="mode_controller">Controle</string>
|
||||
<string name="mode_controller_hint">Como a Steam vê seu controle. Vale a partir da próxima sessão.</string>
|
||||
@@ -770,7 +754,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automático</string>
|
||||
<string name="drawer_relative_mouse_on">Ativado</string>
|
||||
<string name="drawer_relative_mouse_off">Desativado</string>
|
||||
<string name="drawer_direct_cursor">Cursor</string>
|
||||
<string name="drawer_pc_keyboard">Teclado de PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Segunda tela</string>
|
||||
@@ -1109,43 +1092,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB pelo computador (último recurso)</string>
|
||||
<string name="wadb_only_if">Só se a Depuração por Wi-Fi não estiver disponível.</string>
|
||||
<string name="wadb_computer_group">3 · ADB pelo computador (último recurso)</string>
|
||||
<string name="ctrl_osc_hint">Quando os controles de toque aparecem em uma sessão</string>
|
||||
<string name="ctrl_color">Cor</string>
|
||||
<string name="ctrl_color_hint">Tom dos botões na tela</string>
|
||||
<string name="ctrl_custom">Personalizada</string>
|
||||
<string name="ctrl_opacity">Opacidade</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Tamanho dos botões</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% é o tamanho padrão</string>
|
||||
<string name="ctrl_stick_click">Clique do analógico</string>
|
||||
<string name="ctrl_stick_click_hint">Toque duas vezes e segure um analógico para L3 ou R3</string>
|
||||
<string name="ctrl_adaptive">Analógicos adaptáveis</string>
|
||||
<string name="ctrl_rumble">Vibração do jogo</string>
|
||||
<string name="ctrl_dead_zone">Zona morta do analógico</string>
|
||||
<string name="ctrl_steam_button">Botão Steam</string>
|
||||
<string name="ctrl_qam_button">Botão QAM</string>
|
||||
<string name="ctrl_keyboard_button">Botão do teclado</string>
|
||||
<string name="ctrl_select_steam">Pressione Select para abrir o menu Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Em vez de View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Cons como controles de RV</string>
|
||||
<string name="ctrl_joycon_vr_hint">Enquanto o SteamVR está rodando, cada Joy-Con vira uma mão. Aponte-o para a frente e segure Home ou Capture para recentralizá-lo.</string>
|
||||
<string name="setup_animations">Animações</string>
|
||||
<string name="ctrl_adaptive_hint">Os analógicos aparecem onde você toca e somem ao soltar</string>
|
||||
<string name="ctrl_layout">Layout</string>
|
||||
<string name="ctrl_layout_custom">Posições personalizadas salvas</string>
|
||||
<string name="ctrl_layout_default">Ajustado a esta tela</string>
|
||||
<string name="ctrl_edit">Editar</string>
|
||||
<string name="ctrl_reset">Redefinir</string>
|
||||
<string name="ctrl_mapping">Mapeamento de botões</string>
|
||||
<string name="ctrl_mapping_default">Cada botão envia o próprio comando</string>
|
||||
<string name="ctrl_mapping_count">%1$d de %2$d botões remapeados</string>
|
||||
<string name="ctrl_configure">Configurar</string>
|
||||
<string name="ctrl_reset_all">Redefinir controle</string>
|
||||
<string name="ctrl_reset_all_hint">Restaura todas as configurações do controle e o layout</string>
|
||||
<string name="ctrl_mapping_lede">O que cada botão na tela envia ao jogo. Oculto remove o botão.</string>
|
||||
<string name="ctrl_onscreen_buttons">Botões na tela</string>
|
||||
<string name="ctrl_defaults">Padrões</string>
|
||||
<string name="ctrl_reset_mapping">Redefinir mapeamento</string>
|
||||
<string name="content_android_apps">Apps Android</string>
|
||||
<string name="content_apps_count">%1$d apps</string>
|
||||
<string name="content_no_android_apps">Nenhum app Android que possa ser aberto foi encontrado.</string>
|
||||
@@ -1266,15 +1229,8 @@
|
||||
<string name="deck_surface_stick">Analógico</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Alternar entre analógico e trackpad</string>
|
||||
<string name="deck_more_controls">Mais controles do Deck</string>
|
||||
<string name="deck_panels">PAINÉIS</string>
|
||||
<string name="deck_close">Fechar controles da segunda tela</string>
|
||||
<string name="deck_open_steam_menu">Abrir o menu Steam</string>
|
||||
<string name="deck_left_upper">Esquerdo · superior</string>
|
||||
<string name="deck_left_lower">Esquerdo · inferior</string>
|
||||
<string name="deck_right_upper">Direito · superior</string>
|
||||
<string name="deck_right_lower">Direito · inferior</string>
|
||||
<string name="deck_click">Clique</string>
|
||||
<string name="deck_right_trackpad">Trackpad direito</string>
|
||||
<string name="deck_left_trackpad">Trackpad esquerdo</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1823,9 +1779,7 @@
|
||||
<string name="ctrl_target_left">Direcional para a esquerda</string>
|
||||
<string name="ctrl_target_right">Direcional para a direita</string>
|
||||
<string name="ctrl_target_hidden">Oculto</string>
|
||||
<string name="ctrl_editor_drag">Arraste para mover</string>
|
||||
<string name="ctrl_editor_snap">Encaixar</string>
|
||||
<string name="ctrl_editor_save">Salvar</string>
|
||||
<string name="second_mode_none">Nenhum</string>
|
||||
<string name="second_mode_keyboard_trackpad">Teclado + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2673,7 +2627,6 @@
|
||||
<string name="gog_achievements_unavailable">Conquistas indisponíveis; veja os registros da sessão</string>
|
||||
<string name="achievement_unlocked">Conquista desbloqueada</string>
|
||||
<string name="touch_paste">Colar</string>
|
||||
<string name="touch_dpad">Direcional</string>
|
||||
<string name="touch_left_stick">Analógico esquerdo</string>
|
||||
<string name="touch_right_stick">Analógico direito</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3741,4 +3694,7 @@
|
||||
<string name="addons_none_found">Nenhum addon encontrado</string>
|
||||
<string name="addons_unreachable">Não foi possível acessar %1$s</string>
|
||||
<string name="addons_no_file">Não há arquivo para esta versão do jogo</string>
|
||||
<string name="input_reset_positions">Redefinir posições</string>
|
||||
<string name="input_show_label">Mostrar rótulo</string>
|
||||
<string name="input_layout_import_failed">Não foi possível importar este layout</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Atingere Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Comenzile tactile Steam pornesc odată cu următoarea sesiune Steam</string>
|
||||
<string name="osc_steam_layout">Aranjament tactil Steam</string>
|
||||
<string name="screen_keys">Taste pe ecran</string>
|
||||
<string name="screen_keys_add">Adaugă tastă</string>
|
||||
<string name="screen_key_text">Text</string>
|
||||
<string name="screen_key_size">Dimensiune</string>
|
||||
<string name="screen_key_opacity">Opacitate</string>
|
||||
<string name="screen_key_type_button">Tastă</string>
|
||||
<string name="screen_key_shape_trigger">Trăgaci</string>
|
||||
<string name="screen_key_toggle">Comutare</string>
|
||||
<string name="screen_key_layout_export">Exportă</string>
|
||||
<string name="screen_key_shape_pill">Capsulă</string>
|
||||
<string name="screen_key_shape_round">Rotunjit</string>
|
||||
<string name="screen_key_shape_circle">Cerc</string>
|
||||
<string name="screen_key_shape_rect">Dreptunghi</string>
|
||||
<string name="screen_key_bind">Tastă</string>
|
||||
<string name="screen_key_image">Imagine</string>
|
||||
<string name="screen_key_image_clear">Șterge</string>
|
||||
<string name="screen_key_layout">Aranjament</string>
|
||||
<string name="screen_key_layout_save">Salvează</string>
|
||||
<string name="osc_steam_layout_hint">Mută, redimensionează sau ascunde comenzile tactile ale acestui joc; salvate în Steam</string>
|
||||
<string name="mode_controller">Controller</string>
|
||||
<string name="mode_controller_hint">Cum vede Steam controllerul tău. Se aplică la sesiunea următoare.</string>
|
||||
@@ -770,7 +754,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automat</string>
|
||||
<string name="drawer_relative_mouse_on">Pornit</string>
|
||||
<string name="drawer_relative_mouse_off">Oprit</string>
|
||||
<string name="drawer_direct_cursor">Cursor</string>
|
||||
<string name="drawer_pc_keyboard">Tastatură de PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Al doilea ecran</string>
|
||||
@@ -1117,43 +1100,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB pe computer (ultima soluție)</string>
|
||||
<string name="wadb_only_if">Doar dacă Depanarea wireless nu este disponibilă.</string>
|
||||
<string name="wadb_computer_group">3 · ADB pe computer (ultima soluție)</string>
|
||||
<string name="ctrl_osc_hint">Când apar comenzile tactile într-o sesiune</string>
|
||||
<string name="ctrl_color">Culoare</string>
|
||||
<string name="ctrl_color_hint">Tenta butoanelor de pe ecran</string>
|
||||
<string name="ctrl_custom">Personalizat</string>
|
||||
<string name="ctrl_opacity">Opacitate</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Dimensiunea butoanelor</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% este dimensiunea standard</string>
|
||||
<string name="ctrl_stick_click">Apăsarea manșei</string>
|
||||
<string name="ctrl_stick_click_hint">Apasă de două ori și ține apăsată o manșă pentru L3 sau R3</string>
|
||||
<string name="ctrl_adaptive">Manșe adaptive</string>
|
||||
<string name="ctrl_rumble">Vibrații de joc</string>
|
||||
<string name="ctrl_dead_zone">Zonă moartă a manetei</string>
|
||||
<string name="ctrl_steam_button">Butonul Steam</string>
|
||||
<string name="ctrl_qam_button">Butonul QAM</string>
|
||||
<string name="ctrl_keyboard_button">Butonul tastaturii</string>
|
||||
<string name="ctrl_select_steam">Apasă Select pentru a deschide meniul Steam</string>
|
||||
<string name="ctrl_select_steam_hint">În loc de View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con ca controllere VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">Cât timp rulează SteamVR, fiecare Joy-Con devine o mână. Îndreaptă-l înainte și ține apăsat Home sau Capture pentru a-l recentra.</string>
|
||||
<string name="setup_animations">Animații</string>
|
||||
<string name="ctrl_adaptive_hint">Manșele apar unde atingi ecranul și se ascund la eliberare</string>
|
||||
<string name="ctrl_layout">Aranjament</string>
|
||||
<string name="ctrl_layout_custom">Poziții personalizate salvate</string>
|
||||
<string name="ctrl_layout_default">Adaptat pentru acest ecran</string>
|
||||
<string name="ctrl_edit">Editează</string>
|
||||
<string name="ctrl_reset">Resetează</string>
|
||||
<string name="ctrl_mapping">Maparea butoanelor</string>
|
||||
<string name="ctrl_mapping_default">Fiecare buton trimite propria intrare</string>
|
||||
<string name="ctrl_mapping_count">%1$d din %2$d butoane remapate</string>
|
||||
<string name="ctrl_configure">Configurează</string>
|
||||
<string name="ctrl_reset_all">Resetează controllerul</string>
|
||||
<string name="ctrl_reset_all_hint">Restaurează toate setările controllerului și aranjamentul</string>
|
||||
<string name="ctrl_mapping_lede">Ce trimite jocului fiecare buton de pe ecran. Ascuns elimină butonul.</string>
|
||||
<string name="ctrl_onscreen_buttons">Butoane pe ecran</string>
|
||||
<string name="ctrl_defaults">Valori implicite</string>
|
||||
<string name="ctrl_reset_mapping">Resetează maparea</string>
|
||||
<string name="content_android_apps">Aplicații Android</string>
|
||||
<string name="content_apps_count">%1$d aplicații</string>
|
||||
<string name="content_no_android_apps">Nu s-a găsit nicio aplicație Android care poate fi lansată.</string>
|
||||
@@ -1274,15 +1237,8 @@
|
||||
<string name="deck_surface_stick">Manșă</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Comută între manșă și trackpad</string>
|
||||
<string name="deck_more_controls">Mai multe comenzi Deck</string>
|
||||
<string name="deck_panels">PANOURI</string>
|
||||
<string name="deck_close">Închide comenzile celui de-al doilea ecran</string>
|
||||
<string name="deck_open_steam_menu">Deschide meniul Steam</string>
|
||||
<string name="deck_left_upper">Stânga · sus</string>
|
||||
<string name="deck_left_lower">Stânga · jos</string>
|
||||
<string name="deck_right_upper">Dreapta · sus</string>
|
||||
<string name="deck_right_lower">Dreapta · jos</string>
|
||||
<string name="deck_click">Clic</string>
|
||||
<string name="deck_right_trackpad">Trackpad-ul drept</string>
|
||||
<string name="deck_left_trackpad">Trackpad-ul stâng</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1831,9 +1787,7 @@
|
||||
<string name="ctrl_target_left">D-pad stânga</string>
|
||||
<string name="ctrl_target_right">D-pad dreapta</string>
|
||||
<string name="ctrl_target_hidden">Ascuns</string>
|
||||
<string name="ctrl_editor_drag">Trage pentru a mișca</string>
|
||||
<string name="ctrl_editor_snap">Aliniere</string>
|
||||
<string name="ctrl_editor_save">Salvează</string>
|
||||
<string name="second_mode_none">Niciunul</string>
|
||||
<string name="second_mode_keyboard_trackpad">Tastatură + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2684,7 +2638,6 @@
|
||||
<string name="gog_achievements_unavailable">Realizări indisponibile; verifică jurnalele sesiunii</string>
|
||||
<string name="achievement_unlocked">Realizare deblocată</string>
|
||||
<string name="touch_paste">Inserează</string>
|
||||
<string name="touch_dpad">Cruce directională</string>
|
||||
<string name="touch_left_stick">Stick stânga</string>
|
||||
<string name="touch_right_stick">Stick dreapta</string>
|
||||
<string name="touch_menu">Meniu</string>
|
||||
@@ -3741,4 +3694,7 @@
|
||||
<string name="addons_none_found">Nu s-au găsit suplimente</string>
|
||||
<string name="addons_unreachable">Nu s-a putut accesa %1$s</string>
|
||||
<string name="addons_no_file">Nu există fișier pentru această versiune a jocului</string>
|
||||
<string name="input_reset_positions">Resetează pozițiile</string>
|
||||
<string name="input_show_label">Afișează eticheta</string>
|
||||
<string name="input_layout_import_failed">Acest aranjament nu a putut fi importat</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Сенсорное управление Steam (бета)</string>
|
||||
<string name="osc_style_next_session">Сенсорное управление Steam включится со следующей сессии Steam</string>
|
||||
<string name="osc_steam_layout">Сенсорная раскладка Steam</string>
|
||||
<string name="screen_keys">Экранные клавиши</string>
|
||||
<string name="screen_keys_add">Добавить клавишу</string>
|
||||
<string name="screen_key_text">Текст</string>
|
||||
<string name="screen_key_size">Размер</string>
|
||||
<string name="screen_key_opacity">Непрозрачность</string>
|
||||
<string name="screen_key_type_button">Клавиша</string>
|
||||
<string name="screen_key_shape_trigger">Триггер</string>
|
||||
<string name="screen_key_toggle">Переключение</string>
|
||||
<string name="screen_key_layout_export">Экспорт</string>
|
||||
<string name="screen_key_shape_pill">Капсула</string>
|
||||
<string name="screen_key_shape_round">Скругление</string>
|
||||
<string name="screen_key_shape_circle">Круг</string>
|
||||
<string name="screen_key_shape_rect">Прямоугольник</string>
|
||||
<string name="screen_key_bind">Клавиша</string>
|
||||
<string name="screen_key_image">Изображение</string>
|
||||
<string name="screen_key_image_clear">Очистить</string>
|
||||
<string name="screen_key_layout">Раскладка</string>
|
||||
<string name="screen_key_layout_save">Сохранить</string>
|
||||
<string name="osc_steam_layout_hint">Перемещайте, меняйте размер или скрывайте сенсорные кнопки этой игры; сохраняется в Steam</string>
|
||||
<string name="mode_controller">Контроллер</string>
|
||||
<string name="mode_controller_hint">Как Steam распознает ваш контроллер. Вступит в силу в следующей сессии.</string>
|
||||
@@ -791,7 +775,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Автоматически</string>
|
||||
<string name="drawer_relative_mouse_on">Включено</string>
|
||||
<string name="drawer_relative_mouse_off">Выключено</string>
|
||||
<string name="drawer_direct_cursor">Курсор</string>
|
||||
<string name="drawer_pc_keyboard">Клавиатура ПК</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Второй экран</string>
|
||||
@@ -1160,43 +1143,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB на ПК (крайняя мера)</string>
|
||||
<string name="wadb_only_if">Используйте только если отладка по Wi-Fi недоступна.</string>
|
||||
<string name="wadb_computer_group">3 · ADB на ПК (крайняя мера)</string>
|
||||
<string name="ctrl_osc_hint">Когда показывать экранные элементы управления в сессии</string>
|
||||
<string name="ctrl_color">Цвет</string>
|
||||
<string name="ctrl_color_hint">Оттенок экранных кнопок</string>
|
||||
<string name="ctrl_custom">Пользовательский</string>
|
||||
<string name="ctrl_opacity">Непрозрачность</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Размер кнопок</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% — стандартный размер</string>
|
||||
<string name="ctrl_stick_click">Нажатие стика</string>
|
||||
<string name="ctrl_stick_click_hint">Дважды нажмите и удерживайте стик для L3 или R3</string>
|
||||
<string name="ctrl_adaptive">Адаптивные стики</string>
|
||||
<string name="ctrl_rumble">Вибрация в играх</string>
|
||||
<string name="ctrl_dead_zone">Мёртвая зона стика</string>
|
||||
<string name="ctrl_steam_button">Кнопка Steam</string>
|
||||
<string name="ctrl_qam_button">Кнопка QAM</string>
|
||||
<string name="ctrl_keyboard_button">Кнопка клавиатуры</string>
|
||||
<string name="ctrl_select_steam">Нажмите Select, чтобы открыть меню Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Вместо View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con как VR-контроллеры</string>
|
||||
<string name="ctrl_joycon_vr_hint">Пока работает SteamVR, каждый Joy-Con становится рукой. Направьте его вперёд и удерживайте Home или Capture, чтобы снова его отцентрировать.</string>
|
||||
<string name="setup_animations">Анимации</string>
|
||||
<string name="ctrl_adaptive_hint">Стики появляются в месте касания и исчезают после отпускания</string>
|
||||
<string name="ctrl_layout">Раскладка</string>
|
||||
<string name="ctrl_layout_custom">Сохранено свое расположение</string>
|
||||
<string name="ctrl_layout_default">Адаптировано под этот экран</string>
|
||||
<string name="ctrl_edit">Изменить</string>
|
||||
<string name="ctrl_reset">Сбросить</string>
|
||||
<string name="ctrl_mapping">Назначение кнопок</string>
|
||||
<string name="ctrl_mapping_default">Каждая кнопка отправляет свой ввод</string>
|
||||
<string name="ctrl_mapping_count">Переназначено кнопок: %1$d из %2$d</string>
|
||||
<string name="ctrl_configure">Настроить</string>
|
||||
<string name="ctrl_reset_all">Сбросить контроллер</string>
|
||||
<string name="ctrl_reset_all_hint">Восстанавливает все настройки контроллера и раскладку</string>
|
||||
<string name="ctrl_mapping_lede">Что каждая экранная кнопка отправляет в игру. Значение «Скрыто» убирает кнопку.</string>
|
||||
<string name="ctrl_onscreen_buttons">Экранные кнопки</string>
|
||||
<string name="ctrl_defaults">По умолчанию</string>
|
||||
<string name="ctrl_reset_mapping">Сбросить назначение</string>
|
||||
<string name="content_android_apps">Приложения Android</string>
|
||||
<string name="content_apps_count">Приложений: %1$d</string>
|
||||
<string name="content_no_android_apps">Не найдено приложений Android для запуска.</string>
|
||||
@@ -1318,15 +1281,8 @@
|
||||
<string name="deck_surface_stick">Стик</string>
|
||||
<string name="deck_surface_trackpad">Тачпад</string>
|
||||
<string name="deck_surface_switch">Переключение между стиком и тачпадом</string>
|
||||
<string name="deck_more_controls">Другие элементы управления Deck</string>
|
||||
<string name="deck_panels">ПАНЕЛИ</string>
|
||||
<string name="deck_close">Закрыть управление вторым экраном</string>
|
||||
<string name="deck_open_steam_menu">Открыть меню Steam</string>
|
||||
<string name="deck_left_upper">Слева · сверху</string>
|
||||
<string name="deck_left_lower">Слева · снизу</string>
|
||||
<string name="deck_right_upper">Справа · сверху</string>
|
||||
<string name="deck_right_lower">Справа · снизу</string>
|
||||
<string name="deck_click">Клик</string>
|
||||
<string name="deck_right_trackpad">Правый тачпад</string>
|
||||
<string name="deck_left_trackpad">Левый тачпад</string>
|
||||
<string name="second_trackpad">Тачпад</string>
|
||||
@@ -1901,9 +1857,7 @@
|
||||
<string name="ctrl_target_left">Крестовина влево</string>
|
||||
<string name="ctrl_target_right">Крестовина вправо</string>
|
||||
<string name="ctrl_target_hidden">Скрыто</string>
|
||||
<string name="ctrl_editor_drag">Перетащите для перемещения</string>
|
||||
<string name="ctrl_editor_snap">Привязка</string>
|
||||
<string name="ctrl_editor_save">Сохранить</string>
|
||||
<string name="second_mode_none">Ничего</string>
|
||||
<string name="second_mode_keyboard_trackpad">Клавиатура + тачпад</string>
|
||||
<string name="second_mode_terminal">Терминал</string>
|
||||
@@ -2791,7 +2745,6 @@
|
||||
<string name="gog_achievements_unavailable">Достижения недоступны; проверьте журналы сессии</string>
|
||||
<string name="achievement_unlocked">Достижение открыто</string>
|
||||
<string name="touch_paste">Вставить</string>
|
||||
<string name="touch_dpad">Крестовина</string>
|
||||
<string name="touch_left_stick">Левый стик</string>
|
||||
<string name="touch_right_stick">Правый стик</string>
|
||||
<string name="touch_menu">Меню</string>
|
||||
@@ -3863,4 +3816,7 @@
|
||||
<string name="addons_none_found">Аддоны не найдены</string>
|
||||
<string name="addons_unreachable">Не удалось подключиться к %1$s</string>
|
||||
<string name="addons_no_file">Нет файла для этой версии игры</string>
|
||||
<string name="input_reset_positions">Сбросить положение</string>
|
||||
<string name="input_show_label">Показывать подпись</string>
|
||||
<string name="input_layout_import_failed">Не удалось импортировать эту раскладку</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam-pekstyrning (beta)</string>
|
||||
<string name="osc_style_next_session">Steams pekstyrning startar med nästa Steam-session</string>
|
||||
<string name="osc_steam_layout">Steams peklayout</string>
|
||||
<string name="screen_keys">Skärmtangenter</string>
|
||||
<string name="screen_keys_add">Lägg till tangent</string>
|
||||
<string name="screen_key_text">Text</string>
|
||||
<string name="screen_key_size">Storlek</string>
|
||||
<string name="screen_key_opacity">Opacitet</string>
|
||||
<string name="screen_key_type_button">Tangent</string>
|
||||
<string name="screen_key_shape_trigger">Avtryckare</string>
|
||||
<string name="screen_key_toggle">Växla</string>
|
||||
<string name="screen_key_layout_export">Exportera</string>
|
||||
<string name="screen_key_shape_pill">Kapsel</string>
|
||||
<string name="screen_key_shape_round">Rundad</string>
|
||||
<string name="screen_key_shape_circle">Cirkel</string>
|
||||
<string name="screen_key_shape_rect">Rektangel</string>
|
||||
<string name="screen_key_bind">Tangent</string>
|
||||
<string name="screen_key_image">Bild</string>
|
||||
<string name="screen_key_image_clear">Rensa</string>
|
||||
<string name="screen_key_layout">Layout</string>
|
||||
<string name="screen_key_layout_save">Spara</string>
|
||||
<string name="osc_steam_layout_hint">Flytta, ändra storlek på eller dölj spelets pekkontroller; sparas i Steam</string>
|
||||
<string name="mode_controller">Handkontroll</string>
|
||||
<string name="mode_controller_hint">Hur Steam ser din handkontroll. Gäller från nästa session.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Automatiskt</string>
|
||||
<string name="drawer_relative_mouse_on">På</string>
|
||||
<string name="drawer_relative_mouse_off">Av</string>
|
||||
<string name="drawer_direct_cursor">Markör</string>
|
||||
<string name="drawer_pc_keyboard">PC-tangentbord</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Andra skärmen</string>
|
||||
@@ -1111,43 +1094,23 @@
|
||||
<string name="wadb_computer_last">3 · Dator-ADB (sista utväg)</string>
|
||||
<string name="wadb_only_if">Bara om Trådlös felsökning inte är tillgänglig.</string>
|
||||
<string name="wadb_computer_group">3 · Dator-ADB (sista utväg)</string>
|
||||
<string name="ctrl_osc_hint">När skärmkontrollerna visas i en session</string>
|
||||
<string name="ctrl_color">Färg</string>
|
||||
<string name="ctrl_color_hint">Nyans på skärmknapparna</string>
|
||||
<string name="ctrl_custom">Anpassad</string>
|
||||
<string name="ctrl_opacity">Opacitet</string>
|
||||
<string name="ctrl_percent">%1$d %%</string>
|
||||
<string name="ctrl_size">Knappstorlek</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100 % är standardstorleken</string>
|
||||
<string name="ctrl_stick_click">Spakklick</string>
|
||||
<string name="ctrl_stick_click_hint">Dubbeltryck och håll en spak för L3 eller R3</string>
|
||||
<string name="ctrl_adaptive">Adaptiva spakar</string>
|
||||
<string name="ctrl_rumble">Spelvibration</string>
|
||||
<string name="ctrl_dead_zone">Styrspakens dödzon</string>
|
||||
<string name="ctrl_steam_button">Steam-knappen</string>
|
||||
<string name="ctrl_qam_button">QAM-knappen</string>
|
||||
<string name="ctrl_keyboard_button">Tangentbordsknappen</string>
|
||||
<string name="ctrl_select_steam">Tryck på Select för att öppna Steam-menyn</string>
|
||||
<string name="ctrl_select_steam_hint">I stället för View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con som VR-handkontroller</string>
|
||||
<string name="ctrl_joycon_vr_hint">Medan SteamVR körs blir varje Joy-Con en hand. Rikta den framåt och håll in Home eller Capture för att centrera den igen.</string>
|
||||
<string name="setup_animations">Animationer</string>
|
||||
<string name="ctrl_adaptive_hint">Spakarna visas där du trycker och döljs när du släpper</string>
|
||||
<string name="ctrl_layout">Layout</string>
|
||||
<string name="ctrl_layout_custom">Anpassade positioner sparade</string>
|
||||
<string name="ctrl_layout_default">Anpassad till den här skärmen</string>
|
||||
<string name="ctrl_edit">Redigera</string>
|
||||
<string name="ctrl_reset">Återställ</string>
|
||||
<string name="ctrl_mapping">Knappmappning</string>
|
||||
<string name="ctrl_mapping_default">Varje knapp skickar sin egen inmatning</string>
|
||||
<string name="ctrl_mapping_count">%1$d av %2$d knappar ommappade</string>
|
||||
<string name="ctrl_configure">Konfigurera</string>
|
||||
<string name="ctrl_reset_all">Återställ handkontroll</string>
|
||||
<string name="ctrl_reset_all_hint">Återställer alla handkontrollsinställningar och layouten</string>
|
||||
<string name="ctrl_mapping_lede">Vad varje skärmknapp skickar till spelet. Dold tar bort knappen.</string>
|
||||
<string name="ctrl_onscreen_buttons">Skärmknappar</string>
|
||||
<string name="ctrl_defaults">Standardvärden</string>
|
||||
<string name="ctrl_reset_mapping">Återställ mappning</string>
|
||||
<string name="content_android_apps">Android-appar</string>
|
||||
<string name="content_apps_count">%1$d appar</string>
|
||||
<string name="content_no_android_apps">Inga startbara Android-appar hittades.</string>
|
||||
@@ -1267,15 +1230,8 @@
|
||||
<string name="deck_surface_stick">Styrspak</string>
|
||||
<string name="deck_surface_trackpad">Styrplatta</string>
|
||||
<string name="deck_surface_switch">Växla mellan styrspak och styrplatta</string>
|
||||
<string name="deck_more_controls">Fler Deck-kontroller</string>
|
||||
<string name="deck_panels">PANELER</string>
|
||||
<string name="deck_close">Stäng kontrollerna på andra skärmen</string>
|
||||
<string name="deck_open_steam_menu">Öppna Steam-menyn</string>
|
||||
<string name="deck_left_upper">Vänster · övre</string>
|
||||
<string name="deck_left_lower">Vänster · nedre</string>
|
||||
<string name="deck_right_upper">Höger · övre</string>
|
||||
<string name="deck_right_lower">Höger · nedre</string>
|
||||
<string name="deck_click">Klick</string>
|
||||
<string name="deck_right_trackpad">Höger styrplatta</string>
|
||||
<string name="deck_left_trackpad">Vänster styrplatta</string>
|
||||
<string name="second_trackpad">Styrplatta</string>
|
||||
@@ -1807,9 +1763,7 @@
|
||||
<string name="ctrl_target_left">D-pad vänster</string>
|
||||
<string name="ctrl_target_right">D-pad höger</string>
|
||||
<string name="ctrl_target_hidden">Dold</string>
|
||||
<string name="ctrl_editor_drag">Dra för att flytta</string>
|
||||
<string name="ctrl_editor_snap">Fäst</string>
|
||||
<string name="ctrl_editor_save">Spara</string>
|
||||
<string name="second_mode_none">Inget</string>
|
||||
<string name="second_mode_keyboard_trackpad">Tangentbord + styrplatta</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2657,7 +2611,6 @@
|
||||
<string name="gog_achievements_unavailable">Prestationer inte tillgängliga; kontrollera sessionsloggarna</string>
|
||||
<string name="achievement_unlocked">Prestation upplåst</string>
|
||||
<string name="touch_paste">Klistra in</string>
|
||||
<string name="touch_dpad">Styrkors</string>
|
||||
<string name="touch_left_stick">Vänster styrspak</string>
|
||||
<string name="touch_right_stick">Höger styrspak</string>
|
||||
<string name="touch_menu">Meny</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Inga tillägg hittades</string>
|
||||
<string name="addons_unreachable">Kunde inte nå %1$s</string>
|
||||
<string name="addons_no_file">Ingen fil för den här spelversionen</string>
|
||||
<string name="input_reset_positions">Återställ positioner</string>
|
||||
<string name="input_show_label">Visa etikett</string>
|
||||
<string name="input_layout_import_failed">Det gick inte att importera layouten</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">การสัมผัสของ Steam (ทดลอง)</string>
|
||||
<string name="osc_style_next_session">ปุ่มสัมผัสของ Steam จะเริ่มใช้งานในเซสชัน Steam ถัดไป</string>
|
||||
<string name="osc_steam_layout">รูปแบบปุ่มสัมผัสของ Steam</string>
|
||||
<string name="screen_keys">ปุ่มบนหน้าจอ</string>
|
||||
<string name="screen_keys_add">เพิ่มปุ่ม</string>
|
||||
<string name="screen_key_text">ข้อความ</string>
|
||||
<string name="screen_key_size">ขนาด</string>
|
||||
<string name="screen_key_opacity">ความโปร่งใส</string>
|
||||
<string name="screen_key_type_button">ปุ่ม</string>
|
||||
<string name="screen_key_shape_trigger">ไก</string>
|
||||
<string name="screen_key_toggle">สลับ</string>
|
||||
<string name="screen_key_layout_export">ส่งออก</string>
|
||||
<string name="screen_key_shape_pill">แคปซูล</string>
|
||||
<string name="screen_key_shape_round">มน</string>
|
||||
<string name="screen_key_shape_circle">วงกลม</string>
|
||||
<string name="screen_key_shape_rect">สี่เหลี่ยม</string>
|
||||
<string name="screen_key_bind">ปุ่ม</string>
|
||||
<string name="screen_key_image">รูปภาพ</string>
|
||||
<string name="screen_key_image_clear">ล้าง</string>
|
||||
<string name="screen_key_layout">การจัดวาง</string>
|
||||
<string name="screen_key_layout_save">บันทึก</string>
|
||||
<string name="osc_steam_layout_hint">ย้าย ปรับขนาด หรือซ่อนปุ่มสัมผัสของเกมนี้ บันทึกไปยัง Steam</string>
|
||||
<string name="mode_controller">คอนโทรลเลอร์</string>
|
||||
<string name="mode_controller_hint">วิธีที่ Steam มองเห็นคอนโทรลเลอร์ของคุณ จะมีผลในเซสชันถัดไป</string>
|
||||
@@ -766,7 +750,6 @@
|
||||
<string name="drawer_relative_mouse_auto">อัตโนมัติ</string>
|
||||
<string name="drawer_relative_mouse_on">เปิด</string>
|
||||
<string name="drawer_relative_mouse_off">ปิด</string>
|
||||
<string name="drawer_direct_cursor">เคอร์เซอร์</string>
|
||||
<string name="drawer_pc_keyboard">แป้นพิมพ์พีซี</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">หน้าจอที่สอง</string>
|
||||
@@ -1105,43 +1088,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB จากคอมพิวเตอร์ (ทางเลือกสุดท้าย)</string>
|
||||
<string name="wadb_only_if">ใช้เฉพาะเมื่อ Wireless debugging ใช้งานไม่ได้</string>
|
||||
<string name="wadb_computer_group">3 · ADB จากคอมพิวเตอร์ (ทางเลือกสุดท้าย)</string>
|
||||
<string name="ctrl_osc_hint">เมื่อปุ่มสัมผัสจะปรากฏในเซสชัน</string>
|
||||
<string name="ctrl_color">สี</string>
|
||||
<string name="ctrl_color_hint">สีของปุ่มบนหน้าจอ</string>
|
||||
<string name="ctrl_custom">กำหนดเอง</string>
|
||||
<string name="ctrl_opacity">ความโปร่งใส</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">ขนาดปุ่ม</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% คือขนาดมาตรฐาน</string>
|
||||
<string name="ctrl_stick_click">การกดสติ๊ก</string>
|
||||
<string name="ctrl_stick_click_hint">แตะสองครั้งแล้วกดสติ๊กค้างไว้สำหรับ L3 หรือ R3</string>
|
||||
<string name="ctrl_adaptive">สติ๊กแบบปรับอัตโนมัติ</string>
|
||||
<string name="ctrl_rumble">การสั่นของเกม</string>
|
||||
<string name="ctrl_dead_zone">เดดโซนของแอนะล็อกสติ๊ก</string>
|
||||
<string name="ctrl_steam_button">ปุ่ม Steam</string>
|
||||
<string name="ctrl_qam_button">ปุ่ม QAM</string>
|
||||
<string name="ctrl_keyboard_button">ปุ่มแป้นพิมพ์</string>
|
||||
<string name="ctrl_select_steam">กด Select เพื่อเปิดเมนู Steam</string>
|
||||
<string name="ctrl_select_steam_hint">แทน View/Select</string>
|
||||
<string name="ctrl_joycon_vr">ใช้ Joy-Con เป็นคอนโทรลเลอร์ VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">ขณะที่ SteamVR ทำงาน Joy-Con แต่ละตัวจะกลายเป็นมือ ชี้ไปข้างหน้าแล้วกด Home หรือ Capture ค้างไว้เพื่อจัดให้อยู่ตรงกลางอีกครั้ง</string>
|
||||
<string name="setup_animations">ภาพเคลื่อนไหว</string>
|
||||
<string name="ctrl_adaptive_hint">สติ๊กจะปรากฏที่ตำแหน่งที่คุณแตะและซ่อนเมื่อปล่อย</string>
|
||||
<string name="ctrl_layout">การจัดวาง</string>
|
||||
<string name="ctrl_layout_custom">บันทึกตำแหน่งกำหนดเองไว้แล้ว</string>
|
||||
<string name="ctrl_layout_default">ปรับให้พอดีกับหน้าจอนี้</string>
|
||||
<string name="ctrl_edit">แก้ไข</string>
|
||||
<string name="ctrl_reset">รีเซ็ต</string>
|
||||
<string name="ctrl_mapping">การกำหนดปุ่ม</string>
|
||||
<string name="ctrl_mapping_default">ทุกปุ่มส่งอินพุตของตัวเอง</string>
|
||||
<string name="ctrl_mapping_count">กำหนดใหม่ %1$d จาก %2$d ปุ่ม</string>
|
||||
<string name="ctrl_configure">ตั้งค่า</string>
|
||||
<string name="ctrl_reset_all">รีเซ็ตคอนโทรลเลอร์</string>
|
||||
<string name="ctrl_reset_all_hint">คืนค่าการตั้งค่าคอนโทรลเลอร์ทั้งหมดและการจัดวาง</string>
|
||||
<string name="ctrl_mapping_lede">สิ่งที่ปุ่มบนหน้าจอแต่ละปุ่มส่งไปยังเกม ซ่อนจะเอาปุ่มนั้นออก</string>
|
||||
<string name="ctrl_onscreen_buttons">ปุ่มบนหน้าจอ</string>
|
||||
<string name="ctrl_defaults">ค่าเริ่มต้น</string>
|
||||
<string name="ctrl_reset_mapping">รีเซ็ตการกำหนดปุ่ม</string>
|
||||
<string name="content_android_apps">แอป Android</string>
|
||||
<string name="content_apps_count">%1$d แอป</string>
|
||||
<string name="content_no_android_apps">ไม่พบแอป Android ที่เปิดได้</string>
|
||||
@@ -1260,15 +1223,8 @@
|
||||
<string name="deck_surface_stick">สติ๊ก</string>
|
||||
<string name="deck_surface_trackpad">แทร็กแพด</string>
|
||||
<string name="deck_surface_switch">สลับระหว่างสติ๊กและแทร็กแพด</string>
|
||||
<string name="deck_more_controls">การควบคุม Deck เพิ่มเติม</string>
|
||||
<string name="deck_panels">แผง</string>
|
||||
<string name="deck_close">ปิดการควบคุมหน้าจอที่สอง</string>
|
||||
<string name="deck_open_steam_menu">เปิดเมนู Steam</string>
|
||||
<string name="deck_left_upper">ซ้าย · บน</string>
|
||||
<string name="deck_left_lower">ซ้าย · ล่าง</string>
|
||||
<string name="deck_right_upper">ขวา · บน</string>
|
||||
<string name="deck_right_lower">ขวา · ล่าง</string>
|
||||
<string name="deck_click">คลิก</string>
|
||||
<string name="deck_right_trackpad">แทร็กแพดขวา</string>
|
||||
<string name="deck_left_trackpad">แทร็กแพดซ้าย</string>
|
||||
<string name="second_trackpad">แทร็กแพด</string>
|
||||
@@ -1783,9 +1739,7 @@
|
||||
<string name="ctrl_target_left">D-pad ซ้าย</string>
|
||||
<string name="ctrl_target_right">D-pad ขวา</string>
|
||||
<string name="ctrl_target_hidden">ซ่อน</string>
|
||||
<string name="ctrl_editor_drag">ลากเพื่อย้าย</string>
|
||||
<string name="ctrl_editor_snap">จัดให้พอดี</string>
|
||||
<string name="ctrl_editor_save">บันทึก</string>
|
||||
<string name="second_mode_none">ไม่มี</string>
|
||||
<string name="second_mode_keyboard_trackpad">แป้นพิมพ์ + แทร็กแพด</string>
|
||||
<string name="second_mode_terminal">เทอร์มินัล</string>
|
||||
@@ -2630,7 +2584,6 @@
|
||||
<string name="gog_achievements_unavailable">ไม่พบความสำเร็จ ตรวจสอบบันทึกเซสชัน</string>
|
||||
<string name="achievement_unlocked">ปลดล็อกความสำเร็จแล้ว</string>
|
||||
<string name="touch_paste">วาง</string>
|
||||
<string name="touch_dpad">ปุ่มกากบาท</string>
|
||||
<string name="touch_left_stick">อนาล็อกซ้าย</string>
|
||||
<string name="touch_right_stick">อนาล็อกขวา</string>
|
||||
<string name="touch_menu">เมนู</string>
|
||||
@@ -3672,4 +3625,7 @@
|
||||
<string name="addons_none_found">ไม่พบแอดออน</string>
|
||||
<string name="addons_unreachable">ไม่สามารถเชื่อมต่อ %1$s ได้</string>
|
||||
<string name="addons_no_file">ไม่มีไฟล์สำหรับเกมเวอร์ชันนี้</string>
|
||||
<string name="input_reset_positions">รีเซ็ตตำแหน่ง</string>
|
||||
<string name="input_show_label">แสดงป้ายกำกับ</string>
|
||||
<string name="input_layout_import_failed">ไม่สามารถนำเข้าการจัดวางนี้ได้</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam dokunmatik (beta)</string>
|
||||
<string name="osc_style_next_session">Steam\'in dokunmatik kontrolleri sonraki Steam oturumunda başlar</string>
|
||||
<string name="osc_steam_layout">Steam dokunmatik düzeni</string>
|
||||
<string name="screen_keys">Ekran tuşları</string>
|
||||
<string name="screen_keys_add">Tuş ekle</string>
|
||||
<string name="screen_key_text">Metin</string>
|
||||
<string name="screen_key_size">Boyut</string>
|
||||
<string name="screen_key_opacity">Opaklık</string>
|
||||
<string name="screen_key_type_button">Tuş</string>
|
||||
<string name="screen_key_shape_trigger">Tetik</string>
|
||||
<string name="screen_key_toggle">Aç/Kapa</string>
|
||||
<string name="screen_key_layout_export">Dışa aktar</string>
|
||||
<string name="screen_key_shape_pill">Kapsül</string>
|
||||
<string name="screen_key_shape_round">Yuvarlak</string>
|
||||
<string name="screen_key_shape_circle">Daire</string>
|
||||
<string name="screen_key_shape_rect">Dikdörtgen</string>
|
||||
<string name="screen_key_bind">Tuş</string>
|
||||
<string name="screen_key_image">Görsel</string>
|
||||
<string name="screen_key_image_clear">Temizle</string>
|
||||
<string name="screen_key_layout">Düzen</string>
|
||||
<string name="screen_key_layout_save">Kaydet</string>
|
||||
<string name="osc_steam_layout_hint">Bu oyunun dokunmatik kontrollerini taşıyın, boyutlandırın veya gizleyin; Steam\'e kaydedilir</string>
|
||||
<string name="mode_controller">Kumanda</string>
|
||||
<string name="mode_controller_hint">Steam\'in kumandanızı nasıl gördüğü. Sonraki oturumda uygulanır.</string>
|
||||
@@ -768,7 +752,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Otomatik</string>
|
||||
<string name="drawer_relative_mouse_on">Açık</string>
|
||||
<string name="drawer_relative_mouse_off">Kapalı</string>
|
||||
<string name="drawer_direct_cursor">İmleç</string>
|
||||
<string name="drawer_pc_keyboard">PC klavyesi</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">İkinci ekran</string>
|
||||
@@ -1103,43 +1086,23 @@
|
||||
<string name="wadb_computer_last">3 · Bilgisayardan ADB (son yöntem)</string>
|
||||
<string name="wadb_only_if">Yalnızca Kablosuz hata ayıklama kullanılamıyorsa.</string>
|
||||
<string name="wadb_computer_group">3 · Bilgisayardan ADB (son yöntem)</string>
|
||||
<string name="ctrl_osc_hint">Dokunmatik kontrollerin bir oturumda ne zaman görüneceği</string>
|
||||
<string name="ctrl_color">Renk</string>
|
||||
<string name="ctrl_color_hint">Ekrandaki düğmelerin rengi</string>
|
||||
<string name="ctrl_custom">Özel</string>
|
||||
<string name="ctrl_opacity">Opaklık</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Düğme boyutu</string>
|
||||
<string name="ctrl_size_hint" formatted="false">%100 standart boyuttur</string>
|
||||
<string name="ctrl_stick_click">Çubuk tıklaması</string>
|
||||
<string name="ctrl_stick_click_hint">L3 veya R3 için bir çubuğa çift dokunup basılı tutun</string>
|
||||
<string name="ctrl_adaptive">Uyarlanabilir çubuklar</string>
|
||||
<string name="ctrl_rumble">Oyun titreşimi</string>
|
||||
<string name="ctrl_dead_zone">Çubuk ölü bölgesi</string>
|
||||
<string name="ctrl_steam_button">Steam düğmesi</string>
|
||||
<string name="ctrl_qam_button">QAM düğmesi</string>
|
||||
<string name="ctrl_keyboard_button">Klavye düğmesi</string>
|
||||
<string name="ctrl_select_steam">Steam menüsünü açmak için Select\'e basın</string>
|
||||
<string name="ctrl_select_steam_hint">Görünüm/Select yerine.</string>
|
||||
<string name="ctrl_joycon_vr">VR kumandası olarak Joy-Con\'lar</string>
|
||||
<string name="ctrl_joycon_vr_hint">SteamVR çalışırken her Joy-Con bir el olur. Öne doğrultun ve yeniden ortalamak için Home veya Capture düğmesini basılı tutun.</string>
|
||||
<string name="setup_animations">Animasyonlar</string>
|
||||
<string name="ctrl_adaptive_hint">Çubuklar dokunduğunuz yerde görünür, bıraktığınızda gizlenir</string>
|
||||
<string name="ctrl_layout">Düzen</string>
|
||||
<string name="ctrl_layout_custom">Özel konumlar kaydedildi</string>
|
||||
<string name="ctrl_layout_default">Bu ekrana uyarlandı</string>
|
||||
<string name="ctrl_edit">Düzenle</string>
|
||||
<string name="ctrl_reset">Sıfırla</string>
|
||||
<string name="ctrl_mapping">Düğme eşlemesi</string>
|
||||
<string name="ctrl_mapping_default">Her düğme kendi girdisini gönderir</string>
|
||||
<string name="ctrl_mapping_count">%2$d düğmeden %1$d\'i yeniden eşlendi</string>
|
||||
<string name="ctrl_configure">Yapılandır</string>
|
||||
<string name="ctrl_reset_all">Kumandayı sıfırla</string>
|
||||
<string name="ctrl_reset_all_hint">Tüm kumanda ayarlarını ve düzeni geri yükler</string>
|
||||
<string name="ctrl_mapping_lede">Ekrandaki her düğmenin oyuna gönderdiği girdi. Gizli, düğmeyi kaldırır.</string>
|
||||
<string name="ctrl_onscreen_buttons">Ekrandaki düğmeler</string>
|
||||
<string name="ctrl_defaults">Varsayılanlar</string>
|
||||
<string name="ctrl_reset_mapping">Eşlemeyi sıfırla</string>
|
||||
<string name="content_android_apps">Android uygulamaları</string>
|
||||
<string name="content_apps_count">%1$d uygulama</string>
|
||||
<string name="content_no_android_apps">Başlatılabilir Android uygulaması bulunamadı.</string>
|
||||
@@ -1259,15 +1222,8 @@
|
||||
<string name="deck_surface_stick">Çubuk</string>
|
||||
<string name="deck_surface_trackpad">Dokunmatik yüzey</string>
|
||||
<string name="deck_surface_switch">Çubuk ile dokunmatik yüzey arasında geçiş yap</string>
|
||||
<string name="deck_more_controls">Diğer Deck kontrolleri</string>
|
||||
<string name="deck_panels">PANELLER</string>
|
||||
<string name="deck_close">İkinci ekran kontrollerini kapat</string>
|
||||
<string name="deck_open_steam_menu">Steam menüsünü aç</string>
|
||||
<string name="deck_left_upper">Sol · üst</string>
|
||||
<string name="deck_left_lower">Sol · alt</string>
|
||||
<string name="deck_right_upper">Sağ · üst</string>
|
||||
<string name="deck_right_lower">Sağ · alt</string>
|
||||
<string name="deck_click">Tıkla</string>
|
||||
<string name="deck_right_trackpad">Sağ dokunmatik yüzey</string>
|
||||
<string name="deck_left_trackpad">Sol dokunmatik yüzey</string>
|
||||
<string name="second_trackpad">Dokunmatik yüzey</string>
|
||||
@@ -1799,9 +1755,7 @@
|
||||
<string name="ctrl_target_left">Yön tuşu sol</string>
|
||||
<string name="ctrl_target_right">Yön tuşu sağ</string>
|
||||
<string name="ctrl_target_hidden">Gizli</string>
|
||||
<string name="ctrl_editor_drag">Taşımak için sürükleyin</string>
|
||||
<string name="ctrl_editor_snap">Hizala</string>
|
||||
<string name="ctrl_editor_save">Kaydet</string>
|
||||
<string name="second_mode_none">Hiçbiri</string>
|
||||
<string name="second_mode_keyboard_trackpad">Klavye + dokunmatik yüzey</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2646,7 +2600,6 @@
|
||||
<string name="gog_achievements_unavailable">Başarımlar kullanılamıyor; oturum günlüklerini kontrol et</string>
|
||||
<string name="achievement_unlocked">Başarımın kilidi açıldı</string>
|
||||
<string name="touch_paste">Yapıştır</string>
|
||||
<string name="touch_dpad">Yön tuşu</string>
|
||||
<string name="touch_left_stick">Sol analog çubuk</string>
|
||||
<string name="touch_right_stick">Sağ analog çubuk</string>
|
||||
<string name="touch_menu">Menü</string>
|
||||
@@ -3702,4 +3655,7 @@
|
||||
<string name="addons_none_found">Eklenti bulunamadı</string>
|
||||
<string name="addons_unreachable">%1$s adresine ulaşılamadı</string>
|
||||
<string name="addons_no_file">Bu oyun sürümü için dosya yok</string>
|
||||
<string name="input_reset_positions">Konumları sıfırla</string>
|
||||
<string name="input_show_label">Etiketi göster</string>
|
||||
<string name="input_layout_import_failed">Bu düzen içe aktarılamadı</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Сенсорне керування Steam (бета)</string>
|
||||
<string name="osc_style_next_session">Сенсорне керування Steam увімкнеться з наступним сеансом Steam</string>
|
||||
<string name="osc_steam_layout">Розкладка сенсорного керування Steam</string>
|
||||
<string name="screen_keys">Екранні клавіші</string>
|
||||
<string name="screen_keys_add">Додати клавішу</string>
|
||||
<string name="screen_key_text">Текст</string>
|
||||
<string name="screen_key_size">Розмір</string>
|
||||
<string name="screen_key_opacity">Непрозорість</string>
|
||||
<string name="screen_key_type_button">Клавіша</string>
|
||||
<string name="screen_key_shape_trigger">Тригер</string>
|
||||
<string name="screen_key_toggle">Перемикання</string>
|
||||
<string name="screen_key_layout_export">Експорт</string>
|
||||
<string name="screen_key_shape_pill">Капсула</string>
|
||||
<string name="screen_key_shape_round">Заокруглення</string>
|
||||
<string name="screen_key_shape_circle">Коло</string>
|
||||
<string name="screen_key_shape_rect">Прямокутник</string>
|
||||
<string name="screen_key_bind">Клавіша</string>
|
||||
<string name="screen_key_image">Зображення</string>
|
||||
<string name="screen_key_image_clear">Очистити</string>
|
||||
<string name="screen_key_layout">Розкладка</string>
|
||||
<string name="screen_key_layout_save">Зберегти</string>
|
||||
<string name="osc_steam_layout_hint">Переміщуйте, змінюйте розмір або приховуйте сенсорні елементи керування цієї гри; зберігається в Steam</string>
|
||||
<string name="mode_controller">Контролер</string>
|
||||
<string name="mode_controller_hint">Яким Steam бачить ваш контролер. Застосовується в наступному сеансі.</string>
|
||||
@@ -772,7 +756,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Автоматично</string>
|
||||
<string name="drawer_relative_mouse_on">Увімкнено</string>
|
||||
<string name="drawer_relative_mouse_off">Вимкнено</string>
|
||||
<string name="drawer_direct_cursor">Курсор</string>
|
||||
<string name="drawer_pc_keyboard">Клавіатура ПК</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Другий екран</string>
|
||||
@@ -1123,43 +1106,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB з комп’ютера (останній варіант)</string>
|
||||
<string name="wadb_only_if">Лише якщо бездротове налагодження недоступне.</string>
|
||||
<string name="wadb_computer_group">3 · ADB з комп’ютера (останній варіант)</string>
|
||||
<string name="ctrl_osc_hint">Коли сенсорне керування з’являється в сеансі</string>
|
||||
<string name="ctrl_color">Колір</string>
|
||||
<string name="ctrl_color_hint">Відтінок екранних кнопок</string>
|
||||
<string name="ctrl_custom">Власний</string>
|
||||
<string name="ctrl_opacity">Непрозорість</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Розмір кнопок</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% — стандартний розмір</string>
|
||||
<string name="ctrl_stick_click">Натискання стика</string>
|
||||
<string name="ctrl_stick_click_hint">Двічі торкніться і затримайте стик, щоб отримати L3 або R3</string>
|
||||
<string name="ctrl_adaptive">Адаптивні стики</string>
|
||||
<string name="ctrl_rumble">Вібрація гри</string>
|
||||
<string name="ctrl_dead_zone">Мертва зона стіка</string>
|
||||
<string name="ctrl_steam_button">Кнопка Steam</string>
|
||||
<string name="ctrl_qam_button">Кнопка QAM</string>
|
||||
<string name="ctrl_keyboard_button">Кнопка клавіатури</string>
|
||||
<string name="ctrl_select_steam">Натисніть Select, щоб відкрити меню Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Замість View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Con як VR-контролери</string>
|
||||
<string name="ctrl_joycon_vr_hint">Поки працює SteamVR, кожен Joy-Con стає рукою. Спрямуйте його вперед і утримуйте Home або Capture, щоб знову його відцентрувати.</string>
|
||||
<string name="setup_animations">Анімації</string>
|
||||
<string name="ctrl_adaptive_hint">Стики з’являються там, де ви торкаєтеся, і зникають після відпускання</string>
|
||||
<string name="ctrl_layout">Розкладка</string>
|
||||
<string name="ctrl_layout_custom">Збережено власне розташування</string>
|
||||
<string name="ctrl_layout_default">Підлаштовано під цей екран</string>
|
||||
<string name="ctrl_edit">Змінити</string>
|
||||
<string name="ctrl_reset">Скинути</string>
|
||||
<string name="ctrl_mapping">Призначення кнопок</string>
|
||||
<string name="ctrl_mapping_default">Кожна кнопка надсилає власне введення</string>
|
||||
<string name="ctrl_mapping_count">Перепризначено %1$d з %2$d кнопок</string>
|
||||
<string name="ctrl_configure">Налаштувати</string>
|
||||
<string name="ctrl_reset_all">Скинути контролер</string>
|
||||
<string name="ctrl_reset_all_hint">Відновлює всі налаштування контролера та розкладку</string>
|
||||
<string name="ctrl_mapping_lede">Що кожна екранна кнопка надсилає грі. «Приховано» прибирає кнопку.</string>
|
||||
<string name="ctrl_onscreen_buttons">Екранні кнопки</string>
|
||||
<string name="ctrl_defaults">Стандартні</string>
|
||||
<string name="ctrl_reset_mapping">Скинути призначення</string>
|
||||
<string name="content_android_apps">Додатки Android</string>
|
||||
<string name="content_apps_count">%1$d додатків</string>
|
||||
<string name="content_no_android_apps">Не знайдено жодного додатка Android для запуску.</string>
|
||||
@@ -1281,15 +1244,8 @@
|
||||
<string name="deck_surface_stick">Стік</string>
|
||||
<string name="deck_surface_trackpad">Трекпад</string>
|
||||
<string name="deck_surface_switch">Перемкнути між стіком і трекпадом</string>
|
||||
<string name="deck_more_controls">Більше елементів керування Deck</string>
|
||||
<string name="deck_panels">ПАНЕЛІ</string>
|
||||
<string name="deck_close">Закрити керування на другому екрані</string>
|
||||
<string name="deck_open_steam_menu">Відкрити меню Steam</string>
|
||||
<string name="deck_left_upper">Ліва · верхня</string>
|
||||
<string name="deck_left_lower">Ліва · нижня</string>
|
||||
<string name="deck_right_upper">Права · верхня</string>
|
||||
<string name="deck_right_lower">Права · нижня</string>
|
||||
<string name="deck_click">Натискання</string>
|
||||
<string name="deck_right_trackpad">Правий трекпад</string>
|
||||
<string name="deck_left_trackpad">Лівий трекпад</string>
|
||||
<string name="second_trackpad">Трекпад</string>
|
||||
@@ -1855,9 +1811,7 @@
|
||||
<string name="ctrl_target_left">Хрестовина вліво</string>
|
||||
<string name="ctrl_target_right">Хрестовина вправо</string>
|
||||
<string name="ctrl_target_hidden">Приховано</string>
|
||||
<string name="ctrl_editor_drag">Перетягніть, щоб перемістити</string>
|
||||
<string name="ctrl_editor_snap">Прив’язка</string>
|
||||
<string name="ctrl_editor_save">Зберегти</string>
|
||||
<string name="second_mode_none">Нічого</string>
|
||||
<string name="second_mode_keyboard_trackpad">Клавіатура + трекпад</string>
|
||||
<string name="second_mode_terminal">Термінал</string>
|
||||
@@ -2711,7 +2665,6 @@
|
||||
<string name="gog_achievements_unavailable">Досягнення недоступні; перевірте журнали сесії</string>
|
||||
<string name="achievement_unlocked">Досягнення відкрито</string>
|
||||
<string name="touch_paste">Вставити</string>
|
||||
<string name="touch_dpad">Хрестовина</string>
|
||||
<string name="touch_left_stick">Лівий стик</string>
|
||||
<string name="touch_right_stick">Правий стик</string>
|
||||
<string name="touch_menu">Меню</string>
|
||||
@@ -3780,4 +3733,7 @@
|
||||
<string name="addons_none_found">Аддонів не знайдено</string>
|
||||
<string name="addons_unreachable">Не вдалося під’єднатися до %1$s</string>
|
||||
<string name="addons_no_file">Немає файлу для цієї версії гри</string>
|
||||
<string name="input_reset_positions">Скинути розташування</string>
|
||||
<string name="input_show_label">Показувати підпис</string>
|
||||
<string name="input_layout_import_failed">Не вдалося імпортувати цю розкладку</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Chạm Steam (beta)</string>
|
||||
<string name="osc_style_next_session">Các nút chạm của Steam bắt đầu từ phiên Steam kế tiếp</string>
|
||||
<string name="osc_steam_layout">Bố cục chạm Steam</string>
|
||||
<string name="screen_keys">Phím trên màn hình</string>
|
||||
<string name="screen_keys_add">Thêm phím</string>
|
||||
<string name="screen_key_text">Văn bản</string>
|
||||
<string name="screen_key_size">Kích thước</string>
|
||||
<string name="screen_key_opacity">Độ mờ</string>
|
||||
<string name="screen_key_type_button">Phím</string>
|
||||
<string name="screen_key_shape_trigger">Cò</string>
|
||||
<string name="screen_key_toggle">Bật tắt</string>
|
||||
<string name="screen_key_layout_export">Xuất</string>
|
||||
<string name="screen_key_shape_pill">Viên nang</string>
|
||||
<string name="screen_key_shape_round">Bo tròn</string>
|
||||
<string name="screen_key_shape_circle">Tròn</string>
|
||||
<string name="screen_key_shape_rect">Chữ nhật</string>
|
||||
<string name="screen_key_bind">Phím</string>
|
||||
<string name="screen_key_image">Hình ảnh</string>
|
||||
<string name="screen_key_image_clear">Xóa</string>
|
||||
<string name="screen_key_layout">Bố cục</string>
|
||||
<string name="screen_key_layout_save">Lưu</string>
|
||||
<string name="osc_steam_layout_hint">Di chuyển, đổi kích thước hoặc ẩn các nút chạm của game này; được lưu vào Steam</string>
|
||||
<string name="mode_controller">Tay cầm</string>
|
||||
<string name="mode_controller_hint">Cách Steam nhận dạng tay cầm của bạn. Áp dụng từ phiên sau.</string>
|
||||
@@ -766,7 +750,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Tự động</string>
|
||||
<string name="drawer_relative_mouse_on">Bật</string>
|
||||
<string name="drawer_relative_mouse_off">Tắt</string>
|
||||
<string name="drawer_direct_cursor">Con trỏ</string>
|
||||
<string name="drawer_pc_keyboard">Bàn phím PC</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Màn hình thứ hai</string>
|
||||
@@ -1105,43 +1088,23 @@
|
||||
<string name="wadb_computer_last">3 · ADB từ máy tính (phương án cuối)</string>
|
||||
<string name="wadb_only_if">Chỉ khi Gỡ lỗi qua mạng không dây không khả dụng.</string>
|
||||
<string name="wadb_computer_group">3 · ADB từ máy tính (phương án cuối)</string>
|
||||
<string name="ctrl_osc_hint">Khi các nút điều khiển chạm xuất hiện trong một phiên</string>
|
||||
<string name="ctrl_color">Màu</string>
|
||||
<string name="ctrl_color_hint">Màu sắc của các nút trên màn hình</string>
|
||||
<string name="ctrl_custom">Tùy chỉnh</string>
|
||||
<string name="ctrl_opacity">Độ mờ</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Kích thước nút</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% là kích thước chuẩn</string>
|
||||
<string name="ctrl_stick_click">Nhấn cần</string>
|
||||
<string name="ctrl_stick_click_hint">Chạm hai lần và giữ một cần để dùng L3 hoặc R3</string>
|
||||
<string name="ctrl_adaptive">Cần thích ứng</string>
|
||||
<string name="ctrl_rumble">Rung khi chơi game</string>
|
||||
<string name="ctrl_dead_zone">Vùng chết của cần điều khiển</string>
|
||||
<string name="ctrl_steam_button">Nút Steam</string>
|
||||
<string name="ctrl_qam_button">Nút QAM</string>
|
||||
<string name="ctrl_keyboard_button">Nút bàn phím</string>
|
||||
<string name="ctrl_select_steam">Nhấn Select để mở menu Steam</string>
|
||||
<string name="ctrl_select_steam_hint">Thay cho View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Dùng Joy-Con làm tay cầm VR</string>
|
||||
<string name="ctrl_joycon_vr_hint">Khi SteamVR đang chạy, mỗi Joy-Con trở thành một bàn tay. Hướng nó về phía trước rồi giữ Home hoặc Capture để căn giữa lại.</string>
|
||||
<string name="setup_animations">Hiệu ứng chuyển động</string>
|
||||
<string name="ctrl_adaptive_hint">Cần xuất hiện ở nơi bạn chạm và ẩn khi thả ra</string>
|
||||
<string name="ctrl_layout">Bố cục</string>
|
||||
<string name="ctrl_layout_custom">Vị trí tùy chỉnh đã lưu</string>
|
||||
<string name="ctrl_layout_default">Vừa khớp với màn hình này</string>
|
||||
<string name="ctrl_edit">Sửa</string>
|
||||
<string name="ctrl_reset">Đặt lại</string>
|
||||
<string name="ctrl_mapping">Gán nút</string>
|
||||
<string name="ctrl_mapping_default">Mỗi nút gửi tín hiệu riêng của nó</string>
|
||||
<string name="ctrl_mapping_count">%1$d trong %2$d nút đã được gán lại</string>
|
||||
<string name="ctrl_configure">Cấu hình</string>
|
||||
<string name="ctrl_reset_all">Đặt lại tay cầm</string>
|
||||
<string name="ctrl_reset_all_hint">Khôi phục mọi thiết lập tay cầm và bố cục</string>
|
||||
<string name="ctrl_mapping_lede">Mỗi nút trên màn hình gửi gì đến game. Ẩn sẽ xóa nút đó.</string>
|
||||
<string name="ctrl_onscreen_buttons">Nút trên màn hình</string>
|
||||
<string name="ctrl_defaults">Mặc định</string>
|
||||
<string name="ctrl_reset_mapping">Đặt lại gán nút</string>
|
||||
<string name="content_android_apps">Ứng dụng Android</string>
|
||||
<string name="content_apps_count">%1$d ứng dụng</string>
|
||||
<string name="content_no_android_apps">Không tìm thấy ứng dụng Android nào có thể khởi chạy.</string>
|
||||
@@ -1260,15 +1223,8 @@
|
||||
<string name="deck_surface_stick">Cần</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Chuyển giữa cần và trackpad</string>
|
||||
<string name="deck_more_controls">Thêm điều khiển Deck</string>
|
||||
<string name="deck_panels">BẢNG</string>
|
||||
<string name="deck_close">Đóng điều khiển màn hình phụ</string>
|
||||
<string name="deck_open_steam_menu">Mở menu Steam</string>
|
||||
<string name="deck_left_upper">Trái · trên</string>
|
||||
<string name="deck_left_lower">Trái · dưới</string>
|
||||
<string name="deck_right_upper">Phải · trên</string>
|
||||
<string name="deck_right_lower">Phải · dưới</string>
|
||||
<string name="deck_click">Nhấn</string>
|
||||
<string name="deck_right_trackpad">Trackpad phải</string>
|
||||
<string name="deck_left_trackpad">Trackpad trái</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1783,9 +1739,7 @@
|
||||
<string name="ctrl_target_left">D-pad trái</string>
|
||||
<string name="ctrl_target_right">D-pad phải</string>
|
||||
<string name="ctrl_target_hidden">Ẩn</string>
|
||||
<string name="ctrl_editor_drag">Kéo để di chuyển</string>
|
||||
<string name="ctrl_editor_snap">Hít vào lưới (snap)</string>
|
||||
<string name="ctrl_editor_save">Lưu</string>
|
||||
<string name="second_mode_none">Không có</string>
|
||||
<string name="second_mode_keyboard_trackpad">Bàn phím + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2630,7 +2584,6 @@
|
||||
<string name="gog_achievements_unavailable">Không có thành tích; hãy kiểm tra nhật ký phiên</string>
|
||||
<string name="achievement_unlocked">Đã mở khóa thành tích</string>
|
||||
<string name="touch_paste">Dán</string>
|
||||
<string name="touch_dpad">Phím chữ thập</string>
|
||||
<string name="touch_left_stick">Cần analog trái</string>
|
||||
<string name="touch_right_stick">Cần analog phải</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3672,4 +3625,7 @@
|
||||
<string name="addons_none_found">Không tìm thấy addon</string>
|
||||
<string name="addons_unreachable">Không thể kết nối tới %1$s</string>
|
||||
<string name="addons_no_file">Không có tệp cho phiên bản trò chơi này</string>
|
||||
<string name="input_reset_positions">Đặt lại vị trí</string>
|
||||
<string name="input_show_label">Hiện nhãn</string>
|
||||
<string name="input_layout_import_failed">Không thể nhập bố cục này</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam 触控(测试版)</string>
|
||||
<string name="osc_style_next_session">Steam 的触控按键将从下次 Steam 会话开始生效</string>
|
||||
<string name="osc_steam_layout">Steam 触控布局</string>
|
||||
<string name="screen_keys">屏幕按键</string>
|
||||
<string name="screen_keys_add">添加按键</string>
|
||||
<string name="screen_key_text">文本</string>
|
||||
<string name="screen_key_size">大小</string>
|
||||
<string name="screen_key_opacity">透明</string>
|
||||
<string name="screen_key_type_button">单键</string>
|
||||
<string name="screen_key_shape_trigger">扳机</string>
|
||||
<string name="screen_key_toggle">切换</string>
|
||||
<string name="screen_key_layout_export">导出</string>
|
||||
<string name="screen_key_shape_pill">胶囊</string>
|
||||
<string name="screen_key_shape_round">圆角</string>
|
||||
<string name="screen_key_shape_circle">圆形</string>
|
||||
<string name="screen_key_shape_rect">矩形</string>
|
||||
<string name="screen_key_bind">绑定</string>
|
||||
<string name="screen_key_image">图片</string>
|
||||
<string name="screen_key_image_clear">清除</string>
|
||||
<string name="screen_key_layout">布局</string>
|
||||
<string name="screen_key_layout_save">保存</string>
|
||||
<string name="osc_steam_layout_hint">移动、调整大小或隐藏此游戏的触控按键;保存到 Steam</string>
|
||||
<string name="mode_controller">手柄</string>
|
||||
<string name="mode_controller_hint">决定 Steam 把你的手柄识别为哪种类型,将在下次会话生效。</string>
|
||||
@@ -766,7 +750,6 @@
|
||||
<string name="drawer_relative_mouse_auto">自动</string>
|
||||
<string name="drawer_relative_mouse_on">开</string>
|
||||
<string name="drawer_relative_mouse_off">关</string>
|
||||
<string name="drawer_direct_cursor">光标</string>
|
||||
<string name="drawer_pc_keyboard">PC 键盘</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">副屏</string>
|
||||
@@ -1189,43 +1172,23 @@
|
||||
<string name="wadb_computer_last">3 · 电脑 ADB(最后手段)</string>
|
||||
<string name="wadb_only_if">仅在无线调试不可用时使用。</string>
|
||||
<string name="wadb_computer_group">3 · 电脑 ADB(最后手段)</string>
|
||||
<string name="ctrl_osc_hint">会话中屏幕控制何时出现</string>
|
||||
<string name="ctrl_color">颜色</string>
|
||||
<string name="ctrl_color_hint">屏幕按钮的色调</string>
|
||||
<string name="ctrl_custom">自定义</string>
|
||||
<string name="ctrl_opacity">不透明度</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">按钮大小</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% 为标准大小</string>
|
||||
<string name="ctrl_stick_click">摇杆按击</string>
|
||||
<string name="ctrl_stick_click_hint">双击并按住摇杆可触发 L3 或 R3</string>
|
||||
<string name="ctrl_adaptive">自适应摇杆</string>
|
||||
<string name="ctrl_rumble">游戏震动</string>
|
||||
<string name="ctrl_dead_zone">摇杆死区</string>
|
||||
<string name="ctrl_steam_button">Steam 按钮</string>
|
||||
<string name="ctrl_qam_button">QAM 按钮</string>
|
||||
<string name="ctrl_keyboard_button">键盘按钮</string>
|
||||
<string name="ctrl_select_steam">按 Select 打开 Steam 菜单</string>
|
||||
<string name="ctrl_select_steam_hint">代替 View/Select。</string>
|
||||
<string name="ctrl_joycon_vr">将 Joy-Con 用作 VR 手柄</string>
|
||||
<string name="ctrl_joycon_vr_hint">SteamVR 运行时,每个 Joy-Con 都会成为一只手。将其指向前方并按住 HOME 键或截图键即可重新居中。</string>
|
||||
<string name="setup_animations">动画</string>
|
||||
<string name="ctrl_adaptive_hint">摇杆出现在触摸处,松手后隐藏</string>
|
||||
<string name="ctrl_layout">布局</string>
|
||||
<string name="ctrl_layout_custom">已保存自定义位置</string>
|
||||
<string name="ctrl_layout_default">已适配此屏幕</string>
|
||||
<string name="ctrl_edit">编辑</string>
|
||||
<string name="ctrl_reset">重置</string>
|
||||
<string name="ctrl_mapping">按键映射</string>
|
||||
<string name="ctrl_mapping_default">每个按钮发送各自的输入</string>
|
||||
<string name="ctrl_mapping_count">%2$d 个按钮中已重映射 %1$d 个</string>
|
||||
<string name="ctrl_configure">配置</string>
|
||||
<string name="ctrl_reset_all">重置手柄</string>
|
||||
<string name="ctrl_reset_all_hint">恢复所有手柄设置和布局</string>
|
||||
<string name="ctrl_mapping_lede">每个屏幕按钮发送给游戏的内容。“隐藏”会移除该按钮。</string>
|
||||
<string name="ctrl_onscreen_buttons">屏幕按钮</string>
|
||||
<string name="ctrl_defaults">默认值</string>
|
||||
<string name="ctrl_reset_mapping">重置映射</string>
|
||||
<string name="content_android_apps">Android 应用</string>
|
||||
<string name="content_apps_count">%1$d 个应用</string>
|
||||
<string name="content_no_android_apps">未找到可启动的 Android 应用。</string>
|
||||
@@ -1344,15 +1307,8 @@
|
||||
<string name="deck_surface_stick">摇杆</string>
|
||||
<string name="deck_surface_trackpad">触控板</string>
|
||||
<string name="deck_surface_switch">在摇杆与触控板之间切换</string>
|
||||
<string name="deck_more_controls">更多 Deck 控制</string>
|
||||
<string name="deck_panels">面板</string>
|
||||
<string name="deck_close">关闭副屏控制</string>
|
||||
<string name="deck_open_steam_menu">打开 Steam 菜单</string>
|
||||
<string name="deck_left_upper">左 · 上</string>
|
||||
<string name="deck_left_lower">左 · 下</string>
|
||||
<string name="deck_right_upper">右 · 上</string>
|
||||
<string name="deck_right_lower">右 · 下</string>
|
||||
<string name="deck_click">点击</string>
|
||||
<string name="deck_right_trackpad">右触控板</string>
|
||||
<string name="deck_left_trackpad">左触控板</string>
|
||||
<string name="second_trackpad">触控板</string>
|
||||
@@ -1861,9 +1817,7 @@
|
||||
<string name="ctrl_target_left">方向键左</string>
|
||||
<string name="ctrl_target_right">方向键右</string>
|
||||
<string name="ctrl_target_hidden">隐藏</string>
|
||||
<string name="ctrl_editor_drag">拖动以移动</string>
|
||||
<string name="ctrl_editor_snap">对齐</string>
|
||||
<string name="ctrl_editor_save">保存</string>
|
||||
<string name="second_mode_none">无</string>
|
||||
<string name="second_mode_keyboard_trackpad">键盘 + 触控板</string>
|
||||
<string name="second_mode_terminal">终端</string>
|
||||
@@ -2634,7 +2588,6 @@
|
||||
<string name="gog_achievements_unavailable">成就不可用;请查看会话日志</string>
|
||||
<string name="achievement_unlocked">成就已解锁</string>
|
||||
<string name="touch_paste">粘贴</string>
|
||||
<string name="touch_dpad">方向键</string>
|
||||
<string name="touch_left_stick">左摇杆</string>
|
||||
<string name="touch_right_stick">右摇杆</string>
|
||||
<string name="touch_menu">菜单</string>
|
||||
@@ -3676,4 +3629,7 @@
|
||||
<string name="addons_none_found">未找到插件</string>
|
||||
<string name="addons_unreachable">无法连接到 %1$s</string>
|
||||
<string name="addons_no_file">没有适用于此游戏版本的文件</string>
|
||||
<string name="input_reset_positions">重置位置</string>
|
||||
<string name="input_show_label">显示标签</string>
|
||||
<string name="input_layout_import_failed">无法导入此布局</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam 觸控(測試版)</string>
|
||||
<string name="osc_style_next_session">Steam 的觸控控制會在下次 Steam 會話啟用</string>
|
||||
<string name="osc_steam_layout">Steam 觸控佈局</string>
|
||||
<string name="screen_keys">螢幕按鍵</string>
|
||||
<string name="screen_keys_add">新增按鍵</string>
|
||||
<string name="screen_key_text">文本</string>
|
||||
<string name="screen_key_size">大小</string>
|
||||
<string name="screen_key_opacity">透明</string>
|
||||
<string name="screen_key_type_button">單鍵</string>
|
||||
<string name="screen_key_shape_trigger">扳機</string>
|
||||
<string name="screen_key_toggle">切換</string>
|
||||
<string name="screen_key_layout_export">匯出</string>
|
||||
<string name="screen_key_shape_pill">膠囊</string>
|
||||
<string name="screen_key_shape_round">圓角</string>
|
||||
<string name="screen_key_shape_circle">圓形</string>
|
||||
<string name="screen_key_shape_rect">矩形</string>
|
||||
<string name="screen_key_bind">綁定</string>
|
||||
<string name="screen_key_image">圖片</string>
|
||||
<string name="screen_key_image_clear">清除</string>
|
||||
<string name="screen_key_layout">佈局</string>
|
||||
<string name="screen_key_layout_save">儲存</string>
|
||||
<string name="osc_steam_layout_hint">移動、調整大小或隱藏此遊戲的觸控控制;會儲存至 Steam</string>
|
||||
<string name="mode_controller">控制器</string>
|
||||
<string name="mode_controller_hint">Steam 如何識別你的控制器。下次會話生效。</string>
|
||||
@@ -766,7 +750,6 @@
|
||||
<string name="drawer_relative_mouse_auto">自動</string>
|
||||
<string name="drawer_relative_mouse_on">開</string>
|
||||
<string name="drawer_relative_mouse_off">關</string>
|
||||
<string name="drawer_direct_cursor">游標</string>
|
||||
<string name="drawer_pc_keyboard">電腦鍵盤</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">第二螢幕</string>
|
||||
@@ -1105,43 +1088,23 @@
|
||||
<string name="wadb_computer_last">3 · 電腦 ADB(最後手段)</string>
|
||||
<string name="wadb_only_if">只在無法使用無線偵錯時使用。</string>
|
||||
<string name="wadb_computer_group">3 · 電腦 ADB(最後手段)</string>
|
||||
<string name="ctrl_osc_hint">會話中何時顯示觸控控制</string>
|
||||
<string name="ctrl_color">顏色</string>
|
||||
<string name="ctrl_color_hint">螢幕按鍵的色調</string>
|
||||
<string name="ctrl_custom">自訂</string>
|
||||
<string name="ctrl_opacity">不透明度</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">按鍵大小</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% 為標準大小</string>
|
||||
<string name="ctrl_stick_click">按下搖桿</string>
|
||||
<string name="ctrl_stick_click_hint">在搖桿上輕按兩下並按住,即可觸發 L3 或 R3</string>
|
||||
<string name="ctrl_adaptive">自動調整搖桿</string>
|
||||
<string name="ctrl_rumble">遊戲震動</string>
|
||||
<string name="ctrl_dead_zone">搖桿死區</string>
|
||||
<string name="ctrl_steam_button">Steam 按鈕</string>
|
||||
<string name="ctrl_qam_button">QAM 按鈕</string>
|
||||
<string name="ctrl_keyboard_button">鍵盤按鈕</string>
|
||||
<string name="ctrl_select_steam">按 Select 開啟 Steam 選單</string>
|
||||
<string name="ctrl_select_steam_hint">代替 View/Select。</string>
|
||||
<string name="ctrl_joycon_vr">將 Joy-Con 用作 VR 控制器</string>
|
||||
<string name="ctrl_joycon_vr_hint">SteamVR 執行時,每個 Joy-Con 都會變成一隻手。將它指向前方並按住 HOME 鍵或擷取鍵,即可重新置中。</string>
|
||||
<string name="setup_animations">動畫</string>
|
||||
<string name="ctrl_adaptive_hint">搖桿會在你觸控的位置出現,放開後隱藏</string>
|
||||
<string name="ctrl_layout">佈局</string>
|
||||
<string name="ctrl_layout_custom">已儲存自訂位置</string>
|
||||
<string name="ctrl_layout_default">已配合此螢幕</string>
|
||||
<string name="ctrl_edit">編輯</string>
|
||||
<string name="ctrl_reset">重設</string>
|
||||
<string name="ctrl_mapping">按鍵對應</string>
|
||||
<string name="ctrl_mapping_default">每個按鍵都發送其原本的輸入</string>
|
||||
<string name="ctrl_mapping_count">已重新對應 %1$d/%2$d 個按鍵</string>
|
||||
<string name="ctrl_configure">設定</string>
|
||||
<string name="ctrl_reset_all">重設控制器</string>
|
||||
<string name="ctrl_reset_all_hint">還原所有控制器設定和佈局</string>
|
||||
<string name="ctrl_mapping_lede">每個螢幕按鍵向遊戲發送的輸入。「隱藏」會移除該按鍵。</string>
|
||||
<string name="ctrl_onscreen_buttons">螢幕按鍵</string>
|
||||
<string name="ctrl_defaults">預設值</string>
|
||||
<string name="ctrl_reset_mapping">重設對應</string>
|
||||
<string name="content_android_apps">Android 應用程式</string>
|
||||
<string name="content_apps_count">%1$d 個應用程式</string>
|
||||
<string name="content_no_android_apps">找不到可啟動的 Android 應用程式。</string>
|
||||
@@ -1260,15 +1223,8 @@
|
||||
<string name="deck_surface_stick">搖桿</string>
|
||||
<string name="deck_surface_trackpad">觸控板</string>
|
||||
<string name="deck_surface_switch">在搖桿和觸控板之間切換</string>
|
||||
<string name="deck_more_controls">更多 Deck 控制</string>
|
||||
<string name="deck_panels">面板</string>
|
||||
<string name="deck_close">關閉第二螢幕控制</string>
|
||||
<string name="deck_open_steam_menu">開啟 Steam 選單</string>
|
||||
<string name="deck_left_upper">左側 · 上方</string>
|
||||
<string name="deck_left_lower">左側 · 下方</string>
|
||||
<string name="deck_right_upper">右側 · 上方</string>
|
||||
<string name="deck_right_lower">右側 · 下方</string>
|
||||
<string name="deck_click">按下</string>
|
||||
<string name="deck_right_trackpad">右側觸控板</string>
|
||||
<string name="deck_left_trackpad">左側觸控板</string>
|
||||
<string name="second_trackpad">觸控板</string>
|
||||
@@ -1783,9 +1739,7 @@
|
||||
<string name="ctrl_target_left">十字鍵左</string>
|
||||
<string name="ctrl_target_right">十字鍵右</string>
|
||||
<string name="ctrl_target_hidden">隱藏</string>
|
||||
<string name="ctrl_editor_drag">拖曳以移動</string>
|
||||
<string name="ctrl_editor_snap">對齊</string>
|
||||
<string name="ctrl_editor_save">儲存</string>
|
||||
<string name="second_mode_none">無</string>
|
||||
<string name="second_mode_keyboard_trackpad">鍵盤 + 觸控板</string>
|
||||
<string name="second_mode_terminal">終端機</string>
|
||||
@@ -2630,7 +2584,6 @@
|
||||
<string name="gog_achievements_unavailable">成就不可用;請查看工作階段日誌</string>
|
||||
<string name="achievement_unlocked">成就已解鎖</string>
|
||||
<string name="touch_paste">貼上</string>
|
||||
<string name="touch_dpad">方向鍵</string>
|
||||
<string name="touch_left_stick">左搖桿</string>
|
||||
<string name="touch_right_stick">右搖桿</string>
|
||||
<string name="touch_menu">選單</string>
|
||||
@@ -3675,4 +3628,7 @@
|
||||
<string name="addons_none_found">找不到插件</string>
|
||||
<string name="addons_unreachable">無法連接 %1$s</string>
|
||||
<string name="addons_no_file">沒有適用於此遊戲版本的檔案</string>
|
||||
<string name="input_reset_positions">重設位置</string>
|
||||
<string name="input_show_label">顯示標籤</string>
|
||||
<string name="input_layout_import_failed">無法匯入此佈局</string>
|
||||
</resources>
|
||||
@@ -272,24 +272,8 @@
|
||||
<string name="osc_steam_touch">Steam 觸控(測試版)</string>
|
||||
<string name="osc_style_next_session">Steam 觸控控制會在下次 Steam 工作階段啟用</string>
|
||||
<string name="osc_steam_layout">Steam 觸控版面配置</string>
|
||||
<string name="screen_keys">螢幕按鍵</string>
|
||||
<string name="screen_keys_add">新增按鍵</string>
|
||||
<string name="screen_key_text">文本</string>
|
||||
<string name="screen_key_size">大小</string>
|
||||
<string name="screen_key_opacity">透明</string>
|
||||
<string name="screen_key_type_button">單鍵</string>
|
||||
<string name="screen_key_shape_trigger">扳機</string>
|
||||
<string name="screen_key_toggle">切換</string>
|
||||
<string name="screen_key_layout_export">匯出</string>
|
||||
<string name="screen_key_shape_pill">膠囊</string>
|
||||
<string name="screen_key_shape_round">圓角</string>
|
||||
<string name="screen_key_shape_circle">圓形</string>
|
||||
<string name="screen_key_shape_rect">矩形</string>
|
||||
<string name="screen_key_bind">綁定</string>
|
||||
<string name="screen_key_image">圖片</string>
|
||||
<string name="screen_key_image_clear">清除</string>
|
||||
<string name="screen_key_layout">版面配置</string>
|
||||
<string name="screen_key_layout_save">儲存</string>
|
||||
<string name="osc_steam_layout_hint">移動、調整大小或隱藏這款遊戲的觸控控制;會儲存到 Steam</string>
|
||||
<string name="mode_controller">控制器</string>
|
||||
<string name="mode_controller_hint">Steam 辨識你的控制器的方式。下次工作階段生效。</string>
|
||||
@@ -766,7 +750,6 @@
|
||||
<string name="drawer_relative_mouse_auto">自動</string>
|
||||
<string name="drawer_relative_mouse_on">開</string>
|
||||
<string name="drawer_relative_mouse_off">關</string>
|
||||
<string name="drawer_direct_cursor">游標</string>
|
||||
<string name="drawer_pc_keyboard">電腦鍵盤</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">第二螢幕</string>
|
||||
@@ -1105,43 +1088,23 @@
|
||||
<string name="wadb_computer_last">3 · 電腦 ADB(最後手段)</string>
|
||||
<string name="wadb_only_if">僅在無線偵錯無法使用時使用。</string>
|
||||
<string name="wadb_computer_group">3 · 電腦 ADB(最後手段)</string>
|
||||
<string name="ctrl_osc_hint">工作階段中顯示螢幕控制時</string>
|
||||
<string name="ctrl_color">顏色</string>
|
||||
<string name="ctrl_color_hint">螢幕按鍵的色調</string>
|
||||
<string name="ctrl_custom">自訂</string>
|
||||
<string name="ctrl_opacity">不透明度</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">按鍵大小</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% 為標準大小</string>
|
||||
<string name="ctrl_stick_click">搖桿點擊</string>
|
||||
<string name="ctrl_stick_click_hint">點兩下並按住搖桿可觸發 L3 或 R3</string>
|
||||
<string name="ctrl_adaptive">自適應搖桿</string>
|
||||
<string name="ctrl_rumble">遊戲震動</string>
|
||||
<string name="ctrl_dead_zone">搖桿死區</string>
|
||||
<string name="ctrl_steam_button">Steam 按鈕</string>
|
||||
<string name="ctrl_qam_button">QAM 按鈕</string>
|
||||
<string name="ctrl_keyboard_button">鍵盤按鈕</string>
|
||||
<string name="ctrl_select_steam">按 Select 開啟 Steam 功能表</string>
|
||||
<string name="ctrl_select_steam_hint">代替 View/Select。</string>
|
||||
<string name="ctrl_joycon_vr">將 Joy-Con 當作 VR 控制器</string>
|
||||
<string name="ctrl_joycon_vr_hint">SteamVR 執行時,每個 Joy-Con 都會變成一隻手。將它指向前方並按住 HOME 鍵或擷取鍵,即可重新置中。</string>
|
||||
<string name="setup_animations">動畫</string>
|
||||
<string name="ctrl_adaptive_hint">搖桿會出現在你觸控的位置,並在放開後隱藏</string>
|
||||
<string name="ctrl_layout">版面配置</string>
|
||||
<string name="ctrl_layout_custom">已儲存自訂位置</string>
|
||||
<string name="ctrl_layout_default">已適應此螢幕</string>
|
||||
<string name="ctrl_edit">編輯</string>
|
||||
<string name="ctrl_reset">重設</string>
|
||||
<string name="ctrl_mapping">按鍵映射</string>
|
||||
<string name="ctrl_mapping_default">每個按鍵傳送對應的原始輸入</string>
|
||||
<string name="ctrl_mapping_count">%1$d/%2$d 個按鍵已重新映射</string>
|
||||
<string name="ctrl_configure">設定</string>
|
||||
<string name="ctrl_reset_all">重設控制器</string>
|
||||
<string name="ctrl_reset_all_hint">還原所有控制器設定和版面配置</string>
|
||||
<string name="ctrl_mapping_lede">設定每個螢幕按鍵向遊戲傳送的輸入。「隱藏」會移除該按鍵。</string>
|
||||
<string name="ctrl_onscreen_buttons">螢幕按鍵</string>
|
||||
<string name="ctrl_defaults">預設值</string>
|
||||
<string name="ctrl_reset_mapping">重設映射</string>
|
||||
<string name="content_android_apps">Android 應用程式</string>
|
||||
<string name="content_apps_count">%1$d 個應用程式</string>
|
||||
<string name="content_no_android_apps">沒有找到可啟動的 Android 應用程式。</string>
|
||||
@@ -1260,15 +1223,8 @@
|
||||
<string name="deck_surface_stick">搖桿</string>
|
||||
<string name="deck_surface_trackpad">觸控板</string>
|
||||
<string name="deck_surface_switch">在搖桿與觸控板之間切換</string>
|
||||
<string name="deck_more_controls">更多 Deck 控制</string>
|
||||
<string name="deck_panels">面板</string>
|
||||
<string name="deck_close">關閉第二螢幕控制</string>
|
||||
<string name="deck_open_steam_menu">開啟 Steam 選單</string>
|
||||
<string name="deck_left_upper">左側 · 上方</string>
|
||||
<string name="deck_left_lower">左側 · 下方</string>
|
||||
<string name="deck_right_upper">右側 · 上方</string>
|
||||
<string name="deck_right_lower">右側 · 下方</string>
|
||||
<string name="deck_click">點擊</string>
|
||||
<string name="deck_right_trackpad">右側觸控板</string>
|
||||
<string name="deck_left_trackpad">左側觸控板</string>
|
||||
<string name="second_trackpad">觸控板</string>
|
||||
@@ -1783,9 +1739,7 @@
|
||||
<string name="ctrl_target_left">方向鍵左</string>
|
||||
<string name="ctrl_target_right">方向鍵右</string>
|
||||
<string name="ctrl_target_hidden">隱藏</string>
|
||||
<string name="ctrl_editor_drag">拖曳以移動</string>
|
||||
<string name="ctrl_editor_snap">對齊</string>
|
||||
<string name="ctrl_editor_save">儲存</string>
|
||||
<string name="second_mode_none">無</string>
|
||||
<string name="second_mode_keyboard_trackpad">鍵盤 + 觸控板</string>
|
||||
<string name="second_mode_terminal">終端機</string>
|
||||
@@ -2630,7 +2584,6 @@
|
||||
<string name="gog_achievements_unavailable">成就無法使用;請查看工作階段記錄</string>
|
||||
<string name="achievement_unlocked">成就已解鎖</string>
|
||||
<string name="touch_paste">貼上</string>
|
||||
<string name="touch_dpad">方向鍵</string>
|
||||
<string name="touch_left_stick">左搖桿</string>
|
||||
<string name="touch_right_stick">右搖桿</string>
|
||||
<string name="touch_menu">選單</string>
|
||||
@@ -3675,4 +3628,7 @@
|
||||
<string name="addons_none_found">找不到插件</string>
|
||||
<string name="addons_unreachable">無法連線至 %1$s</string>
|
||||
<string name="addons_no_file">沒有適用於此遊戲版本的檔案</string>
|
||||
<string name="input_reset_positions">重設位置</string>
|
||||
<string name="input_show_label">顯示標籤</string>
|
||||
<string name="input_layout_import_failed">無法匯入此版面配置</string>
|
||||
</resources>
|
||||
@@ -1,14 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="input_library_recovered">Unreadable input settings were preserved in a recovery copy. You can continue editing the restored profiles.</string>
|
||||
<string name="input_builtin_layout_hint">This built-in layout keeps its existing controls. Create a custom layout to add, move or resize elements.</string>
|
||||
<string name="input_properties">Properties</string>
|
||||
<string name="input_click_properties">Click properties</string>
|
||||
<string name="input_click_name">%1$s · Click</string>
|
||||
<string name="input_buttons">Buttons</string>
|
||||
<string name="input_axes">Sticks, pads and triggers</string>
|
||||
<string name="input_hide_tools">Hide tools</string>
|
||||
<string name="input_show_tools">Show tools</string>
|
||||
<string name="input_route_controller">Controller</string>
|
||||
<string name="input_controller_route_hint">Send controller input to Steam Input or the game.</string>
|
||||
<string name="input_disabled_hint">This element sends no controller, mouse or keyboard input.</string>
|
||||
@@ -16,29 +14,12 @@
|
||||
<string name="input_command">DroidDeck action</string>
|
||||
<string name="input_action">Action</string>
|
||||
<string name="input_scroll_speed">Scroll speed: %1$d steps/s</string>
|
||||
<string name="input_auto_selection">Auto selection</string>
|
||||
<string name="input_more">Shortcuts and diagnostics</string>
|
||||
<string name="input_layouts">Layouts</string>
|
||||
<string name="input_edit_separate">Opening a profile for editing does not activate it.</string>
|
||||
<string name="input_saved_profiles">Saved profiles</string>
|
||||
<string name="input_new_profile">+ New profile</string>
|
||||
<string name="input_new_layout">+ New layout</string>
|
||||
<string name="input_new_bindings">+ New bindings</string>
|
||||
<string name="input_layouts_hint">Saved elements, positions and sizes. Actions are stored in bindings.</string>
|
||||
<string name="input_used_by">Used by %1$d profiles</string>
|
||||
<string name="input_shared_detail">%1$s · Used by %2$d profiles. Changes apply to every profile using these bindings.</string>
|
||||
<string name="input_empty_layout">Empty layout</string>
|
||||
<string name="input_profile_parts">Saved parts</string>
|
||||
<string name="input_profile_parts_hint">Choose shared bindings and a layout for each touch screen.</string>
|
||||
<string name="input_direct_edit_hint">Arrange elements directly on the target display. Properties open on the main display.</string>
|
||||
<string name="input_use_profile">Use this profile</string>
|
||||
<string name="input_rename">Rename</string>
|
||||
<string name="input_copy">Make a copy</string>
|
||||
<string name="input_delete">Delete</string>
|
||||
<string name="input_empty_elements">Add elements to the layout before assigning their actions.</string>
|
||||
<string name="input_edit_on">Edit on</string>
|
||||
<string name="input_confirm_change">Confirm change</string>
|
||||
<string name="input_confirm_change_hint">Continue with this reset or deletion?</string>
|
||||
<string name="input_save_failed">Could not save input settings</string>
|
||||
<string name="input_name">Name</string>
|
||||
<string name="input_start_from">Start from</string>
|
||||
@@ -51,21 +32,17 @@
|
||||
<string name="input_editor_undo">Undo</string>
|
||||
<string name="input_editor_add">+ Add</string>
|
||||
<string name="input_editor_hint">Drag to move. Drag a corner to resize. Tap Properties to assign an action.</string>
|
||||
<string name="input_editor_place">Tap to place the new element.</string>
|
||||
<string name="input_editor_remote">Editing on your second screen</string>
|
||||
<string name="input_display_unavailable">The selected display is not available. Connect it to edit this layout at its actual size.</string>
|
||||
<string name="input_editor_discard">Discard unsaved layout changes?</string>
|
||||
<string name="input_editor_shared">This layout is used by %1$d profiles. Saved changes apply to all of them.</string>
|
||||
<string name="input_editor_unassigned">Unassigned</string>
|
||||
<string name="input_default_profiles">Default profiles</string>
|
||||
<string name="input_desktop_mode">Desktop mode</string>
|
||||
<string name="input_game_mode">Game mode</string>
|
||||
<string name="input_manual_override">The session is pinned to %1$s. Choose Auto in the session menu to use these defaults.</string>
|
||||
<string name="input_default_both">Default for Desktop and Game</string>
|
||||
<string name="input_default_game">Default for Game mode</string>
|
||||
<string name="input_default_desktop">Default for Desktop mode</string>
|
||||
<string name="input_device_settings">Device settings</string>
|
||||
<string name="input_device_hint">Vibration, stick dead zone, shortcuts and diagnostics</string>
|
||||
<string name="input_profile_controls">Controls</string>
|
||||
<string name="input_physical_hint">Buttons, sticks, triggers and extra keys</string>
|
||||
<string name="input_copy_profile">Copy profile</string>
|
||||
@@ -77,9 +54,6 @@
|
||||
<string name="input_edit_layout">Edit on screen</string>
|
||||
<string name="input_saved_layouts">Saved layouts…</string>
|
||||
<string name="input_saved_layouts_hint">Choose a layout or create your own</string>
|
||||
<string name="input_builtin_appearance">Built-in gamepad options</string>
|
||||
<string name="input_builtin_appearance_hint">Appearance, buttons and positions</string>
|
||||
<string name="input_builtin_shared">These options apply to the built-in main-screen gamepad in every profile. Custom layouts are edited directly on screen.</string>
|
||||
<string name="input_second_screen_enable">Choose Profile controls in the second-screen session menu. The Profile and Second screen selectors in the Controller menu choose the controls to show.</string>
|
||||
<string name="input_assign_actions">Button actions</string>
|
||||
<string name="input_shared_with">Shared with %1$s. Edits apply to those profiles too.</string>
|
||||
@@ -99,7 +73,6 @@
|
||||
<string name="input_reuse_part_detail">Copy these controls and actions, or link them so future edits apply to both profiles.</string>
|
||||
<string name="input_keep_shared">Keep shared</string>
|
||||
<string name="input_independent_copy">Independent copy</string>
|
||||
<string name="input_builtin_positions_shared">Built-in gamepad · positions shared across profiles</string>
|
||||
<string name="input_floating_stick">Start stick at touch position</string>
|
||||
<string name="input_hide_idle">Hide stick when not in use</string>
|
||||
<string name="input_tools">Tools</string>
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
<resources>
|
||||
<string name="input_settings">Input profiles</string>
|
||||
<string name="input_settings_hint">Choose what each control sends. Native controls keep their gamepad or Steam Input behavior; local actions send keys, mouse input or DroidDeck commands.</string>
|
||||
<string name="input_profiles">Profiles</string>
|
||||
<string name="input_profile_game">Game</string>
|
||||
<string name="input_profile_desktop">Desktop</string>
|
||||
<string name="input_active_profile">Active profile</string>
|
||||
<string name="input_auto_hint">Auto uses Desktop in desktop sessions and Game in other sessions. Select Game manually when playing a game from the desktop.</string>
|
||||
<string name="input_edit_profile">Edit profile</string>
|
||||
<string name="input_source">Control source</string>
|
||||
<string name="input_physical">Physical controller</string>
|
||||
<string name="input_primary">Main screen</string>
|
||||
<string name="input_secondary">Second screen</string>
|
||||
<string name="input_bindings">Bindings</string>
|
||||
<string name="input_native">Native / Steam Input</string>
|
||||
<string name="input_native_target">Native: %1$s</string>
|
||||
<string name="input_remap_native">Send another controller control</string>
|
||||
@@ -29,16 +21,8 @@
|
||||
<string name="input_command_keyboard">Show keyboard</string>
|
||||
<string name="input_command_steam">Open Steam menu</string>
|
||||
<string name="input_command_qam">Open Steam quick access</string>
|
||||
<string name="input_surface">Screen layout</string>
|
||||
<string name="input_surface_edit">Custom second-screen layout</string>
|
||||
<string name="input_surface_hint">Arrange controls here, then select Custom controls in the second-screen panel. Their actions come from this profile’s Second screen bindings. Native trackpads require a Steam Deck controller; Steam Mobile Touch layouts remain configured in Steam.</string>
|
||||
<string name="input_position_x">Horizontal position</string>
|
||||
<string name="input_position_y">Vertical position</string>
|
||||
<string name="input_width">Width</string>
|
||||
<string name="input_height">Height</string>
|
||||
<string name="input_remove_element">Remove control</string>
|
||||
<string name="input_add_element">Add control</string>
|
||||
<string name="input_custom_controls">Custom controls</string>
|
||||
<string name="input_extra_keys">Device-specific buttons</string>
|
||||
<string name="input_capture">Assign a physical button</string>
|
||||
<string name="input_capture_confirm">Release the button, then choose Edit, Retry, or Cancel. B or Back cancels after release.</string>
|
||||
|
||||
@@ -301,23 +301,7 @@
|
||||
<string name="osc_steam_touch">Steam touch (beta)</string>
|
||||
<string name="osc_style_next_session">Steam\'s touch controls start with the next Steam session</string>
|
||||
<string name="osc_steam_layout">Steam touch layout</string>
|
||||
<string name="screen_keys">Screen keys</string>
|
||||
<string name="screen_keys_add">Add key</string>
|
||||
<string name="screen_key_text">Text</string>
|
||||
<string name="screen_key_size">Size</string>
|
||||
<string name="screen_key_opacity">Alpha</string>
|
||||
<string name="screen_key_type_button">Key</string>
|
||||
<string name="screen_key_shape_pill">Pill</string>
|
||||
<string name="screen_key_shape_round">Round</string>
|
||||
<string name="screen_key_shape_circle">Circle</string>
|
||||
<string name="screen_key_shape_rect">Rect</string>
|
||||
<string name="screen_key_shape_trigger">Trigger</string>
|
||||
<string name="screen_key_bind">Bind</string>
|
||||
<string name="screen_key_image">Image</string>
|
||||
<string name="screen_key_image_clear">Clear</string>
|
||||
<string name="screen_key_toggle">Toggle</string>
|
||||
<string name="screen_key_layout">Layout</string>
|
||||
<string name="screen_key_layout_save">Save</string>
|
||||
<string name="screen_key_layout_export">Export</string>
|
||||
<string name="osc_steam_layout_hint">Move, resize or hide this game\'s touch controls; saved to Steam</string>
|
||||
<string name="mode_controller">Controller</string>
|
||||
@@ -840,7 +824,6 @@
|
||||
<string name="drawer_relative_mouse_auto">Auto</string>
|
||||
<string name="drawer_relative_mouse_on">On</string>
|
||||
<string name="drawer_relative_mouse_off">Off</string>
|
||||
<string name="drawer_direct_cursor">Cursor</string>
|
||||
<string name="drawer_pc_keyboard">PC keyboard</string>
|
||||
<string name="drawer_android_keyboard">Android</string>
|
||||
<string name="drawer_second_screen">Second screen</string>
|
||||
@@ -1220,43 +1203,23 @@
|
||||
<string name="wadb_computer_last">3 · Computer ADB (last resort)</string>
|
||||
<string name="wadb_only_if">Only if Wireless debugging is unavailable.</string>
|
||||
<string name="wadb_computer_group">3 · Computer ADB (last resort)</string>
|
||||
<string name="ctrl_osc_hint">When the touch controls appear in a session</string>
|
||||
<string name="ctrl_color">Color</string>
|
||||
<string name="ctrl_color_hint">Tint of the on-screen buttons</string>
|
||||
<string name="ctrl_custom">Custom</string>
|
||||
<string name="ctrl_opacity">Opacity</string>
|
||||
<string name="ctrl_percent">%1$d%%</string>
|
||||
<string name="ctrl_size">Button size</string>
|
||||
<string name="ctrl_size_hint" formatted="false">100% is the standard size</string>
|
||||
<string name="ctrl_stick_click">Stick click</string>
|
||||
<string name="ctrl_stick_click_hint">Double-tap and hold a stick for L3 or R3</string>
|
||||
<string name="ctrl_adaptive">Adaptive sticks</string>
|
||||
<string name="ctrl_rumble">Game vibration</string>
|
||||
<string name="ctrl_dead_zone">Stick dead zone</string>
|
||||
<string name="ctrl_steam_button">Steam button</string>
|
||||
<string name="ctrl_qam_button">QAM button</string>
|
||||
<string name="ctrl_keyboard_button">Keyboard button</string>
|
||||
<string name="ctrl_select_steam">Press Select to open the Steam menu</string>
|
||||
<string name="ctrl_select_steam_hint">Instead of View/Select.</string>
|
||||
<string name="ctrl_joycon_vr">Joy-Cons as VR controllers</string>
|
||||
<string name="ctrl_joycon_vr_hint">While SteamVR runs, each Joy-Con becomes a hand. Point it ahead and hold Home or Capture to recenter it.</string>
|
||||
<string name="setup_animations">Animations</string>
|
||||
<string name="ctrl_adaptive_hint">Sticks appear where you touch and hide on release</string>
|
||||
<string name="ctrl_layout">Layout</string>
|
||||
<string name="ctrl_layout_custom">Custom positions saved</string>
|
||||
<string name="ctrl_layout_default">Fitted to this screen</string>
|
||||
<string name="ctrl_edit">Edit</string>
|
||||
<string name="ctrl_reset">Reset</string>
|
||||
<string name="ctrl_mapping">Button mapping</string>
|
||||
<string name="ctrl_mapping_default">Every button sends its own input</string>
|
||||
<string name="ctrl_mapping_count">%1$d of %2$d buttons remapped</string>
|
||||
<string name="ctrl_configure">Configure</string>
|
||||
<string name="ctrl_reset_all">Reset controller</string>
|
||||
<string name="ctrl_reset_all_hint">Restores all controller settings and the layout</string>
|
||||
<string name="ctrl_mapping_lede">What each on-screen button sends to the game. Hidden removes the button.</string>
|
||||
<string name="ctrl_onscreen_buttons">On-screen buttons</string>
|
||||
<string name="ctrl_defaults">Defaults</string>
|
||||
<string name="ctrl_reset_mapping">Reset mapping</string>
|
||||
<string name="content_android_apps">Android apps</string>
|
||||
<string name="content_apps_count">%1$d apps</string>
|
||||
<string name="content_no_android_apps">No launchable Android apps found.</string>
|
||||
@@ -1418,15 +1381,8 @@
|
||||
<string name="deck_surface_stick">Stick</string>
|
||||
<string name="deck_surface_trackpad">Trackpad</string>
|
||||
<string name="deck_surface_switch">Switch between stick and trackpad</string>
|
||||
<string name="deck_more_controls">More Deck controls</string>
|
||||
<string name="deck_panels">PANELS</string>
|
||||
<string name="deck_close">Close second-screen controls</string>
|
||||
<string name="deck_open_steam_menu">Open Steam menu</string>
|
||||
<string name="deck_left_upper">Left · upper</string>
|
||||
<string name="deck_left_lower">Left · lower</string>
|
||||
<string name="deck_right_upper">Right · upper</string>
|
||||
<string name="deck_right_lower">Right · lower</string>
|
||||
<string name="deck_click">Click</string>
|
||||
<string name="deck_right_trackpad">Right trackpad</string>
|
||||
<string name="deck_left_trackpad">Left trackpad</string>
|
||||
<string name="second_trackpad">Trackpad</string>
|
||||
@@ -1978,9 +1934,7 @@
|
||||
<string name="ctrl_target_left">D-pad left</string>
|
||||
<string name="ctrl_target_right">D-pad right</string>
|
||||
<string name="ctrl_target_hidden">Hidden</string>
|
||||
<string name="ctrl_editor_drag">Drag to move</string>
|
||||
<string name="ctrl_editor_snap">Snap</string>
|
||||
<string name="ctrl_editor_save">Save</string>
|
||||
<string name="second_mode_none">None</string>
|
||||
<string name="second_mode_keyboard_trackpad">Keyboard + trackpad</string>
|
||||
<string name="second_mode_terminal">Terminal</string>
|
||||
@@ -2915,7 +2869,6 @@
|
||||
<string name="setup_gpu_bridge_on">Mali bridge: on</string>
|
||||
<string name="setup_gpu_bridge_detail">%1$s is not an Adreno. The experimental Vulkan bridge is on: the session draws through the phone\'s own driver. Expect bugs; send the session logs.</string>
|
||||
<string name="touch_paste">Paste</string>
|
||||
<string name="touch_dpad">D-pad</string>
|
||||
<string name="touch_left_stick">Left stick</string>
|
||||
<string name="touch_right_stick">Right stick</string>
|
||||
<string name="touch_menu">Menu</string>
|
||||
@@ -3863,4 +3816,7 @@
|
||||
<string name="addons_no_file">No file for this game version</string>
|
||||
<string name="addons_source_wowi" translatable="false">WoWInterface</string>
|
||||
<string name="addons_source_curse" translatable="false">CurseForge</string>
|
||||
<string name="input_reset_positions">Reset positions</string>
|
||||
<string name="input_show_label">Show label</string>
|
||||
<string name="input_layout_import_failed">Could not import this layout</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.droiddeck.launcher.input
|
||||
|
||||
import android.content.Context
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [34], manifest = Config.NONE)
|
||||
class InputLayoutFileTest {
|
||||
private val context: Context get() = RuntimeEnvironment.getApplication()
|
||||
@Before fun reset() {
|
||||
for (name in listOf("input-profiles", "input-surfaces", "controller")) context.getSharedPreferences(name, Context.MODE_PRIVATE).edit().clear().commit()
|
||||
}
|
||||
|
||||
private fun import(raw: String) = InputLayoutFile.import(context, raw, "Fallback", InputLayoutScreen.MAIN, InputSurfaceStyle(), 1000, 500, 2f)
|
||||
|
||||
@Test fun exportThenImportKeepsKeysShapesCentresSizesAndToggles() {
|
||||
val keys = LegacyScreenKeyMigration.convert(context,
|
||||
"28:0.25,0.6,50::::0.8:2:0:1;29+33:0.7,0.8,40::Find::0.6:3:1:1;103+0+106+0+108+0+105+0:0.5,0.5,80::::1:6:0:1;17+32+31+30:0.2,0.3,70::::1:5:0:1",
|
||||
1000, 500, 2f)
|
||||
val layout = SavedInputLayout("source", "My layout", keys.map { it.first })
|
||||
val bindings = SavedInputBindings("source.bindings", "My layout", false, layout.id, elements = keys.associate { it.first.id to it.second })
|
||||
val raw = InputLayoutFile.export(layout, bindings, 1000, 500)!!
|
||||
assertEquals("My layout", JSONObject(raw).getString("name"))
|
||||
val (imported, actions) = import(raw)!!
|
||||
assertEquals("My layout", imported.name)
|
||||
assertEquals(InputLayoutScreen.MAIN, imported.screen)
|
||||
assertEquals(layout.elements.map { it.kind }, imported.elements.map { it.kind })
|
||||
for ((before, after) in layout.elements.zip(imported.elements)) {
|
||||
assertEquals(before.x + before.width / 2, after.x + after.width / 2, .002f)
|
||||
assertEquals(before.y + before.height / 2, after.y + after.height / 2, .002f)
|
||||
assertEquals(before.height, after.height, .005f)
|
||||
assertEquals(before.toggle, after.toggle)
|
||||
assertEquals(before.opacity, after.opacity, .001f)
|
||||
}
|
||||
assertEquals(InputButtonShape.CIRCLE, imported.elements[0].buttonShape)
|
||||
assertEquals(InputButtonShape.RECTANGLE, imported.elements[1].buttonShape)
|
||||
assertEquals("Find", imported.elements[1].name)
|
||||
val codes = imported.elements.map { actions.action(it) }
|
||||
assertEquals(InputAction.Keys(listOf(28)), codes[0])
|
||||
assertEquals(InputAction.Keys(listOf(29, 33)), codes[1])
|
||||
assertEquals(listOf(103, 106, 108, 105), (codes[2] as InputAction.Directions).let { listOf(it.up, it.right, it.down, it.left) })
|
||||
assertEquals(InputAction.Directions(17, 32, 31, 30), codes[3])
|
||||
InputLibraries.update(context) { it.withLayout(imported).withPreset(actions).chooseLayout(InputProfile.GAME, InputRole.PRIMARY, imported.id) }
|
||||
assertEquals(imported.id, InputLibraries.read(context).layout(InputProfile.GAME, InputRole.PRIMARY)!!.id)
|
||||
}
|
||||
|
||||
@Test fun importsOlderDroidDeckAndWinlatorFiles() {
|
||||
val raw = """{"id":0,"name":"DroidDeck","cursorSpeed":1.5,"elements":[
|
||||
{"type":"BUTTON","shape":"CIRCLE","bindings":["KEY_SPACE"],"scale":1.2,"x":0.8,"y":0.7,"toggleSwitch":false,"text":"Jump","opacity":0.5},
|
||||
{"type":"BUTTON","shape":"ROUND_RECT","bindings":["KEY_CTRL_L","KEY_C"],"scale":1.0,"x":0.3,"y":0.2,"toggleSwitch":true,"text":""},
|
||||
{"type":"STICK","shape":"ROUND_RECT","bindings":["KEY_W","","KEY_D","","KEY_S","","KEY_A",""],"scale":1.0,"x":0.2,"y":0.7},
|
||||
{"type":"STICK","bindings":["KEY_UP","KEY_RIGHT","KEY_DOWN","KEY_LEFT"],"scale":1.0,"x":0.6,"y":0.5},
|
||||
{"type":"D_PAD","bindings":["KEY_I","KEY_L","KEY_K","KEY_J"],"scale":1.0,"x":0.4,"y":0.5},
|
||||
{"type":"TRACKPAD","bindings":["MOUSE_MOVE_LEFT"]},
|
||||
{"type":"BUTTON","bindings":["GAMEPAD_BUTTON_A"],"x":0.1,"y":0.1}
|
||||
]}"""
|
||||
val (layout, actions) = import(raw)!!
|
||||
assertEquals("DroidDeck", layout.name)
|
||||
assertEquals(listOf(InputElementKind.BUTTON, InputElementKind.BUTTON, InputElementKind.STICK, InputElementKind.STICK, InputElementKind.DPAD), layout.elements.map { it.kind })
|
||||
val jump = layout.elements[0]
|
||||
assertEquals("Jump", jump.name)
|
||||
assertEquals(.5f, jump.opacity, .001f)
|
||||
assertEquals(InputButtonShape.CIRCLE, jump.buttonShape)
|
||||
assertEquals(.8f, jump.x + jump.width / 2, .001f)
|
||||
assertEquals(6f * 10f * 1.2f / 500f, jump.height, .002f)
|
||||
assertTrue(layout.elements[1].toggle)
|
||||
assertEquals(InputAction.Keys(listOf(29, 46)), actions.action(layout.elements[1]))
|
||||
assertEquals(InputAction.Directions(17, 32, 31, 30, listOf(0, 0, 0, 0)), actions.action(layout.elements[2]))
|
||||
assertEquals(InputAction.Directions(103, 106, 108, 105, listOf(0, 0, 0, 0)), actions.action(layout.elements[3]))
|
||||
assertEquals(InputAction.Directions(23, 38, 37, 36), actions.action(layout.elements[4]))
|
||||
}
|
||||
|
||||
@Test fun rejectsFilesWithoutUsableControls() {
|
||||
assertNull(import("not json"))
|
||||
assertNull(import("""{"name":"x"}"""))
|
||||
assertNull(import("""{"elements":[{"type":"BUTTON","bindings":["GAMEPAD_BUTTON_A"]}]}"""))
|
||||
val (layout, _) = import("""{"elements":[{"type":"BUTTON","bindings":["KEY_E"],"x":"bad","scale":-1}]}""")!!
|
||||
assertEquals("Fallback", layout.name)
|
||||
assertEquals(.5f, layout.elements.single().x + layout.elements.single().width / 2, .001f)
|
||||
}
|
||||
|
||||
@Test fun layoutsWithoutKeyBindingsHaveNothingToExport() {
|
||||
val library = InputLibraries.read(context)
|
||||
val gamepad = library.layouts.first { it.id == InputLibraries.OVERLAY }
|
||||
assertNull(InputLayoutFile.export(gamepad, library.bindings.firstOrNull { it.layoutId == gamepad.id }, 1000, 500))
|
||||
assertEquals("A_B_.icp", InputLayoutFile.fileName(gamepad.copy(name = "A/B?")))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.droiddeck.launcher.input
|
||||
|
||||
import android.content.Context
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [34], manifest = Config.NONE)
|
||||
class InputLayoutToolsTest {
|
||||
private val context: Context get() = RuntimeEnvironment.getApplication()
|
||||
@Before fun reset() {
|
||||
for (name in listOf("input-profiles", "input-surfaces", "controller")) context.getSharedPreferences(name, Context.MODE_PRIVATE).edit().clear().commit()
|
||||
}
|
||||
|
||||
@Test fun scaleAllResizesEveryElementAroundItsCentreInsideTheScreen() {
|
||||
val elements = listOf(InputSurfaceElement(InputControl.A, .4f, .4f, .2f, .2f, "a", name = "A"),
|
||||
InputSurfaceElement(InputControl.A, 0f, .9f, .1f, .1f, "b", name = "B"))
|
||||
val bigger = elements.scaled(1.25f)
|
||||
assertEquals(.25f, bigger[0].width, .0001f)
|
||||
assertEquals(.5f, bigger[0].x + bigger[0].width / 2, .0001f)
|
||||
assertEquals(.5f, bigger[0].y + bigger[0].height / 2, .0001f)
|
||||
assertEquals(0f, bigger[1].x, .0001f)
|
||||
assertEquals(1f, bigger[1].y + bigger[1].height, .0001f)
|
||||
assertTrue(bigger.all { it == it.bounded() })
|
||||
assertEquals(.16f, elements.scaled(.8f)[0].height, .0001f)
|
||||
assertEquals(elements.map { it.name }, bigger.map { it.name })
|
||||
}
|
||||
|
||||
@Test fun resetPositionsOnlyRestoresGeometryOfElementsTheDefaultsKnow() {
|
||||
val defaults = listOf(InputSurfaceElement(InputControl.A, .1f, .1f, .2f, .2f, "legacy:a"))
|
||||
val moved = listOf(defaults[0].copy(x = .5f, y = .6f, width = .3f, name = "Jump", opacity = .5f),
|
||||
InputSurfaceElement(InputControl.A, .3f, .3f, .1f, .1f, "custom", name = "Custom"))
|
||||
val reset = moved.withPositionsOf(defaults)
|
||||
assertEquals(defaults[0].copy(name = "Jump", opacity = .5f), reset[0])
|
||||
assertEquals(moved[1], reset[1])
|
||||
}
|
||||
|
||||
@Test fun copiesRememberTheirOriginSoStockPositionsCanBeRestored() {
|
||||
val library = InputLibraries.read(context)
|
||||
val copied = library.copyLayout(InputLibraries.DECK, "Mine", "mine")
|
||||
val mine = copied.layouts.first { it.id == "mine" }
|
||||
assertEquals(InputLibraries.DECK, mine.origin)
|
||||
assertEquals(InputLibraries.DECK, copied.copyLayout("mine", "Again", "again").layouts.first { it.id == "again" }.origin)
|
||||
val independent = library.useLayout(InputProfile.GAME, InputRole.SECONDARY, InputLibraries.DECK, shared = false)
|
||||
assertEquals(InputLibraries.DECK, independent.layout(InputProfile.GAME, InputRole.SECONDARY)!!.origin)
|
||||
val stock = InputStockLayouts.layouts().first { it.id == InputLibraries.DECK }.elements
|
||||
val dragged = mine.copy(elements = mine.elements.map { it.copy(x = 0f, y = 0f) })
|
||||
assertEquals(stock, InputLibraries.defaultPositions(context, copied, dragged))
|
||||
assertEquals(mine.elements, dragged.elements.withPositionsOf(stock))
|
||||
assertEquals(copied, InputLibraries.decode(InputLibraries.encode(copied)))
|
||||
}
|
||||
|
||||
@Test fun builtInGamepadDefaultsComeFromTheGamepadGenerator() {
|
||||
val library = InputLibraries.read(context)
|
||||
val gamepad = library.layouts.first { it.id == InputLibraries.OVERLAY }
|
||||
val defaults = InputLibraries.defaultPositions(context, library, gamepad)!!
|
||||
assertEquals(gamepad.elements.map { it.id }.toSet(), defaults.map { it.id }.toSet())
|
||||
assertNull(InputLibraries.defaultPositions(context, library, SavedInputLayout("new", "New")))
|
||||
}
|
||||
|
||||
@Test fun quickButtonsHideWithoutRemovingElementsAndPersist() {
|
||||
val library = InputLibraries.read(context)
|
||||
val gamepad = library.layouts.first { it.id == InputLibraries.OVERLAY }
|
||||
assertTrue(InputCommand.KEYBOARD in gamepad.quickButtons)
|
||||
assertTrue(InputLibraries.setQuickButton(context, gamepad.id, InputCommand.KEYBOARD, false))
|
||||
val hidden = InputLibraries.read(context).layouts.first { it.id == gamepad.id }
|
||||
assertEquals(gamepad.elements, hidden.elements)
|
||||
assertEquals(setOf(InputCommand.KEYBOARD), hidden.style.hidden)
|
||||
val shown = hidden.style.shown(hidden.elements)
|
||||
assertEquals(gamepad.elements.filterNot { it.id == "builtin:keyboard" }, shown)
|
||||
assertTrue(InputLibraries.setQuickButton(context, gamepad.id, InputCommand.KEYBOARD, true))
|
||||
assertEquals(gamepad, InputLibraries.read(context).layouts.first { it.id == gamepad.id })
|
||||
}
|
||||
|
||||
@Test fun onlySteamQuickAccessAndKeyboardCanBeHidden() {
|
||||
val library = InputLibraries.read(context)
|
||||
val gamepad = library.layouts.first { it.id == InputLibraries.OVERLAY }
|
||||
assertThrows(IllegalArgumentException::class.java) {
|
||||
library.withLayout(gamepad.copy(style = gamepad.style.copy(hidden = setOf(InputCommand.MENU)))).validate()
|
||||
}
|
||||
val custom = InputSurfaceElement(InputControl.A, .1f, .1f, .1f, .1f, "custom", name = "Steam")
|
||||
assertFalse(InputSurfaceStyle(hidden = QUICK_BUTTONS.toSet()).hides(custom))
|
||||
}
|
||||
|
||||
private fun overlapping(elements: List<InputSurfaceElement>, width: Int, height: Int): List<Pair<String, String>> {
|
||||
fun round(e: InputSurfaceElement) = e.buttonShape == InputButtonShape.CIRCLE && e.kind != InputElementKind.STICK
|
||||
val result = mutableListOf<Pair<String, String>>()
|
||||
for ((i, a) in elements.withIndex()) for (b in elements.drop(i + 1)) {
|
||||
val ax = (a.x + a.width / 2) * width; val ay = (a.y + a.height / 2) * height
|
||||
val bx = (b.x + b.width / 2) * width; val by = (b.y + b.height / 2) * height
|
||||
val hit = if (round(a) && round(b)) {
|
||||
val ra = minOf(a.width * width, a.height * height) / 2; val rb = minOf(b.width * width, b.height * height) / 2
|
||||
kotlin.math.hypot(ax - bx, ay - by) < ra + rb - .5f
|
||||
} else kotlin.math.abs(ax - bx) < (a.width + b.width) * width / 2 - .5f && kotlin.math.abs(ay - by) < (a.height + b.height) * height / 2 - .5f
|
||||
if (hit) result += a.id to b.id
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@Test fun generatedGamepadSpacingFollowsButtonSize() {
|
||||
for ((w, h) in listOf(1920 to 1080, 1280 to 960)) {
|
||||
val normal = LegacyGamepadLayout(context, w, h).elements()
|
||||
for (scale in listOf(.8f, 1.25f)) {
|
||||
val elements = LegacyGamepadLayout(context, w, h, scale = scale).elements()
|
||||
assertEquals("$w x $h at $scale", emptyList<Pair<String, String>>(), overlapping(elements, w, h))
|
||||
val face = listOf("legacy:a", "legacy:y").map { id -> elements.first { it.id == id } }
|
||||
val faceNormal = listOf("legacy:a", "legacy:y").map { id -> normal.first { it.id == id } }
|
||||
val gap = (face[0].y - face[1].y) / (faceNormal[0].y - faceNormal[1].y)
|
||||
if (scale > 1f) assertTrue(gap > 1f) else assertTrue(gap < 1f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun scalingACustomLayoutScalesTheGapsBetweenNeighbours() {
|
||||
val left = listOf(InputSurfaceElement(InputControl.A, .05f, .5f, .08f, .1f, "one", name = "One"),
|
||||
InputSurfaceElement(InputControl.A, .16f, .5f, .08f, .1f, "two", name = "Two"))
|
||||
val right = listOf(InputSurfaceElement(InputControl.A, .7f, .2f, .1f, .1f, "three", name = "Three"),
|
||||
InputSurfaceElement(InputControl.A, .85f, .2f, .1f, .1f, "four", name = "Four"))
|
||||
for (pair in listOf(left, right)) {
|
||||
val gap = pair[1].x - (pair[0].x + pair[0].width)
|
||||
val bigger = pair.scaled(1.25f)
|
||||
assertEquals(gap * 1.25f, bigger[1].x - (bigger[0].x + bigger[0].width), .0001f)
|
||||
val smaller = pair.scaled(.8f)
|
||||
assertEquals(gap * .8f, smaller[1].x - (smaller[0].x + smaller[0].width), .0001f)
|
||||
assertTrue((bigger + smaller).all { it.x >= 0f && it.x + it.width <= 1.0001f && it.y >= 0f && it.y + it.height <= 1.0001f })
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun aScaledGamepadStaysGeneratedAndRegeneratesOnRotation() {
|
||||
val (display, metrics) = InputLibraries.primaryDisplay(context)
|
||||
val long = maxOf(metrics.widthPixels, metrics.heightPixels)
|
||||
val short = minOf(metrics.widthPixels, metrics.heightPixels)
|
||||
val gamepad = InputLibraries.read(context).layouts.first { it.id == InputLibraries.OVERLAY }
|
||||
val scaled = gamepad.copy(scale = 1.25f, elements = LegacyGamepadLayout(display, long, short, scale = 1.25f).regenerate(gamepad.elements))
|
||||
assertEquals(long to short, OnScreenLayout.generatedSize(context, scaled, long, short))
|
||||
val rotated = OnScreenLayout.elements(context, scaled, short, long, android.graphics.Rect())
|
||||
assertEquals(LegacyGamepadLayout(context, short, long, scale = 1.25f).regenerate(scaled.elements), rotated)
|
||||
assertNull(OnScreenLayout.generatedSize(context, scaled.copy(scale = 1f), long, short))
|
||||
InputLibraries.update(context) { it.withLayout(scaled) }
|
||||
assertEquals(1.25f, InputLibraries.read(context).layouts.first { it.id == gamepad.id }.scale)
|
||||
}
|
||||
|
||||
private fun assertCross(elements: List<InputSurfaceElement>, width: Int, height: Int, ids: List<String>) {
|
||||
val (up, right, down, left) = ids.map { id -> elements.first { it.id == id }.let { (it.x + it.width / 2) * width to (it.y + it.height / 2) * height } }
|
||||
val cx = (up.first + right.first + down.first + left.first) / 4
|
||||
val cy = (up.second + right.second + down.second + left.second) / 4
|
||||
assertEquals(up.first, down.first, 1f)
|
||||
assertEquals(left.second, right.second, 1f)
|
||||
assertTrue(up.second < down.second && left.first < right.first)
|
||||
val reach = listOf(up, right, down, left).map { kotlin.math.hypot(it.first - cx, it.second - cy) }
|
||||
reach.forEach { assertEquals(reach[0], it, 1f) }
|
||||
}
|
||||
|
||||
private fun assertGamepadShape(elements: List<InputSurfaceElement>, width: Int, height: Int, label: String) {
|
||||
assertCross(elements, width, height, listOf("legacy:y", "legacy:b", "legacy:a", "legacy:x"))
|
||||
assertCross(elements, width, height, listOf("legacy:up", "legacy:right", "legacy:down", "legacy:left"))
|
||||
assertEquals(label, emptyList<Pair<String, String>>(), overlapping(elements, width, height))
|
||||
}
|
||||
|
||||
@Test @Config(qualifiers = "w833dp-h468dp-land-369dpi")
|
||||
fun buttonSizeKeepsTheGamepadShapeAtHandheldDensity() {
|
||||
for ((w, h) in listOf(1920 to 1080, 1920 to 1200)) {
|
||||
val normal = LegacyGamepadLayout(context, w, h).elements()
|
||||
assertGamepadShape(normal, w, h, "$w x $h")
|
||||
val right = setOf("legacy:a", "legacy:b", "legacy:x", "legacy:y", "legacy:rs", "legacy:rb", "legacy:rt", "legacy:start")
|
||||
val left = setOf("legacy:up", "legacy:right", "legacy:down", "legacy:left", "legacy:ls", "legacy:lb", "legacy:lt", "legacy:select")
|
||||
val moved = normal.map { e ->
|
||||
when (e.id) {
|
||||
in right -> e.copy(x = e.x + 21f / w, y = e.y + 18f / h)
|
||||
in left -> e.copy(x = e.x - 20f / w, y = e.y + 15f / h)
|
||||
else -> e
|
||||
}
|
||||
}
|
||||
for (scale in listOf(.8f, 1.25f)) {
|
||||
val generator = LegacyGamepadLayout(context, w, h, scale = scale)
|
||||
assertGamepadShape(generator.elements(), w, h, "$w x $h generated at $scale")
|
||||
val rescaled = generator.rescale(moved, LegacyGamepadLayout(context, w, h))
|
||||
assertGamepadShape(rescaled, w, h, "$w x $h moved at $scale")
|
||||
val a = rescaled.first { it.id == "legacy:a" }
|
||||
val generatedA = generator.elements().first { it.id == "legacy:a" }
|
||||
assertEquals(generatedA.x + 21f / w, a.x, .001f)
|
||||
assertEquals(generatedA.y + 18f / h, a.y, .001f)
|
||||
assertEquals(moved, LegacyGamepadLayout(context, w, h).rescale(rescaled, generator).let { back ->
|
||||
back.zip(moved).map { (b, m) -> if (kotlin.math.abs(b.x - m.x) < .001f && kotlin.math.abs(b.y - m.y) < .001f && kotlin.math.abs(b.width - m.width) < .001f) m else b }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,11 +19,12 @@ class InputLibraryTest {
|
||||
for (name in listOf("input-profiles", "input-surfaces", "controller")) context.getSharedPreferences(name, Context.MODE_PRIVATE).edit().clear().commit()
|
||||
}
|
||||
|
||||
@Test fun freshLibraryHasOnlyTheMainGamepadAndTwoLowerScreenLayouts() {
|
||||
@Test fun freshLibraryHasTheMainGamepadAndTheStockLowerScreenLayouts() {
|
||||
val library = InputLibraries.read(context)
|
||||
assertEquals(listOf("game", "desktop"), library.profiles.map { it.id })
|
||||
assertEquals(setOf(InputLibraries.OVERLAY, InputLibraries.DECK, InputLibraries.TRACKPAD), library.layouts.map { it.id }.toSet())
|
||||
assertEquals(6, library.bindings.size)
|
||||
assertEquals(setOf(InputLibraries.OVERLAY, InputLibraries.TRACKPAD) + DeckPanel.entries.map { it.layout }, library.layouts.map { it.id }.toSet())
|
||||
assertEquals(10, library.bindings.size)
|
||||
for (panel in DeckPanel.entries) assertEquals(panel.layout, library.panelLayout(false, panel.bindings)?.id)
|
||||
assertEquals(InputLibraries.DECK, library.activeLayout(false, InputRole.SECONDARY)?.id)
|
||||
assertEquals(InputLibraries.TRACKPAD, library.activeLayout(true, InputRole.SECONDARY)?.id)
|
||||
assertEquals(InputAction.Pointer(), library.compileActive(true).action(InputRole.PHYSICAL, InputControl.LS))
|
||||
@@ -32,22 +33,18 @@ class InputLibraryTest {
|
||||
val desktop = library.activeLayout(true, InputRole.SECONDARY)!!
|
||||
val pad = desktop.elements.single { it.kind == InputElementKind.TRACKPAD }
|
||||
assertTrue(pad.mouseGestures)
|
||||
assertEquals(3, desktop.elements.size)
|
||||
assertEquals(1, desktop.elements.size)
|
||||
assertEquals(InputAction.Pointer(), library.compileActive(true).elementAction(InputRole.SECONDARY, pad.id, pad.control))
|
||||
assertEquals(InputAction.MouseButton(272), library.compileActive(true).elementClickAction(InputRole.SECONDARY, pad))
|
||||
val game = library.activeLayout(false, InputRole.SECONDARY)!!
|
||||
assertEquals(9, game.elements.size)
|
||||
assertEquals(6, game.elements.size)
|
||||
assertEquals(setOf(InputControl.LEFT_PAD, InputControl.RIGHT_PAD), game.elements.filter { it.kind == InputElementKind.TRACKPAD }.map { it.control }.toSet())
|
||||
for (control in listOf(InputControl.L4, InputControl.L5, InputControl.R4, InputControl.R5)) {
|
||||
val element = game.elements.single { it.control == control }
|
||||
assertEquals(InputAction.Native(), library.compileActive(false).elementAction(InputRole.SECONDARY, element.id, element.control))
|
||||
}
|
||||
for ((isDesktop, commands) in listOf(true to listOf(InputCommand.MENU, InputCommand.KEYBOARD),
|
||||
false to listOf(InputCommand.STEAM, InputCommand.QUICK_ACCESS, InputCommand.MENU))) {
|
||||
val elements = library.activeLayout(isDesktop, InputRole.SECONDARY)!!.elements.filter { it.id.startsWith("command:") }
|
||||
assertEquals(commands.map { InputAction.Command(it) }, elements.map { library.compileActive(isDesktop).elementAction(InputRole.SECONDARY, it.id, it.control) })
|
||||
assertTrue(elements.all { InputButtonIcons.has(it.icon) && it.icon > 255 })
|
||||
}
|
||||
for (layout in InputStockLayouts.layouts()) assertTrue(layout.elements.none { it.id.startsWith("command:") })
|
||||
assertTrue(game.elements.filter { it.kind == InputElementKind.TRACKPAD }.all { it.y == .02f })
|
||||
assertEquals(library, InputLibraries.decode(InputLibraries.encode(library)))
|
||||
}
|
||||
|
||||
@@ -71,11 +68,11 @@ class InputLibraryTest {
|
||||
assertEquals(original, InputLibraries.read(context))
|
||||
}
|
||||
|
||||
@Test fun resettingDefaultActionsKeepsTheMenuAndKeyboardCommands() {
|
||||
@Test fun resettingDefaultActionsKeepsTheStockPanelActions() {
|
||||
val library = InputLibraries.read(context)
|
||||
for (id in listOf("game", "desktop")) {
|
||||
val reset = library.resetProfile(id).validate()
|
||||
for (element in library.layout(id, InputRole.SECONDARY)!!.elements.filter { it.id.startsWith("command:") }) {
|
||||
for (element in library.layout(id, InputRole.SECONDARY)!!.elements) {
|
||||
assertEquals(library.compile(id).elementAction(InputRole.SECONDARY, element.id, element.control),
|
||||
reset.compile(id).elementAction(InputRole.SECONDARY, element.id, element.control))
|
||||
}
|
||||
@@ -460,7 +457,7 @@ class InputLibraryTest {
|
||||
assertTrue(upgraded.layout("game", InputRole.SECONDARY)!!.editable)
|
||||
val output = upgraded.compile("game")
|
||||
assertEquals(InputAction.Keys(listOf(57)), output.elementAction(InputRole.SECONDARY, "legacy:l4", InputControl.L4))
|
||||
assertEquals(InputAction.Command(InputCommand.MENU), output.elementAction(InputRole.SECONDARY, "command:0", InputControl.A))
|
||||
assertEquals(InputStockLayouts.layouts().single { it.id == InputLibraries.DECK }.elements, upgraded.layout("game", InputRole.SECONDARY)!!.elements)
|
||||
assertEquals(upgraded, InputLibraries.read(context))
|
||||
}
|
||||
|
||||
@@ -473,7 +470,9 @@ class InputLibraryTest {
|
||||
val copy = changed.layout("game", role)!!
|
||||
assertNotEquals(layout.id, copy.id)
|
||||
assertEquals(layout.elements, copy.elements)
|
||||
assertEquals(InputAction.Command(InputCommand.MENU), changed.compile("game").elementAction(role, "command:0", InputControl.A))
|
||||
val stock = InputStockLayouts.presets(listOf(layout)).single()
|
||||
for (element in layout.elements) assertEquals(stock.elements[element.id] ?: stock.controls[element.control] ?: InputAction.Native(),
|
||||
changed.compile("game").elementAction(role, element.id, element.control))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,4 +532,64 @@ class InputLibraryTest {
|
||||
assertEquals(ControllerPrefs.STEAM_BLUE, upgraded.layouts.single { it.id == InputLibraries.OVERLAY }.style.tint)
|
||||
assertEquals(upgraded, InputLibraries.read(context))
|
||||
}
|
||||
private fun versionElevenPanel(layout: SavedInputLayout, commands: List<Int>, padTop: Float = .14f) = layout.copy(elements = commands.mapIndexed { position, i ->
|
||||
InputSurfaceElement(InputControl.A, .02f + position * .3f, .01f, .28f, .11f, "command:$i", name = "Command $i", icon = InputButtonIcons.MENU)
|
||||
} + layout.elements.map { if (it.kind == InputElementKind.TRACKPAD) it.copy(y = padTop, height = it.y + it.height - padTop) else it })
|
||||
|
||||
private fun versionElevenLibrary(change: (InputLibrary) -> InputLibrary = { it }): InputLibrary {
|
||||
val fresh = InputLibraries.read(context)
|
||||
val stock = InputStockLayouts.layouts()
|
||||
var old = fresh.copy(layouts = fresh.layouts.filter { it.id == InputLibraries.OVERLAY || it.id == InputLibraries.DECK || it.id == InputLibraries.TRACKPAD },
|
||||
bindings = fresh.bindings.filter { b -> DeckPanel.entries.none { it != DeckPanel.BOTH && it.bindings == b.id } })
|
||||
old = old.withLayout(versionElevenPanel(stock.single { it.id == InputLibraries.DECK }, listOf(2, 3, 0)))
|
||||
.withLayout(versionElevenPanel(stock.single { it.id == InputLibraries.TRACKPAD }, listOf(0, 1)))
|
||||
old = old.copy(bindings = old.bindings.map { b ->
|
||||
when (b.layoutId) {
|
||||
InputLibraries.DECK -> b.copy(elements = b.elements + mapOf("command:0" to InputAction.Command(InputCommand.MENU), "command:2" to InputAction.Command(InputCommand.STEAM)))
|
||||
InputLibraries.TRACKPAD -> b.copy(elements = b.elements + ("command:1" to InputAction.Command(InputCommand.KEYBOARD)))
|
||||
else -> b
|
||||
}
|
||||
})
|
||||
return change(old).validate()
|
||||
}
|
||||
|
||||
private fun storeVersionEleven(library: InputLibrary) {
|
||||
prefs.edit().putString("library", JSONObject(InputLibraries.encode(library)).put("version", 11).toString()).commit()
|
||||
}
|
||||
|
||||
@Test fun versionTwelveMovesStockPanelCommandsToTheBarAndAddsTheDeckTabs() {
|
||||
val mine = SavedInputLayout("mine", "Mine", listOf(InputSurfaceElement(InputControl.A, .1f, .1f, .2f, .2f, "command:0", name = "Menu")),
|
||||
screen = InputLayoutScreen.SECONDARY)
|
||||
val minePreset = SavedInputBindings("mine.bindings", "Mine", false, mine.id, elements = mapOf("command:0" to InputAction.Command(InputCommand.MENU)))
|
||||
val old = versionElevenLibrary { it.withLayout(mine).withPreset(minePreset) }
|
||||
assertTrue(old.layouts.single { it.id == InputLibraries.DECK }.elements.any { it.id.startsWith("command:") })
|
||||
storeVersionEleven(old)
|
||||
val upgraded = InputLibraries.read(context)
|
||||
val stock = InputStockLayouts.layouts()
|
||||
for (id in listOf(InputLibraries.DECK, InputLibraries.TRACKPAD))
|
||||
assertEquals(stock.single { it.id == id }.elements, upgraded.layouts.single { it.id == id }.elements)
|
||||
assertTrue(upgraded.bindings.filter { it.layoutId == InputLibraries.DECK || it.layoutId == InputLibraries.TRACKPAD }
|
||||
.all { b -> b.elements.keys.none { it.startsWith("command:") } })
|
||||
assertEquals(InputAction.Pointer(), upgraded.preset(InputStockLayouts.TRACKPAD).elements["legacy:right-pad"])
|
||||
assertEquals(mine, upgraded.layouts.single { it.id == mine.id })
|
||||
assertEquals(minePreset, upgraded.preset(minePreset.id))
|
||||
for (panel in DeckPanel.entries) {
|
||||
assertEquals(stock.single { it.id == panel.layout }, upgraded.layouts.single { it.id == panel.layout })
|
||||
assertEquals(panel.layout, upgraded.preset(panel.bindings).layoutId)
|
||||
}
|
||||
assertEquals(old.profiles, upgraded.profiles)
|
||||
assertEquals(upgraded, InputLibraries.read(context))
|
||||
}
|
||||
|
||||
@Test fun versionTwelveLeavesEditedStockPanelsAlone() {
|
||||
val old = versionElevenLibrary { library ->
|
||||
val trackpad = library.layouts.single { it.id == InputLibraries.TRACKPAD }
|
||||
library.withLayout(trackpad.copy(elements = trackpad.elements.map { if (it.kind == InputElementKind.TRACKPAD) it.copy(x = .1f, width = .8f) else it }))
|
||||
}
|
||||
storeVersionEleven(old)
|
||||
val upgraded = InputLibraries.read(context)
|
||||
assertEquals(old.layouts.single { it.id == InputLibraries.TRACKPAD }, upgraded.layouts.single { it.id == InputLibraries.TRACKPAD })
|
||||
assertEquals(old.preset(InputStockLayouts.TRACKPAD), upgraded.preset(InputStockLayouts.TRACKPAD))
|
||||
assertEquals(InputStockLayouts.layouts().single { it.id == InputLibraries.DECK }.elements, upgraded.layouts.single { it.id == InputLibraries.DECK }.elements)
|
||||
}
|
||||
}
|
||||
@@ -70,8 +70,6 @@ class InputProfilesTest {
|
||||
assertEquals(InputProfile.defaults(InputProfile.GAME).bindings, profile.bindings)
|
||||
assertEquals(mapOf(
|
||||
InputRole.PRIMARY to mapOf("builtin:keyboard" to InputAction.Command(InputCommand.KEYBOARD)),
|
||||
InputRole.SECONDARY to mapOf("command:0" to InputAction.Command(InputCommand.MENU),
|
||||
"command:2" to InputAction.Command(InputCommand.STEAM), "command:3" to InputAction.Command(InputCommand.QUICK_ACCESS)),
|
||||
), profile.elements)
|
||||
}
|
||||
|
||||
|
||||
@@ -146,9 +146,28 @@ class InputRouterTest {
|
||||
val source = router.pad(InputRole.PHYSICAL)
|
||||
val raw = PadState()
|
||||
for (value in listOf(.6f, .5f, .4f, .6f, .3f, .6f)) { raw.leftTrigger = value; source.route(raw) }
|
||||
assertEquals(listOf("MENU"), output.events)
|
||||
raw.leftTrigger = 0f; source.route(raw)
|
||||
assertEquals(listOf("MENU", "MENU"), output.events)
|
||||
}
|
||||
|
||||
@Test fun commandsFireOnReleaseAndNotWhenCancelled() {
|
||||
router.setProfile(bind(InputControl.A, InputAction.Command(InputCommand.KEYBOARD), InputRole.PRIMARY))
|
||||
val button = router.channel(InputRole.PRIMARY, InputControl.A)
|
||||
button.update(1f)
|
||||
assertTrue(output.events.isEmpty())
|
||||
button.update(0f)
|
||||
assertEquals(listOf("KEYBOARD"), output.events)
|
||||
button.update(1f)
|
||||
button.release()
|
||||
button.update(0f)
|
||||
router.releaseAll()
|
||||
button.update(1f)
|
||||
router.releaseAll()
|
||||
button.update(0f)
|
||||
assertEquals(listOf("KEYBOARD"), output.events)
|
||||
}
|
||||
|
||||
@Test fun pointerTicksOnlyWhileMovingAndOrdinaryKeysDoNotWaitForTick() {
|
||||
router.setProfile(InputProfile.defaults(InputProfile.DESKTOP))
|
||||
val source = router.pad(InputRole.PHYSICAL)
|
||||
|
||||
@@ -25,7 +25,7 @@ class OnScreenControlsTest {
|
||||
private var time = 1000L
|
||||
@Before fun setup() {
|
||||
view = OnScreenControls(context, bridge)
|
||||
view.updateLayout(SavedInputLayout("test", "Test", listOf(left, button)))
|
||||
view.updateLayout(SavedInputLayout("test", "Test", listOf(left, button), aspect = ASPECT))
|
||||
measure(view)
|
||||
}
|
||||
@After fun close() { view.releaseAll(); bridge.stop() }
|
||||
@@ -102,7 +102,7 @@ class OnScreenControlsTest {
|
||||
|
||||
@Test fun floatingAndFixedSticksUseTheirConfiguredOrigin() {
|
||||
for (floating in listOf(true, false)) {
|
||||
view.updateLayout(SavedInputLayout("test", "Test", listOf(left.copy(floating = floating))))
|
||||
view.updateLayout(SavedInputLayout("test", "Test", listOf(left.copy(floating = floating)), aspect = ASPECT))
|
||||
measure(view)
|
||||
touch(MotionEvent.ACTION_DOWN, 3 to (230f to 300f))
|
||||
assertEquals(if (floating) 0f else .5f, state().leftX, .001f)
|
||||
@@ -110,16 +110,18 @@ class OnScreenControlsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun systemOnlyVisibilityUsesTheSameLayoutAndReleasesOtherButtons() {
|
||||
@Test fun systemOnlyVisibilityMovesSteamAndQamToTheBottomCornersAndReleasesOtherButtons() {
|
||||
val guide = InputSurfaceElement(InputControl.GUIDE, .4f, .7f, .1f, .2f)
|
||||
view.updateLayout(SavedInputLayout("test", "Test", listOf(button, guide)))
|
||||
view.updateLayout(SavedInputLayout("test", "Test", listOf(button, guide), aspect = ASPECT))
|
||||
measure(view)
|
||||
touch(MotionEvent.ACTION_DOWN, 0 to (800f to 250f))
|
||||
view.setButtonsOnly(true)
|
||||
measure(view)
|
||||
assertFalse(state().isDown(PadState.A))
|
||||
assertFalse(view.takesTouchAt(800f, 250f))
|
||||
assertTrue(view.takesTouchAt(450f, 480f))
|
||||
assertFalse(view.takesTouchAt(450f, 480f))
|
||||
assertTrue(view.takesTouchAt(44f, 556f))
|
||||
assertTrue(view.takesTouchAt(956f, 556f))
|
||||
}
|
||||
|
||||
@Test fun aCancelledSecondFingerDoesNotArmAStickClick() {
|
||||
@@ -177,7 +179,7 @@ class OnScreenControlsTest {
|
||||
|
||||
@Test fun theQuickToggleHidesEverythingButTheKeyboardAndShowsItAgain() {
|
||||
val keyboard = InputSurfaceElement(InputControl.A, .4f, .4f, .1f, .1f, "builtin:keyboard", name = "Keyboard")
|
||||
view.updateLayout(SavedInputLayout("test", "Test", listOf(left, button, keyboard)))
|
||||
view.updateLayout(SavedInputLayout("test", "Test", listOf(left, button, keyboard), aspect = ASPECT))
|
||||
measure(view)
|
||||
val density = context.resources.displayMetrics.density
|
||||
val x = 34 * density
|
||||
@@ -199,9 +201,12 @@ class OnScreenControlsTest {
|
||||
assertTrue(view.takesTouchAt(800f, 250f))
|
||||
view.setButtonsOnly(true)
|
||||
measure(view)
|
||||
assertFalse(view.takesTouchAt(x, y))
|
||||
touch(MotionEvent.ACTION_DOWN, 6 to (x to y)); touch(MotionEvent.ACTION_UP, 6 to (x to y))
|
||||
assertFalse(view.isQuickHidden)
|
||||
}
|
||||
|
||||
private companion object { const val ASPECT = 1000f / 600f }
|
||||
|
||||
private fun touch(action: Int, vararg pointers: Pair<Int, Pair<Float, Float>>, flags: Int = 0): Boolean {
|
||||
val properties = pointers.map { (id, _) -> MotionEvent.PointerProperties().apply { this.id = id; toolType = MotionEvent.TOOL_TYPE_FINGER } }.toTypedArray()
|
||||
val coords = pointers.map { (_, position) -> MotionEvent.PointerCoords().apply { x = position.first; y = position.second; pressure = 1f; size = 1f } }.toTypedArray()
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
package com.droiddeck.launcher.input
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [34], manifest = Config.NONE)
|
||||
class OnScreenLayoutTest {
|
||||
private val context: Context get() = RuntimeEnvironment.getApplication()
|
||||
private val prefs get() = context.getSharedPreferences("input-profiles", Context.MODE_PRIVATE)
|
||||
private val density get() = context.resources.displayMetrics.density
|
||||
|
||||
@Before fun reset() {
|
||||
for (name in listOf("input-profiles", "input-surfaces", "controller")) context.getSharedPreferences(name, Context.MODE_PRIVATE).edit().clear().commit()
|
||||
}
|
||||
|
||||
private fun gamepad() = InputLibraries.read(context).layouts.first { it.id == InputLibraries.OVERLAY }
|
||||
|
||||
private fun px(e: InputSurfaceElement, w: Int, h: Int) = floatArrayOf(e.x * w, e.y * h, e.width * w, e.height * h)
|
||||
|
||||
private fun assertSquare(e: InputSurfaceElement, w: Int, h: Int) = assertEquals(e.width * w, e.height * h, 1.5f)
|
||||
|
||||
private fun assertInside(elements: List<InputSurfaceElement>, w: Int, h: Int, safe: Rect = Rect()) {
|
||||
for (e in elements) {
|
||||
val (x, y, ew, eh) = px(e, w, h).toList()
|
||||
assertTrue("${e.id} left", x >= safe.left - .5f)
|
||||
assertTrue("${e.id} top", y >= safe.top - .5f)
|
||||
assertTrue("${e.id} right", x + ew <= w - safe.right + .5f)
|
||||
assertTrue("${e.id} bottom", y + eh <= h - safe.bottom + .5f)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun theBuiltInGamepadIsRegeneratedForEverySizeWithoutStretching() {
|
||||
val layout = gamepad()
|
||||
for ((w, h) in listOf(1200 to 540, 540 to 1200, 900 to 850)) {
|
||||
val placed = OnScreenLayout.elements(context, layout, w, h, Rect())
|
||||
assertEquals(layout.elements.map { it.id }, placed.map { it.id })
|
||||
assertEquals(LegacyGamepadLayout(context, w, h).regenerate(layout.elements), placed)
|
||||
for (id in listOf("legacy:a", "legacy:up", "legacy:guide")) assertSquare(placed.first { it.id == id }, w, h)
|
||||
assertInside(placed, w, h)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun regenerationKeepsTheUsersButtonStylesAndRemovedButtons() {
|
||||
val layout = gamepad().let { g -> g.copy(elements = g.elements.filterNot { it.id == "legacy:y" }.map { if (it.id == "legacy:a") it.copy(opacity = .4f, icon = 0, name = "Jump") else it }) }
|
||||
val placed = OnScreenLayout.elements(context, layout, 2000, 1000, Rect())
|
||||
assertNull(placed.firstOrNull { it.id == "legacy:y" })
|
||||
val a = placed.first { it.id == "legacy:a" }
|
||||
assertEquals(.4f, a.opacity)
|
||||
assertEquals("Jump", a.name)
|
||||
assertEquals(LegacyGamepadLayout(context, 2000, 1000).elements().first { it.id == "legacy:a" }.x, a.x, .0001f)
|
||||
}
|
||||
|
||||
@Test fun anEditedLayoutKeepsItsAspectAndCornersWhenTheScreenRotates() {
|
||||
val corner = InputSurfaceElement(InputControl.A, .85f, .7f, .1f, .2f)
|
||||
val left = InputSurfaceElement(InputControl.LS, .05f, .5f, .2f, .4f)
|
||||
val middle = InputSurfaceElement(InputControl.GUIDE, .45f, .05f, .1f, .2f)
|
||||
val layout = SavedInputLayout("edited", "Edited", listOf(left, corner, middle), aspect = 2f)
|
||||
assertEquals(layout.elements, OnScreenLayout.elements(context, layout, 2000, 1000, Rect()).map { it.copy(x = round(it.x), y = round(it.y), width = round(it.width), height = round(it.height)) })
|
||||
val portrait = OnScreenLayout.elements(context, layout, 1000, 2000, Rect())
|
||||
val (lx, ly, lw, lh) = px(portrait[0], 1000, 2000).toList()
|
||||
val (cx, cy, cw, ch) = px(portrait[1], 1000, 2000).toList()
|
||||
assertEquals(lw, lh, 1f)
|
||||
assertEquals(cw, ch, 1f)
|
||||
assertEquals(200f, lw, 1f)
|
||||
assertEquals(50f, lx, 1f)
|
||||
assertEquals(2000f, ly + lh + 50f, 1f)
|
||||
assertEquals(1000f - 50f, cx + cw, 1f)
|
||||
assertEquals(2000f - 50f, cy + ch, 1f)
|
||||
assertEquals(500f, px(portrait[2], 1000, 2000).let { it[0] + it[2] / 2f }, 1f)
|
||||
assertInside(portrait, 1000, 2000)
|
||||
}
|
||||
|
||||
private fun round(v: Float) = Math.round(v * 10000f) / 10000f
|
||||
|
||||
@Test fun controlsStayOutOfTheDisplayCutout() {
|
||||
val safe = Rect(120, 0, 0, 40)
|
||||
val generated = OnScreenLayout.elements(context, gamepad(), 2400, 1080, safe)
|
||||
assertInside(generated, 2400, 1080, safe)
|
||||
assertNotEquals(OnScreenLayout.elements(context, gamepad(), 2400, 1080, Rect()), generated)
|
||||
val edge = SavedInputLayout("edited", "Edited", listOf(InputSurfaceElement(InputControl.B, 0f, .9f, .05f, .1f)), aspect = 2400f / 1080)
|
||||
assertInside(OnScreenLayout.elements(context, edge, 2400, 1080, safe), 2400, 1080, safe)
|
||||
}
|
||||
|
||||
@Test fun steamAndQamOnlyModePutsLargeButtonsInTheBottomCornersAndTheKeyboardBetween() {
|
||||
val safe = Rect(80, 0, 30, 20)
|
||||
val placed = OnScreenLayout.elements(context, gamepad(), 1000, 500, safe, buttonsOnly = true)
|
||||
assertEquals(setOf(InputControl.GUIDE, InputControl.QAM, InputControl.A), placed.map { it.control }.toSet())
|
||||
val radius = 30 * density
|
||||
val inset = 44 * density
|
||||
fun centre(e: InputSurfaceElement) = (e.x + e.width / 2f) * 1000 to (e.y + e.height / 2f) * 500
|
||||
val guide = placed.first { it.control == InputControl.GUIDE }
|
||||
val qam = placed.first { it.control == InputControl.QAM }
|
||||
val keyboard = placed.first { it.id == "builtin:keyboard" }
|
||||
assertEquals(2 * radius, guide.width * 1000, .5f)
|
||||
assertEquals(80 + inset, centre(guide).first, .5f)
|
||||
assertEquals(500 - 20 - inset, centre(guide).second, .5f)
|
||||
assertEquals(1000 - 30 - inset, centre(qam).first, .5f)
|
||||
assertEquals(500f, centre(keyboard).first, .5f)
|
||||
assertEquals(500 - 20 - inset, centre(keyboard).second, .5f)
|
||||
val user = SavedInputLayout("edited", "Edited", listOf(InputSurfaceElement(InputControl.A, .5f, .5f, .1f, .1f)))
|
||||
assertEquals(setOf(InputControl.GUIDE, InputControl.QAM), OnScreenLayout.elements(context, user, 2000, 1000, Rect(), buttonsOnly = true).map { it.control }.toSet())
|
||||
}
|
||||
|
||||
@Test fun theUnfoldedStripUsesTheDockGeometryInLandscapeAndPortrait() {
|
||||
for ((size, portrait) in listOf((2208 to 800) to false, (1080 to 1300) to true)) {
|
||||
val (w, h) = size
|
||||
val placed = OnScreenLayout.elements(context, gamepad(), w, h, Rect(), dock = OnScreenLayout.Dock(portrait, grips = true))
|
||||
val boxes = GamepadGeometry.layout(w.toFloat(), h.toFloat(), density, portrait)
|
||||
val ls = placed.first { it.id == "legacy:ls" }
|
||||
val box = boxes.getValue(GamepadGeometry.Slot.LEFT_MAIN)
|
||||
assertEquals(box.left, ls.x * w, 1f)
|
||||
assertEquals(box.width, ls.width * w, 1f)
|
||||
assertEquals(box.height, ls.height * h, 1f)
|
||||
assertSquare(placed.first { it.id == "legacy:a" }, w, h)
|
||||
assertNull(placed.firstOrNull { it.control == InputControl.GUIDE || it.control == InputControl.QAM })
|
||||
assertEquals(portrait, placed.any { it.control == InputControl.L4 })
|
||||
assertInside(placed, w, h)
|
||||
val solid = placed.filter { it.kind != InputElementKind.STICK }
|
||||
for (a in solid) for (b in solid) if (a !== b) {
|
||||
val overlap = if (a.buttonShape == InputButtonShape.CIRCLE && b.buttonShape == InputButtonShape.CIRCLE)
|
||||
Math.hypot(((a.x + a.width / 2f) - (b.x + b.width / 2f)) * w.toDouble(), ((a.y + a.height / 2f) - (b.y + b.height / 2f)) * h.toDouble()) <
|
||||
(a.width * w + b.width * w) / 2f - .5f
|
||||
else a.x < b.x + b.width - .0001f && b.x < a.x + a.width - .0001f && a.y < b.y + b.height - .0001f && b.y < a.y + a.height - .0001f
|
||||
assertFalse("${a.id} overlaps ${b.id}", overlap)
|
||||
}
|
||||
}
|
||||
val user = SavedInputLayout("edited", "Edited", listOf(InputSurfaceElement(InputControl.A, .8f, .6f, .1f, .2f)), aspect = 2208f / 1768)
|
||||
val fitted = OnScreenLayout.elements(context, user, 2208, 800, Rect(), dock = OnScreenLayout.Dock(false, false)).single()
|
||||
assertEquals(.1f * 2208f / 1768 / .2f, fitted.width * 2208 / (fitted.height * 800), .01f)
|
||||
}
|
||||
|
||||
private val legacyKeys = "29+33:0.3,0.7,44::Find::0.6:1:1:1"
|
||||
|
||||
private fun importedOn(library: InputLibrary) = library.activeLayout(false, InputRole.PRIMARY)!!.elements.filter { it.id.startsWith("imported:") }
|
||||
|
||||
@Test fun shownScreenKeysAreDrawnWithTheGamepadAfterMigration() {
|
||||
val before = gamepad()
|
||||
prefs.edit().clear().commit()
|
||||
ControllerPrefs.prefs(context).edit().putString("screenKeys", legacyKeys).commit()
|
||||
val migrated = InputLibraries.read(context)
|
||||
val layout = migrated.activeLayout(false, InputRole.PRIMARY)!!
|
||||
assertEquals(InputLibraries.OVERLAY, layout.id)
|
||||
assertEquals(before.elements, layout.elements.filterNot { it.id.startsWith("imported:") })
|
||||
assertEquals(1, importedOn(migrated).size)
|
||||
assertEquals(InputAction.Keys(listOf(29, 33)), migrated.compileActive(false).elementAction(InputRole.PRIMARY, "imported:0", InputControl.A))
|
||||
assertEquals(InputAction.Native(), migrated.compileActive(false).elementAction(InputRole.PRIMARY, "legacy:a", InputControl.A))
|
||||
assertTrue(migrated.profiles.any { it.id == "migrated.screenkeys.0" })
|
||||
assertTrue(prefs.getBoolean(LegacyScreenKeyMigration.MERGED, false))
|
||||
assertEquals(migrated, InputLibraries.read(context))
|
||||
val placed = OnScreenLayout.elements(context, layout, 2400, 1080, Rect())
|
||||
assertEquals(layout.elements.map { it.id }, placed.map { it.id })
|
||||
}
|
||||
|
||||
@Test fun librariesMigratedBeforeTheMergeGetTheirScreenKeysBackOnceWithoutLosingEdits() {
|
||||
val fresh = InputLibraries.read(context)
|
||||
val backup = JSONObject().put("screenKeys", legacyKeys).toString()
|
||||
val old = LegacyScreenKeyMigration.migrate(context, fresh, backup)
|
||||
val bindings = old.activePart(false, InputRole.PRIMARY).bindings
|
||||
val edited = old.withPreset(old.preset(bindings).let { it.copy(controls = it.controls + (InputControl.A to InputAction.Keys(listOf(57)))) })
|
||||
prefs.edit().putString("library", InputLibraries.encode(edited)).putString(LegacyScreenKeyMigration.BACKUP, backup).commit()
|
||||
val merged = InputLibraries.read(context)
|
||||
assertEquals(1, importedOn(merged).size)
|
||||
assertEquals(InputAction.Keys(listOf(57)), merged.compileActive(false).action(InputRole.PRIMARY, InputControl.A))
|
||||
assertEquals(edited.profiles, merged.profiles)
|
||||
assertEquals(edited.layouts.map { it.id }.toSet(), merged.layouts.map { it.id }.toSet())
|
||||
assertEquals(edited.layouts.first { it.id == "migrated.screenkeys.0.layout" }, merged.layouts.first { it.id == "migrated.screenkeys.0.layout" })
|
||||
assertEquals(backup, prefs.getString(LegacyScreenKeyMigration.BACKUP, null))
|
||||
assertEquals(merged, InputLibraries.read(context))
|
||||
prefs.edit().remove(LegacyScreenKeyMigration.MERGED).commit()
|
||||
assertEquals(1, importedOn(InputLibraries.read(context)).size)
|
||||
}
|
||||
|
||||
@Test fun hiddenScreenKeysOrAProfileThatAlreadyShowsThemAreLeftAlone() {
|
||||
val fresh = InputLibraries.read(context)
|
||||
val hidden = JSONObject().put("screenKeys", legacyKeys).put("screenKeysShown", false).toString()
|
||||
val old = LegacyScreenKeyMigration.migrate(context, fresh, hidden)
|
||||
assertEquals(old, LegacyScreenKeyMigration.merge(old, hidden))
|
||||
val shown = JSONObject().put("screenKeys", legacyKeys).toString()
|
||||
val selected = old.selectProfile(false, "migrated.screenkeys.0").selectProfile(true, "migrated.screenkeys.0")
|
||||
assertEquals(selected, LegacyScreenKeyMigration.merge(selected, shown))
|
||||
}
|
||||
}
|
||||
@@ -143,6 +143,21 @@ class SettingsResetTest {
|
||||
assertEquals(defaultSurface, InputSurfaceLayout.read(app, InputProfile.DESKTOP))
|
||||
}
|
||||
|
||||
@Test fun inputLayoutsAndQuickButtonVisibilityReset() {
|
||||
val original = com.droiddeck.launcher.input.InputLibraries.read(app)
|
||||
val gamepad = original.layouts.first { it.id == com.droiddeck.launcher.input.InputLibraries.OVERLAY }
|
||||
com.droiddeck.launcher.input.InputLibraries.update(app) { library ->
|
||||
library.withLayout(gamepad.withQuickButton(com.droiddeck.launcher.input.InputCommand.STEAM, false)
|
||||
.copy(elements = gamepad.elements.map { it.copy(x = 0f, y = 0f) })).copyLayout(gamepad.id, "Mine", "mine")
|
||||
}
|
||||
|
||||
assertTrue(SettingsReset.resetAll(app, gameProfiles = false))
|
||||
|
||||
val reset = com.droiddeck.launcher.input.InputLibraries.read(app)
|
||||
assertEquals(original.layouts.map { it.id }.toSet(), reset.layouts.map { it.id }.toSet())
|
||||
assertEquals(gamepad, reset.layouts.first { it.id == gamepad.id })
|
||||
}
|
||||
|
||||
@Test fun gameTextureFilteringIsKeptUnlessGameProfilesAreReset() {
|
||||
session.edit().putString("gameTextureFiltering", """{"440":{"anisotropy":16}}""").commit()
|
||||
SettingsReset.resetAll(app, gameProfiles = false)
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.app.Presentation
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.view.Display
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.ui.test.*
|
||||
import com.droiddeck.launcher.input.*
|
||||
import com.droiddeck.launcher.R
|
||||
@@ -379,4 +380,147 @@ class InputSettingsTest {
|
||||
if (display.isValid) ShadowDisplayManager.removeDisplay(displayId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun elementPropertiesEditOpacityLabelsAndOfferImages() {
|
||||
val element = mutableStateOf(InputSurfaceElement(InputControl.A, .1f, .1f, .2f, .2f, "custom", name = "Custom button"))
|
||||
compose.setContent { DroidDeckTheme {
|
||||
androidx.compose.foundation.layout.Column(androidx.compose.ui.Modifier.verticalScroll(androidx.compose.foundation.rememberScrollState())) {
|
||||
InputElementProperties(element.value) { element.value = it }
|
||||
}
|
||||
} }
|
||||
compose.onNodeWithTag("setting-element-opacity").performScrollTo().performSemanticsAction(androidx.compose.ui.semantics.SemanticsActions.SetProgress) { it(60f) }
|
||||
compose.runOnIdle { assertEquals(.6f, element.value.opacity, .001f) }
|
||||
compose.onNodeWithTag("setting-element-label").performScrollTo().performClick()
|
||||
compose.runOnIdle { assertFalse(element.value.showLabel) }
|
||||
compose.onNodeWithText(context.getString(R.string.input_button_text)).performScrollTo().performClick()
|
||||
compose.onNodeWithText(context.getString(R.string.screen_key_image)).assertExists()
|
||||
compose.runOnIdle { element.value = element.value.copy(icon = InputButtonIcons.MENU) }
|
||||
compose.onNodeWithTag("setting-element-label").assertDoesNotExist()
|
||||
compose.runOnIdle { element.value = InputSurfaceElement(InputControl.LEFT_PAD, .1f, .1f, .4f, .4f, "pad", InputElementKind.TRACKPAD, "Pad") }
|
||||
compose.onNodeWithTag("setting-element-label").assertDoesNotExist()
|
||||
compose.onNodeWithTag("setting-element-opacity").assertExists()
|
||||
}
|
||||
|
||||
@Test fun editorScalesEveryControlAndRestoresStockPositions() {
|
||||
val library = InputLibraries.read(context)
|
||||
val layout = library.layout("game", InputRole.SECONDARY)!!
|
||||
assertEquals(InputLibraries.DECK, layout.id)
|
||||
val round = mutableStateOf(0)
|
||||
compose.setContent { DroidDeckTheme { androidx.compose.runtime.key(round.value) { InputSurfaceDialog("game", {}, {}, role = InputRole.PRIMARY,
|
||||
layoutId = layout.id, bindingsId = library.profile("game").binding(InputRole.SECONDARY)) } } }
|
||||
compose.onNodeWithTag("input-editor-tools").performClick()
|
||||
compose.onNodeWithText(context.getString(R.string.input_reset_positions)).performScrollTo().assertIsNotEnabled()
|
||||
compose.onNodeWithTag("input-editor-scale").performScrollTo().performSemanticsAction(androidx.compose.ui.semantics.SemanticsActions.SetProgress) { it(80f) }
|
||||
compose.onNodeWithText(context.getString(R.string.input_editor_done)).performScrollTo().performClick()
|
||||
val scaled = InputLibraries.read(context).layouts.first { it.id == layout.id }
|
||||
assertEquals(layout.elements.scaled(.8f), scaled.elements)
|
||||
compose.runOnIdle { round.value = 1 }
|
||||
compose.onNodeWithTag("input-editor-tools").performClick()
|
||||
compose.onNodeWithText(context.getString(R.string.input_reset_positions)).performScrollTo().performClick()
|
||||
compose.onNodeWithText(context.getString(R.string.input_editor_done)).performScrollTo().performClick()
|
||||
compose.runOnIdle { assertEquals(layout.elements, InputLibraries.read(context).layouts.first { it.id == layout.id }.elements) }
|
||||
}
|
||||
|
||||
@Test fun quickButtonTogglesHideBuiltInButtonsWithoutDeletingThem() {
|
||||
compose.setContent { DroidDeckTheme { InputSettingsPage({}) } }
|
||||
compose.onNodeWithTag("input-profile-game").performScrollTo().performClick()
|
||||
compose.onNodeWithTag("input-part-primary").performScrollTo().performClick()
|
||||
val before = InputLibraries.read(context).layout("game", InputRole.PRIMARY)!!
|
||||
compose.onNodeWithTag("setting-quick-keyboard").performScrollTo().performClick()
|
||||
compose.runOnIdle {
|
||||
val after = InputLibraries.read(context).layout("game", InputRole.PRIMARY)!!
|
||||
assertEquals(before.elements, after.elements)
|
||||
assertEquals(setOf(InputCommand.KEYBOARD), after.style.hidden)
|
||||
}
|
||||
compose.onNodeWithTag("setting-quick-keyboard").performScrollTo().performClick()
|
||||
compose.runOnIdle { assertTrue(InputLibraries.read(context).layout("game", InputRole.PRIMARY)!!.style.hidden.isEmpty()) }
|
||||
}
|
||||
|
||||
@Test fun layoutsCanBeImportedAndExported() {
|
||||
val source = java.io.File(context.cacheDir, "jump.icp").apply {
|
||||
writeText("""{"name":"Jump keys","elements":[{"type":"BUTTON","shape":"CIRCLE","bindings":["KEY_SPACE"],"scale":1.0,"x":0.8,"y":0.7,"text":"Jump"}]}""")
|
||||
}
|
||||
val target = java.io.File(context.cacheDir, "out.icp").apply { delete() }
|
||||
val registry = object : androidx.activity.result.ActivityResultRegistry() {
|
||||
override fun <I, O> onLaunch(requestCode: Int, contract: androidx.activity.result.contract.ActivityResultContract<I, O>, input: I,
|
||||
options: androidx.core.app.ActivityOptionsCompat?) {
|
||||
dispatchResult(requestCode, android.net.Uri.fromFile(if (input is String) target else source))
|
||||
}
|
||||
}
|
||||
val owner = object : androidx.activity.result.ActivityResultRegistryOwner { override val activityResultRegistry = registry }
|
||||
compose.setContent { androidx.compose.runtime.CompositionLocalProvider(androidx.activity.compose.LocalActivityResultRegistryOwner provides owner) {
|
||||
DroidDeckTheme { InputSettingsPage({}) }
|
||||
} }
|
||||
compose.onNodeWithTag("input-profile-game").performScrollTo().performClick()
|
||||
compose.onNodeWithTag("input-part-primary").performScrollTo().performClick()
|
||||
compose.onNodeWithText(context.getString(R.string.input_saved_layouts)).performScrollTo().performClick()
|
||||
compose.onNodeWithTag("layout-manage-${InputLibraries.OVERLAY}").performScrollTo().performClick()
|
||||
compose.onNodeWithText(context.getString(R.string.screen_key_layout_export)).assertDoesNotExist()
|
||||
compose.onNodeWithText(context.getString(R.string.common_close)).performClick()
|
||||
compose.onNodeWithTag("input-layout-import").performScrollTo().performClick()
|
||||
compose.waitUntil(5_000) { InputLibraries.read(context).layout("game", InputRole.PRIMARY)!!.name == "Jump keys" }
|
||||
val imported = InputLibraries.read(context).layout("game", InputRole.PRIMARY)!!
|
||||
assertEquals(InputLayoutScreen.MAIN, imported.screen)
|
||||
assertEquals(InputAction.Keys(listOf(57)), InputLibraries.read(context).compile("game").elementAction(InputRole.PRIMARY, imported.elements.single().id, InputControl.A))
|
||||
compose.onNodeWithText(context.getString(R.string.input_saved_layouts)).performScrollTo().performClick()
|
||||
compose.onNodeWithTag("layout-manage-${imported.id}").performScrollTo().performClick()
|
||||
compose.onNodeWithText(context.getString(R.string.screen_key_layout_export)).performClick()
|
||||
compose.waitUntil(5_000) { target.isFile && target.length() > 0 }
|
||||
assertEquals(source.readText().let { org.json.JSONObject(it).getString("name") }, org.json.JSONObject(target.readText()).getString("name"))
|
||||
assertEquals("KEY_SPACE", org.json.JSONObject(target.readText()).getJSONArray("elements").getJSONObject(0).getJSONArray("bindings").getString(0))
|
||||
}
|
||||
|
||||
@Test fun buttonSizeRegeneratesTheGamepadAndUndoesAsOneStep() {
|
||||
val library = InputLibraries.read(context)
|
||||
val layout = library.layout("game", InputRole.PRIMARY)!!
|
||||
val (_, metrics) = InputLibraries.primaryDisplay(context)
|
||||
assertNotNull(OnScreenLayout.generatedSize(context, layout, metrics.widthPixels, metrics.heightPixels))
|
||||
compose.setContent { DroidDeckTheme { InputSurfaceDialog("game", {}, {}, role = InputRole.PRIMARY,
|
||||
layoutId = layout.id, bindingsId = library.profile("game").binding(InputRole.PRIMARY)) } }
|
||||
compose.onNodeWithTag("input-editor-tools").performClick()
|
||||
val slider = compose.onNodeWithTag("input-editor-scale").performScrollTo()
|
||||
slider.assert(SemanticsMatcher.expectValue(androidx.compose.ui.semantics.SemanticsProperties.StateDescription, "100%"))
|
||||
for (value in listOf(110f, 125f)) slider.performSemanticsAction(androidx.compose.ui.semantics.SemanticsActions.SetProgress) { it(value) }
|
||||
compose.onNodeWithText(context.getString(R.string.input_editor_undo)).performScrollTo().performClick()
|
||||
slider.assert(SemanticsMatcher.expectValue(androidx.compose.ui.semantics.SemanticsProperties.StateDescription, "100%"))
|
||||
slider.performSemanticsAction(androidx.compose.ui.semantics.SemanticsActions.SetProgress) { it(125f) }
|
||||
compose.onNodeWithText(context.getString(R.string.input_editor_done)).performScrollTo().performClick()
|
||||
compose.runOnIdle {
|
||||
val saved = InputLibraries.read(context).layouts.first { it.id == layout.id }
|
||||
assertEquals(1.25f, saved.scale)
|
||||
assertNotNull(OnScreenLayout.generatedSize(context, saved, metrics.widthPixels, metrics.heightPixels))
|
||||
assertNotEquals(layout.elements.first { it.id == "legacy:a" }.y, saved.elements.first { it.id == "legacy:a" }.y)
|
||||
}
|
||||
}
|
||||
|
||||
@Test @Config(qualifiers = "w833dp-h468dp-land-369dpi")
|
||||
fun buttonSizeKeepsMovedGamepadGroupsInShape() {
|
||||
val face = setOf("legacy:a", "legacy:b", "legacy:x", "legacy:y")
|
||||
val original = InputLibraries.read(context)
|
||||
val gamepad = original.layout("game", InputRole.PRIMARY)!!
|
||||
val moved = gamepad.copy(elements = gamepad.elements.map { if (it.id in face) it.copy(x = it.x + .012f, y = it.y + .017f) else it })
|
||||
InputLibraries.update(context) { it.withLayout(moved) }
|
||||
val (_, metrics) = InputLibraries.primaryDisplay(context)
|
||||
assertNull(OnScreenLayout.generatedSize(context, moved, metrics.widthPixels, metrics.heightPixels))
|
||||
val library = InputLibraries.read(context)
|
||||
compose.setContent { DroidDeckTheme { InputSurfaceDialog("game", {}, {}, role = InputRole.PRIMARY,
|
||||
layoutId = moved.id, bindingsId = library.profile("game").binding(InputRole.PRIMARY)) } }
|
||||
compose.onNodeWithTag("input-editor-tools").performClick()
|
||||
compose.onNodeWithTag("input-editor-scale").performScrollTo().performSemanticsAction(androidx.compose.ui.semantics.SemanticsActions.SetProgress) { it(125f) }
|
||||
compose.onNodeWithText(context.getString(R.string.input_editor_done)).performScrollTo().performClick()
|
||||
compose.runOnIdle {
|
||||
val saved = InputLibraries.read(context).layouts.first { it.id == moved.id }
|
||||
assertEquals(1.25f, saved.scale)
|
||||
val w = metrics.widthPixels; val h = metrics.heightPixels
|
||||
fun centre(id: String) = saved.elements.first { it.id == id }.let { (it.x + it.width / 2) * w to (it.y + it.height / 2) * h }
|
||||
assertEquals(centre("legacy:y").first, centre("legacy:a").first, 1f)
|
||||
assertEquals(centre("legacy:x").second, centre("legacy:b").second, 1f)
|
||||
assertTrue(centre("legacy:y").second < centre("legacy:x").second && centre("legacy:x").second < centre("legacy:a").second)
|
||||
assertEquals(centre("legacy:a").second - centre("legacy:y").second, centre("legacy:b").first - centre("legacy:x").first, 1f)
|
||||
assertEquals(centre("legacy:up").first, centre("legacy:down").first, 1f)
|
||||
assertEquals(centre("legacy:left").second, centre("legacy:right").second, 1f)
|
||||
val before = moved.elements.first { it.id == "legacy:a" }
|
||||
assertTrue(saved.elements.first { it.id == "legacy:a" }.width > before.width * 1.2f)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,8 +93,7 @@ class InputSurfaceOwnershipTest {
|
||||
|
||||
@Test fun removingAButtonReleasesOnlyItsOwnInput() {
|
||||
val buttons = child("HoldButton")
|
||||
buttons.layout(0, 0, 300, 300)
|
||||
touch(buttons, MotionEvent.ACTION_DOWN, 150f, 240f)
|
||||
press(buttons)
|
||||
assertTrue(state().isDown(PadState.A))
|
||||
val position = JoyConPadTest.RecordingWriter.deckPads.copyOf()
|
||||
(buttons.parent as ViewGroup).removeView(buttons)
|
||||
@@ -123,8 +122,7 @@ class InputSurfaceOwnershipTest {
|
||||
|
||||
private fun holdFaceButton() {
|
||||
val buttons = child("HoldButton")
|
||||
buttons.layout(0, 0, 300, 300)
|
||||
touch(buttons, MotionEvent.ACTION_DOWN, 150f, 240f)
|
||||
press(buttons)
|
||||
}
|
||||
|
||||
private fun assertTrackpadStillHeld(position: ShortArray) {
|
||||
@@ -139,6 +137,11 @@ class InputSurfaceOwnershipTest {
|
||||
if (view is ViewGroup) for (i in 0 until view.childCount) yieldAll(descendants(view.getChildAt(i)))
|
||||
}
|
||||
|
||||
private fun press(button: View) {
|
||||
button.javaClass.getDeclaredMethod("press", Int::class.java, Boolean::class.java, Boolean::class.java)
|
||||
.apply { isAccessible = true }.invoke(button, 0, true, false)
|
||||
}
|
||||
|
||||
private fun touch(view: View, action: Int, x: Float, y: Float, fingers: Int = 1) {
|
||||
val properties = Array(fingers) { i -> MotionEvent.PointerProperties().apply { id = i; toolType = MotionEvent.TOOL_TYPE_FINGER } }
|
||||
val coords = Array(fingers) { MotionEvent.PointerCoords().apply { this.x = x; this.y = y; pressure = 1f; size = 1f } }
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
package com.droiddeck.launcher.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.ComponentActivity
|
||||
import com.droiddeck.launcher.input.*
|
||||
import java.io.File
|
||||
import org.junit.After
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [34], manifest = Config.NONE, shadows = [JoyConPadTest.RecordingWriter::class])
|
||||
class InputSurfaceTouchTest {
|
||||
private val context: Context get() = RuntimeEnvironment.getApplication()
|
||||
private val bridge = PadBridge(File(context.cacheDir, "surface-touch"))
|
||||
private val events = mutableListOf<String>()
|
||||
private val router = InputRouter(object : InputOutput {
|
||||
override fun key(code: Int, down: Boolean) { events += "key $code $down" }
|
||||
override fun button(code: Int, down: Boolean) {}
|
||||
override fun pointer(dx: Float, dy: Float) {}
|
||||
override fun scroll(steps: Int) {}
|
||||
override fun command(command: InputCommand) { events += command.name }
|
||||
override fun command(command: InputCommand, role: InputRole) { events += "${command.name}:$role" }
|
||||
override fun requestMotion() {}
|
||||
})
|
||||
private lateinit var view: OnScreenControls
|
||||
private val a = InputSurfaceElement(InputControl.A, .7f, .3f, .2f, .2f)
|
||||
private val b = InputSurfaceElement(InputControl.B, .7f, .6f, .2f, .2f)
|
||||
private val stick = InputSurfaceElement(InputControl.LS, .1f, .3f, .2f, .4f, floating = false)
|
||||
private val keyboard = InputSurfaceElement(InputControl.A, .4f, .8f, .1f, .1f, "builtin:keyboard", name = "Keyboard")
|
||||
private var time = 1000L
|
||||
|
||||
@Before fun setup() {
|
||||
bridge.setInputRouter(router)
|
||||
bridge.setInputProfile(InputProfile("touch", elements = mapOf(InputRole.PRIMARY to mapOf(
|
||||
"builtin:keyboard" to InputAction.Command(InputCommand.KEYBOARD), "latch" to InputAction.Keys(listOf(42))))))
|
||||
view = OnScreenControls(context, bridge)
|
||||
show(a, b, stick, keyboard)
|
||||
}
|
||||
|
||||
@After fun close() { view.releaseAll(); bridge.stop() }
|
||||
|
||||
private fun show(vararg elements: InputSurfaceElement) {
|
||||
view.updateLayout(SavedInputLayout("touch", "Touch", elements.toList(), aspect = 1000f / 600f))
|
||||
measure(view)
|
||||
}
|
||||
|
||||
private fun measure(target: View) {
|
||||
target.measure(View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(600, View.MeasureSpec.EXACTLY))
|
||||
target.layout(0, 0, 1000, 600)
|
||||
}
|
||||
|
||||
private fun state() = JoyConPadTest.RecordingWriter.pads[0] ?: PadState()
|
||||
|
||||
@Test fun aFingerSlidingBetweenButtonsMovesThePress() {
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (800f to 240f))
|
||||
assertTrue(state().isDown(PadState.A))
|
||||
touch(MotionEvent.ACTION_MOVE, 1 to (800f to 420f))
|
||||
assertFalse(state().isDown(PadState.A))
|
||||
assertTrue(state().isDown(PadState.B))
|
||||
touch(MotionEvent.ACTION_MOVE, 1 to (600f to 100f))
|
||||
assertFalse(state().isDown(PadState.B))
|
||||
touch(MotionEvent.ACTION_MOVE, 1 to (800f to 240f))
|
||||
assertTrue(state().isDown(PadState.A))
|
||||
touch(MotionEvent.ACTION_UP, 1 to (800f to 240f))
|
||||
assertFalse(state().isDown(PadState.A))
|
||||
}
|
||||
|
||||
@Test fun aStickKeepsItsFingerWhenItCrossesAButton() {
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (200f to 300f))
|
||||
touch(MotionEvent.ACTION_MOVE, 1 to (800f to 240f))
|
||||
assertFalse(state().isDown(PadState.A))
|
||||
assertEquals(1f, state().leftX, .01f)
|
||||
touch(MotionEvent.ACTION_UP, 1 to (800f to 240f))
|
||||
assertEquals(0f, state().leftX, 0f)
|
||||
}
|
||||
|
||||
@Test fun mouseClicksPassThroughToTheGame() {
|
||||
val missed = mutableListOf<Int>()
|
||||
view.onTouchMiss = { missed += it.actionMasked }
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (800f to 240f), tool = MotionEvent.TOOL_TYPE_MOUSE)
|
||||
touch(MotionEvent.ACTION_UP, 1 to (800f to 240f), tool = MotionEvent.TOOL_TYPE_MOUSE)
|
||||
assertFalse(state().isDown(PadState.A))
|
||||
assertEquals(listOf(MotionEvent.ACTION_DOWN, MotionEvent.ACTION_UP), missed)
|
||||
view.onTouchMiss = null
|
||||
assertFalse(touch(MotionEvent.ACTION_DOWN, 1 to (800f to 240f), tool = MotionEvent.TOOL_TYPE_MOUSE))
|
||||
assertFalse(state().isDown(PadState.A))
|
||||
}
|
||||
|
||||
@Test fun keyboardShortcutOpensOnRelease() {
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (450f to 510f))
|
||||
assertTrue(events.isEmpty())
|
||||
touch(MotionEvent.ACTION_UP, 1 to (450f to 510f))
|
||||
assertEquals(listOf("KEYBOARD:PRIMARY"), events)
|
||||
}
|
||||
|
||||
@Test fun cancelledDraggedOrDisabledKeyboardShortcutDoesNotOpen() {
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (450f to 510f))
|
||||
touch(MotionEvent.ACTION_CANCEL, 1 to (450f to 510f))
|
||||
touch(MotionEvent.ACTION_UP, 1 to (450f to 510f))
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (450f to 510f))
|
||||
touch(MotionEvent.ACTION_UP, 1 to (450f to 510f), flags = MotionEvent.FLAG_CANCELED)
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (450f to 510f))
|
||||
touch(MotionEvent.ACTION_MOVE, 1 to (600f to 510f))
|
||||
touch(MotionEvent.ACTION_UP, 1 to (600f to 510f))
|
||||
assertTrue(events.isEmpty())
|
||||
show(a, b, stick)
|
||||
view.setQuickHidden(true)
|
||||
measure(view)
|
||||
assertFalse(view.takesTouchAt(450f, 510f))
|
||||
assertFalse(touch(MotionEvent.ACTION_DOWN, 1 to (450f to 510f)))
|
||||
assertTrue(events.isEmpty())
|
||||
}
|
||||
|
||||
@Test fun keyboardShortcutWorksWithHiddenPadAndButtonsOnly() {
|
||||
view.setQuickHidden(true)
|
||||
measure(view)
|
||||
assertFalse(view.takesTouchAt(800f, 240f))
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (450f to 510f))
|
||||
touch(MotionEvent.ACTION_UP, 1 to (450f to 510f))
|
||||
view.setButtonsOnly(true)
|
||||
measure(view)
|
||||
val (x, y) = centre(element(view, "builtin:keyboard"))
|
||||
assertFalse(view.takesTouchAt(800f, 240f))
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (x to y))
|
||||
touch(MotionEvent.ACTION_UP, 1 to (x to y))
|
||||
assertEquals(listOf("KEYBOARD:PRIMARY", "KEYBOARD:PRIMARY"), events)
|
||||
}
|
||||
|
||||
@Test fun hidingTheViewReleasesLatchedKeys() {
|
||||
val controller = Robolectric.buildActivity(ComponentActivity::class.java).setup()
|
||||
try {
|
||||
controller.get().setContentView(view)
|
||||
show(InputSurfaceElement(InputControl.A, .7f, .3f, .2f, .2f, "latch", toggle = true))
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (800f to 240f))
|
||||
touch(MotionEvent.ACTION_UP, 1 to (800f to 240f))
|
||||
assertEquals(listOf("key 42 true"), events)
|
||||
view.visibility = View.GONE
|
||||
assertEquals(listOf("key 42 true", "key 42 false"), events)
|
||||
} finally { controller.pause().stop().destroy() }
|
||||
}
|
||||
|
||||
@Test fun onlyPanelsVibrateOnPress() {
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (800f to 240f))
|
||||
assertTrue(state().isDown(PadState.A))
|
||||
assertNotEquals(HapticFeedbackConstants.VIRTUAL_KEY, shadowOf(button(view)).lastHapticFeedbackPerformed())
|
||||
touch(MotionEvent.ACTION_UP, 1 to (800f to 240f))
|
||||
val panel = InputSurfaceView(context, bridge, listOf(a))
|
||||
measure(panel)
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (800f to 240f), target = panel)
|
||||
assertEquals(HapticFeedbackConstants.VIRTUAL_KEY, shadowOf(button(panel)).lastHapticFeedbackPerformed())
|
||||
touch(MotionEvent.ACTION_CANCEL, 1 to (800f to 240f), target = panel)
|
||||
}
|
||||
|
||||
@Test fun classicSticksTravelTheirFullRadius() {
|
||||
show(stick.copy(buttonShape = InputButtonShape.CIRCLE))
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (200f to 300f))
|
||||
touch(MotionEvent.ACTION_MOVE, 1 to (250f to 300f))
|
||||
assertEquals(.5f, state().leftX, .01f)
|
||||
touch(MotionEvent.ACTION_MOVE, 1 to (300f to 300f))
|
||||
assertEquals(1f, state().leftX, .01f)
|
||||
touch(MotionEvent.ACTION_UP, 1 to (300f to 300f))
|
||||
}
|
||||
|
||||
@Test fun buttonsAcceptTouchesJustOutsideTheirEdge() {
|
||||
show(InputSurfaceElement(InputControl.A, .7f, .3f, .1f, 1f / 6f, buttonShape = InputButtonShape.CIRCLE),
|
||||
InputSurfaceElement(InputControl.B, .3f, .3f, .2f, .1f, buttonShape = InputButtonShape.PILL),
|
||||
InputSurfaceElement(InputControl.X, .3f, .6f, .2f, .1f))
|
||||
assertTrue(view.takesTouchAt(750f, 285f))
|
||||
assertTrue(view.takesTouchAt(805f, 230f))
|
||||
assertFalse(view.takesTouchAt(750f, 300f))
|
||||
assertFalse(view.takesTouchAt(805f, 285f))
|
||||
assertTrue(view.takesTouchAt(400f, 245f))
|
||||
assertFalse(view.takesTouchAt(400f, 255f))
|
||||
assertFalse(view.takesTouchAt(400f, 359f))
|
||||
assertTrue(view.takesTouchAt(400f, 361f))
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (750f to 285f))
|
||||
assertTrue(state().isDown(PadState.A))
|
||||
touch(MotionEvent.ACTION_UP, 1 to (750f to 285f))
|
||||
}
|
||||
|
||||
@Test fun adaptiveSticksCaptureAroundThemAndTheLeftOneToTheEdge() {
|
||||
val left = InputSurfaceElement(InputControl.LS, .3f, .3f, .2f, .4f, hideWhenIdle = true)
|
||||
val right = InputSurfaceElement(InputControl.RS, .6f, .3f, .2f, .4f, hideWhenIdle = true)
|
||||
show(left, right)
|
||||
assertTrue(view.takesTouchAt(10f, 300f))
|
||||
assertTrue(view.takesTouchAt(10f, 390f))
|
||||
assertFalse(view.takesTouchAt(10f, 420f))
|
||||
assertTrue(view.takesTouchAt(795f, 300f))
|
||||
assertFalse(view.takesTouchAt(815f, 300f))
|
||||
val missed = mutableListOf<Int>()
|
||||
view.onTouchMiss = { missed += it.getPointerId(0) }
|
||||
touch(MotionEvent.ACTION_DOWN, 1 to (50f to 300f))
|
||||
touch(MotionEvent.ACTION_POINTER_DOWN or (1 shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 1 to (50f to 300f), 2 to (60f to 310f))
|
||||
assertEquals(listOf(2), missed)
|
||||
touch(MotionEvent.ACTION_MOVE, 1 to (150f to 300f), 2 to (60f to 310f))
|
||||
assertTrue(state().leftX > .9f)
|
||||
show(left.copy(hideWhenIdle = false), right.copy(hideWhenIdle = false))
|
||||
assertFalse(view.takesTouchAt(10f, 300f))
|
||||
assertFalse(view.takesTouchAt(815f, 300f))
|
||||
}
|
||||
|
||||
private fun element(root: View, id: String): View = descendants(root).first { (it.tag as? InputSurfaceElement)?.id == id }
|
||||
private fun centre(target: View): Pair<Float, Float> {
|
||||
var x = target.width / 2f
|
||||
var y = target.height / 2f
|
||||
var at: View = target
|
||||
while (at !== view) { x += at.left; y += at.top; at = at.parent as View }
|
||||
return x to y
|
||||
}
|
||||
private fun button(root: View): View = descendants(root).first { it.javaClass.simpleName == "HoldButton" }
|
||||
private fun descendants(root: View): Sequence<View> = sequence {
|
||||
yield(root)
|
||||
if (root is ViewGroup) for (i in 0 until root.childCount) yieldAll(descendants(root.getChildAt(i)))
|
||||
}
|
||||
|
||||
private fun touch(action: Int, vararg pointers: Pair<Int, Pair<Float, Float>>, flags: Int = 0,
|
||||
tool: Int = MotionEvent.TOOL_TYPE_FINGER, target: View = view): Boolean {
|
||||
val properties = pointers.map { (id, _) -> MotionEvent.PointerProperties().apply { this.id = id; toolType = tool } }.toTypedArray()
|
||||
val coords = pointers.map { (_, position) -> MotionEvent.PointerCoords().apply { x = position.first; y = position.second; pressure = 1f; size = 1f } }.toTypedArray()
|
||||
val event = MotionEvent.obtain(1000L, time++, action, pointers.size, properties, coords, 0, 0, 1f, 1f, 0, 0, 0, flags)
|
||||
return try { target.dispatchTouchEvent(event) } finally { event.recycle() }
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,6 @@ class InputUiLayoutTest {
|
||||
compose.onNodeWithText(context.getString(R.string.setup_tab_controller)).performClick()
|
||||
compose.onNodeWithTag("input-profile-game").assertIsDisplayed()
|
||||
compose.onNodeWithText(context.getString(R.string.ctrl_layout)).assertDoesNotExist()
|
||||
compose.onNodeWithText(context.getString(R.string.ctrl_configure)).assertDoesNotExist()
|
||||
screenshot("controller-tab")
|
||||
compose.onNodeWithTag("input-profile-game").performClick()
|
||||
compose.onNodeWithTag("input-part-physical").performScrollTo().performClick()
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
package com.droiddeck.launcher.ui
|
||||
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.view.Display
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.currentComposer
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import com.droiddeck.launcher.R
|
||||
import com.droiddeck.launcher.SessionActivity
|
||||
import com.droiddeck.launcher.input.DeckPanel
|
||||
import com.droiddeck.launcher.input.InputLibraries
|
||||
import com.droiddeck.launcher.input.InputSurfaceElement
|
||||
import com.droiddeck.launcher.input.SecondScreenMode
|
||||
import com.droiddeck.launcher.session.SessionPrefs
|
||||
import com.droiddeck.launcher.session.SessionService
|
||||
import com.droiddeck.launcher.session.SessionState
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertSame
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
import org.robolectric.annotation.GraphicsMode
|
||||
import org.robolectric.util.ReflectionHelpers
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [28], qualifiers = "w800dp-h600dp")
|
||||
@GraphicsMode(GraphicsMode.Mode.NATIVE)
|
||||
class SecondScreenBarTest {
|
||||
@get:Rule val compose = createRobolectricComposeRule()
|
||||
private val context get() = RuntimeEnvironment.getApplication()
|
||||
private var previousMode = ""
|
||||
private var previousDeckPad = false
|
||||
|
||||
@Before fun setUp() {
|
||||
previousMode = SessionState.mode
|
||||
previousDeckPad = SessionState.deckPad
|
||||
context.getSharedPreferences("input-profiles", android.content.Context.MODE_PRIVATE).edit().clear().commit()
|
||||
SessionPrefs.setDeckPanel(context, DeckPanel.BOTH)
|
||||
}
|
||||
|
||||
@After fun tearDown() {
|
||||
SessionState.mode = previousMode
|
||||
SessionState.deckPad = previousDeckPad
|
||||
}
|
||||
|
||||
private fun presentation(swap: (() -> Unit)? = {}): SecondScreenPresentation {
|
||||
val activity = Robolectric.buildActivity(SessionActivity::class.java).get()
|
||||
val display = activity.getSystemService(DisplayManager::class.java).getDisplay(Display.DEFAULT_DISPLAY)
|
||||
return SecondScreenPresentation(activity, display, {}, {}, {}, onMenu = {}, onSwap = swap)
|
||||
}
|
||||
|
||||
private fun descendants(view: View): Sequence<View> = sequence {
|
||||
yield(view)
|
||||
if (view is ViewGroup) for (index in 0 until view.childCount) yieldAll(descendants(view.getChildAt(index)))
|
||||
}
|
||||
|
||||
private fun rootChildren(panel: SecondScreenPresentation): List<View> {
|
||||
val root: ViewGroup = ReflectionHelpers.getField(panel, "root")
|
||||
return (0 until root.childCount).map { root.getChildAt(it) }
|
||||
}
|
||||
|
||||
@Test fun trackpadPanelHasTheBarWithTheKeyboardToggleState() {
|
||||
SessionState.mode = SessionService.MODE_STEAM
|
||||
val panel = presentation()
|
||||
try {
|
||||
panel.show()
|
||||
panel.showMode(SecondScreenMode.KEYBOARD_TRACKPAD)
|
||||
val children = rootChildren(panel)
|
||||
assertTrue(children[0] is ComposeView)
|
||||
assertTrue(children[1] is InputSurfaceView)
|
||||
val bar = panel.barModel(SecondScreenMode.KEYBOARD_TRACKPAD)!!
|
||||
assertEquals(context.getString(R.string.second_mode_keyboard_trackpad), bar.title)
|
||||
assertNotNull(bar.onClose); assertNotNull(bar.onMenu); assertNotNull(bar.onSteam); assertNotNull(bar.onQam)
|
||||
assertNull(bar.tabs)
|
||||
val keyboard = bar.extras.single()
|
||||
assertEquals(context.getString(R.string.second_show_keyboard), keyboard.description)
|
||||
assertFalse(keyboard.active)
|
||||
ReflectionHelpers.getField<MutableState<Boolean>>(panel, "keyboardShown").value = true
|
||||
val shown = panel.barModel(SecondScreenMode.KEYBOARD_TRACKPAD)!!.extras.single()
|
||||
assertEquals(context.getString(R.string.second_hide_keyboard), shown.description)
|
||||
assertTrue(shown.active)
|
||||
} finally { panel.closeControls() }
|
||||
}
|
||||
|
||||
@Test fun deckPanelHasTheBarWithSwapAndTabsAndProfileControlsStayFullScreen() {
|
||||
SessionState.mode = SessionService.MODE_STEAM
|
||||
SessionState.deckPad = true
|
||||
var swaps = 0
|
||||
val panel = presentation { swaps++ }
|
||||
try {
|
||||
panel.show()
|
||||
panel.showMode(SecondScreenMode.DECK_CONTROLS)
|
||||
assertTrue(rootChildren(panel)[0] is ComposeView)
|
||||
val bar = panel.barModel(SecondScreenMode.DECK_CONTROLS)!!
|
||||
assertEquals(context.getString(R.string.second_mode_deck_controls), bar.title)
|
||||
assertEquals(listOf(context.getString(R.string.swap_screens)), bar.extras.map { it.description })
|
||||
bar.extras.single().onClick()
|
||||
assertEquals(1, swaps)
|
||||
assertEquals(DeckPanel.entries.map { context.getString(it.label) }, bar.tabs!!.labels)
|
||||
assertEquals(DeckPanel.BOTH.ordinal, bar.tabs!!.selected)
|
||||
panel.showMode(SecondScreenMode.CUSTOM_CONTROLS)
|
||||
assertNull(panel.barModel(SecondScreenMode.CUSTOM_CONTROLS))
|
||||
assertTrue(rootChildren(panel)[0] is InputSurfaceView)
|
||||
} finally { panel.closeControls() }
|
||||
val noSwap = presentation(swap = null)
|
||||
try {
|
||||
noSwap.show()
|
||||
noSwap.showMode(SecondScreenMode.DECK_CONTROLS)
|
||||
assertTrue(noSwap.barModel(SecondScreenMode.DECK_CONTROLS)!!.extras.isEmpty())
|
||||
} finally { noSwap.closeControls() }
|
||||
}
|
||||
|
||||
@Test fun nonSteamSessionsHideSteamAndQuickAccess() {
|
||||
for (mode in listOf(SessionService.MODE_DESKTOP, SessionService.MODE_RUN)) {
|
||||
SessionState.mode = mode
|
||||
SessionState.deckPad = true
|
||||
val panel = presentation()
|
||||
try {
|
||||
panel.show()
|
||||
for (panelMode in listOf(SecondScreenMode.KEYBOARD_TRACKPAD, SecondScreenMode.DECK_CONTROLS)) {
|
||||
panel.showMode(panelMode)
|
||||
val bar = panel.barModel(panelMode)!!
|
||||
assertNull(bar.onSteam); assertNull(bar.onQam)
|
||||
assertNotNull(bar.onClose); assertNotNull(bar.onMenu)
|
||||
}
|
||||
} finally { panel.closeControls() }
|
||||
}
|
||||
val stock = InputLibraries.read(context).layouts.filter { it.id == InputLibraries.DECK || it.id == InputLibraries.TRACKPAD }
|
||||
assertTrue(stock.all { layout -> layout.elements.none { it.id.startsWith("command:") } })
|
||||
}
|
||||
|
||||
@Test fun deckTabsSwitchTheLayoutAndAreRemembered() {
|
||||
SessionState.mode = SessionService.MODE_STEAM
|
||||
SessionState.deckPad = true
|
||||
val library = InputLibraries.read(context)
|
||||
fun shown(panel: SecondScreenPresentation): List<InputSurfaceElement> {
|
||||
val controls = descendants(panel.window!!.decorView).filterIsInstance<InputSurfaceView>().single()
|
||||
return descendants(controls).mapNotNull { it.tag as? InputSurfaceElement }.toList()
|
||||
}
|
||||
val first = presentation()
|
||||
try {
|
||||
first.show()
|
||||
first.showMode(SecondScreenMode.DECK_CONTROLS)
|
||||
assertEquals(library.layouts.single { it.id == DeckPanel.BOTH.layout }.elements, shown(first))
|
||||
val controls = descendants(first.window!!.decorView).filterIsInstance<InputSurfaceView>().single()
|
||||
for (panel in listOf(DeckPanel.GRIPS, DeckPanel.LEFT, DeckPanel.RIGHT, DeckPanel.GAMEPAD)) {
|
||||
first.barModel(SecondScreenMode.DECK_CONTROLS)!!.tabs!!.onSelect(panel.ordinal)
|
||||
assertEquals(panel, SessionPrefs.deckPanel(context))
|
||||
assertEquals(panel.ordinal, first.barModel(SecondScreenMode.DECK_CONTROLS)!!.tabs!!.selected)
|
||||
assertSame(controls, descendants(first.window!!.decorView).filterIsInstance<InputSurfaceView>().single())
|
||||
assertEquals(library.layouts.single { it.id == panel.layout }.elements, shown(first))
|
||||
}
|
||||
first.barModel(SecondScreenMode.DECK_CONTROLS)!!.tabs!!.onSelect(DeckPanel.GRIPS.ordinal)
|
||||
} finally { first.closeControls() }
|
||||
val second = presentation()
|
||||
try {
|
||||
second.show()
|
||||
second.showMode(SecondScreenMode.DECK_CONTROLS)
|
||||
assertEquals(DeckPanel.GRIPS.ordinal, second.barModel(SecondScreenMode.DECK_CONTROLS)!!.tabs!!.selected)
|
||||
assertEquals(library.layouts.single { it.id == DeckPanel.GRIPS.layout }.elements, shown(second))
|
||||
second.showMode(SecondScreenMode.KEYBOARD_TRACKPAD)
|
||||
assertEquals(library.layouts.single { it.id == InputLibraries.TRACKPAD }.elements, shown(second))
|
||||
} finally { second.closeControls() }
|
||||
assertEquals(DeckPanel.GRIPS.bindings, SecondScreenMode.DECK_CONTROLS.panel(context))
|
||||
assertEquals(SecondScreenMode.KEYBOARD_TRACKPAD.bindings, SecondScreenMode.KEYBOARD_TRACKPAD.panel(context))
|
||||
}
|
||||
|
||||
@Test fun barTabRowSelectsTabs() {
|
||||
var picked = -1
|
||||
compose.setContent {
|
||||
DroidDeckTheme {
|
||||
BottomScreenBar(BottomBarModel("Deck", {}, {}, null, null, tabs = deckPanelTabs(context, DeckPanel.BOTH) { picked = it.ordinal }))
|
||||
}
|
||||
}
|
||||
for (panel in DeckPanel.entries) compose.onNodeWithText(context.getString(panel.label)).assertIsDisplayed()
|
||||
compose.onNodeWithTag("tab-${DeckPanel.LEFT.ordinal}").performClick()
|
||||
compose.runOnIdle { assertEquals(DeckPanel.LEFT.ordinal, picked) }
|
||||
}
|
||||
|
||||
@Test fun swappedTopScreenShowsTheTerminalWithItsBar() {
|
||||
SessionState.mode = SessionService.MODE_STEAM
|
||||
val activity = Robolectric.buildActivity(SessionActivity::class.java).get()
|
||||
ReflectionHelpers.getField<MutableState<SecondScreenMode>>(activity, "secondScreenMode\$delegate").value = SecondScreenMode.TERMINAL
|
||||
val method = SessionActivity::class.java.getDeclaredMethod("SwappedTopPanel", androidx.compose.runtime.Composer::class.java, Int::class.javaPrimitiveType)
|
||||
method.isAccessible = true
|
||||
compose.setContent { DroidDeckTheme { method.invoke(activity, currentComposer, 0) } }
|
||||
compose.onNodeWithText(context.getString(R.string.second_mode_terminal)).assertIsDisplayed()
|
||||
compose.onNodeWithContentDescription(context.getString(R.string.drawer_keyboard)).assertIsDisplayed()
|
||||
compose.onNodeWithContentDescription(context.getString(R.string.swap_screens)).assertIsDisplayed()
|
||||
compose.onNodeWithTag("bottom-bar-steam").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test fun swappedTopScreenDeckPanelHasTabs() {
|
||||
SessionState.mode = SessionService.MODE_DESKTOP
|
||||
SessionState.deckPad = true
|
||||
val activity = Robolectric.buildActivity(SessionActivity::class.java).get()
|
||||
ReflectionHelpers.getField<MutableState<SecondScreenMode>>(activity, "secondScreenMode\$delegate").value = SecondScreenMode.DECK_CONTROLS
|
||||
val method = SessionActivity::class.java.getDeclaredMethod("SwappedTopPanel", androidx.compose.runtime.Composer::class.java, Int::class.javaPrimitiveType)
|
||||
method.isAccessible = true
|
||||
compose.setContent { DroidDeckTheme { method.invoke(activity, currentComposer, 0) } }
|
||||
compose.onNodeWithText(context.getString(R.string.second_mode_deck_controls)).assertIsDisplayed()
|
||||
compose.onNodeWithTag("bottom-bar-tabs").assertIsDisplayed()
|
||||
compose.onNodeWithTag("bottom-bar-steam").assertDoesNotExist()
|
||||
compose.onNodeWithTag("bottom-bar-close").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test fun unfoldedControlsGetTheSessionBar() {
|
||||
SessionState.mode = SessionService.MODE_STEAM
|
||||
val activity = Robolectric.buildActivity(SessionActivity::class.java).get()
|
||||
assertTrue(ReflectionHelpers.callInstanceMethod<View>(activity, "unfoldedBar") is ComposeView)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user