diff --git a/app/src/main/java/app/gamenative/ui/component/QuickMenu.kt b/app/src/main/java/app/gamenative/ui/component/QuickMenu.kt
index bd0ea12a56..fecc912f71 100644
--- a/app/src/main/java/app/gamenative/ui/component/QuickMenu.kt
+++ b/app/src/main/java/app/gamenative/ui/component/QuickMenu.kt
@@ -46,6 +46,7 @@ import androidx.compose.material.icons.filled.Gamepad
import androidx.compose.material.icons.filled.Keyboard
import androidx.compose.material.icons.filled.QueryStats
import androidx.compose.material.icons.filled.TouchApp
+import androidx.compose.material.icons.filled.GpsFixed
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.LinearProgressIndicator
@@ -91,6 +92,7 @@ object QuickMenuAction {
const val EDIT_CONTROLS = 4
const val EDIT_PHYSICAL_CONTROLLER = 5
const val PERFORMANCE_HUD = 6
+ const val GYRO_AIMING = 7
}
private object QuickMenuTab {
@@ -247,6 +249,14 @@ fun QuickMenu(
accentColor = PluviaTheme.colors.accentPurple,
)
)
+ add(
+ QuickMenuItem(
+ id = QuickMenuAction.GYRO_AIMING,
+ icon = Icons.Default.GpsFixed,
+ labelResId = R.string.gyro_aiming,
+ accentColor = PluviaTheme.colors.accentCyan,
+ )
+ )
if (hasPhysicalController) {
add(
QuickMenuItem(
diff --git a/app/src/main/java/app/gamenative/ui/component/dialog/ControllerTab.kt b/app/src/main/java/app/gamenative/ui/component/dialog/ControllerTab.kt
index 2ef1543fe7..b8c090e83a 100644
--- a/app/src/main/java/app/gamenative/ui/component/dialog/ControllerTab.kt
+++ b/app/src/main/java/app/gamenative/ui/component/dialog/ControllerTab.kt
@@ -1,7 +1,11 @@
package app.gamenative.ui.component.dialog
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import kotlin.math.abs
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -24,6 +28,8 @@ import com.alorma.compose.settings.ui.SettingsSwitch
import com.alorma.compose.settings.ui.SettingsMenuLink
import com.winlator.container.Container
+private val GYRO_SENSITIVITY_VALUES = listOf(0.25f, 0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f)
+
@Composable
fun ControllerTabContent(state: ContainerConfigState, default: Boolean) {
val config = state.config.value
@@ -98,6 +104,16 @@ fun ControllerTabContent(state: ContainerConfigState, default: Boolean) {
state = config.shooterMode,
onCheckedChange = { state.config.value = config.copy(shooterMode = it) },
)
+ SettingsListDropdown(
+ colors = settingsTileColors(),
+ title = { Text(text = stringResource(R.string.gyro_sensitivity)) },
+ subtitle = { Text(text = stringResource(R.string.gyro_sensitivity_description)) },
+ value = (GYRO_SENSITIVITY_VALUES.withIndex().minByOrNull { abs(it.value - config.gyroSensitivity) }?.index ?: 3).coerceIn(0, GYRO_SENSITIVITY_VALUES.lastIndex),
+ items = GYRO_SENSITIVITY_VALUES.map { "${(it * 100).toInt()}%" },
+ onItemSelected = { index ->
+ state.config.value = config.copy(gyroSensitivity = GYRO_SENSITIVITY_VALUES[index])
+ },
+ )
SettingsListDropdown(
colors = settingsTileColors(),
title = { Text(text = stringResource(R.string.external_display_input)) },
diff --git a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt
index 4a0ea44887..ed7b25371f 100644
--- a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt
+++ b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt
@@ -938,6 +938,19 @@ fun XServerScreen(
false
}
+ QuickMenuAction.GYRO_AIMING -> {
+ val currentlyEnabled = container.getExtra("gyroAiming", "false") == "true"
+ val newEnabled = !currentlyEnabled
+ container.putExtra("gyroAiming", if (newEnabled) "true" else "false")
+ container.saveData()
+ PluviaApp.touchpadView?.setGyroAimingEnabled(newEnabled)
+ PostHog.capture(
+ event = "gyro_aiming_toggled",
+ properties = mapOf("enabled" to newEnabled),
+ )
+ true
+ }
+
QuickMenuAction.EXIT_GAME -> {
PostHog.capture(
event = "game_closed",
@@ -1367,6 +1380,8 @@ fun XServerScreen(
PluviaApp.touchpadView = TouchpadView(context, getxServer(), PrefManager.getBoolean("capture_pointer_on_external_mouse", true))
frameLayout.addView(PluviaApp.touchpadView)
PluviaApp.touchpadView?.setMoveCursorToTouchpoint(PrefManager.getBoolean("move_cursor_to_touchpoint", false))
+ PluviaApp.touchpadView?.setGyroSensitivity(container.getExtra("gyroSensitivity", "1").toFloatOrNull()?.coerceIn(0.25f, 2f) ?: 1f)
+ PluviaApp.touchpadView?.setGyroAimingEnabled(container.getExtra("gyroAiming", "false") == "true")
// Add invisible IME receiver to capture system keyboard input when keyboard is on external display
val imeDisplayContext = context.display?.let { display ->
diff --git a/app/src/main/java/app/gamenative/utils/ContainerUtils.kt b/app/src/main/java/app/gamenative/utils/ContainerUtils.kt
index 2c3e7b0ebe..e7241ec2d6 100644
--- a/app/src/main/java/app/gamenative/utils/ContainerUtils.kt
+++ b/app/src/main/java/app/gamenative/utils/ContainerUtils.kt
@@ -317,6 +317,7 @@ object ContainerUtils {
sharpnessEffect = container.getExtra("sharpnessEffect", "None"),
sharpnessLevel = container.getExtra("sharpnessLevel", "100").toIntOrNull() ?: 100,
sharpnessDenoise = container.getExtra("sharpnessDenoise", "100").toIntOrNull() ?: 100,
+ gyroSensitivity = container.getExtra("gyroSensitivity", "1").toFloatOrNull()?.coerceIn(0.25f, 2f) ?: 1f,
)
}
@@ -483,6 +484,7 @@ object ContainerUtils {
container.putExtra("sharpnessEffect", containerData.sharpnessEffect)
container.putExtra("sharpnessLevel", containerData.sharpnessLevel.toString())
container.putExtra("sharpnessDenoise", containerData.sharpnessDenoise.toString())
+ container.putExtra("gyroSensitivity", containerData.gyroSensitivity.coerceIn(0.25f, 2f).toString())
try {
container.language = containerData.language
} catch (e: Exception) {
diff --git a/app/src/main/java/com/winlator/container/ContainerData.kt b/app/src/main/java/com/winlator/container/ContainerData.kt
index 5d0da2b8e7..f2b6c6667c 100644
--- a/app/src/main/java/com/winlator/container/ContainerData.kt
+++ b/app/src/main/java/com/winlator/container/ContainerData.kt
@@ -94,6 +94,7 @@ data class ContainerData(
val sharpnessEffect: String = "None",
val sharpnessLevel: Int = 100,
val sharpnessDenoise: Int = 100,
+ val gyroSensitivity: Float = 1f,
) {
companion object {
val Saver = mapSaver(
@@ -157,6 +158,7 @@ data class ContainerData(
"sharpnessEffect" to state.sharpnessEffect,
"sharpnessLevel" to state.sharpnessLevel,
"sharpnessDenoise" to state.sharpnessDenoise,
+ "gyroSensitivity" to state.gyroSensitivity,
)
},
restore = { savedMap ->
@@ -219,6 +221,7 @@ data class ContainerData(
sharpnessEffect = (savedMap["sharpnessEffect"] as? String) ?: "None",
sharpnessLevel = (savedMap["sharpnessLevel"] as? Int) ?: 100,
sharpnessDenoise = (savedMap["sharpnessDenoise"] as? Int) ?: 100,
+ gyroSensitivity = (savedMap["gyroSensitivity"] as? Float) ?: (savedMap["gyroSensitivity"] as? Double)?.toFloat() ?: 1f,
)
},
)
diff --git a/app/src/main/java/com/winlator/widget/GyroAimingHelper.java b/app/src/main/java/com/winlator/widget/GyroAimingHelper.java
new file mode 100644
index 0000000000..e622fd90ee
--- /dev/null
+++ b/app/src/main/java/com/winlator/widget/GyroAimingHelper.java
@@ -0,0 +1,179 @@
+package com.winlator.widget;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Display;
+import android.view.Surface;
+
+import timber.log.Timber;
+
+/**
+ * Listens to the device gyroscope and converts angular velocity to relative mouse deltas
+ * for aiming. Only active when started; use from the main thread.
+ */
+public class GyroAimingHelper implements SensorEventListener {
+ public interface Listener {
+ void onMouseDelta(int dx, int dy);
+ }
+
+ private static final float DEFAULT_SENSITIVITY = 400f;
+ private static final float MAX_DELTA_PER_FRAME = 120f;
+ private static final int SENSOR_DELAY_US = 5_000; // 200 Hz
+
+ private final Context context;
+ private final Listener listener;
+ private final Handler mainHandler;
+ private float sensitivity;
+
+ private SensorManager sensorManager;
+ private DisplayManager displayManager;
+ private Sensor gyro;
+ private boolean running;
+ private long lastTimestampNs = 0;
+ private boolean hasLastTimestamp;
+ /** Sub-pixel accumulation so small movements aren't lost when casting to int */
+ private float accumDx = 0f;
+ private float accumDy = 0f;
+
+ public GyroAimingHelper(Context context, Listener listener) {
+ this(context, listener, DEFAULT_SENSITIVITY);
+ }
+
+ public GyroAimingHelper(Context context, Listener listener, float sensitivity) {
+ this.context = context.getApplicationContext();
+ this.listener = listener;
+ this.sensitivity = sensitivity > 0 ? sensitivity : DEFAULT_SENSITIVITY;
+ this.mainHandler = new Handler(Looper.getMainLooper());
+ }
+
+ public void start() {
+ if (running) return;
+ sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+ if (sensorManager == null) {
+ Timber.w("GyroAiming: SensorManager is null");
+ return;
+ }
+ gyro = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
+ if (gyro == null) {
+ Timber.w("GyroAiming: no TYPE_GYROSCOPE sensor on this device");
+ return;
+ }
+ hasLastTimestamp = false;
+ accumDx = 0f;
+ accumDy = 0f;
+ boolean registered = sensorManager.registerListener(this, gyro, SENSOR_DELAY_US);
+ if (!registered) {
+ Timber.e("GyroAiming: failed to start, registerListener returned false (sensor=%s)", gyro.getName());
+ return;
+ }
+ running = true;
+ Timber.d("GyroAiming: started (sensor=%s)", gyro.getName());
+ }
+
+ public void stop() {
+ if (!running) return;
+ running = false;
+ mainHandler.removeCallbacksAndMessages(null);
+ if (sensorManager != null && gyro != null) {
+ sensorManager.unregisterListener(this, gyro);
+ }
+ sensorManager = null;
+ displayManager = null;
+ gyro = null;
+ Timber.d("GyroAiming: stopped");
+ }
+
+ public boolean isRunning() {
+ return running;
+ }
+
+ public void setSensitivity(float sensitivity) {
+ this.sensitivity = sensitivity > 0 ? sensitivity : DEFAULT_SENSITIVITY;
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (!running) return;
+ if (event.sensor.getType() != Sensor.TYPE_GYROSCOPE || listener == null) return;
+
+ long t = event.timestamp;
+ if (!hasLastTimestamp) {
+ lastTimestampNs = t;
+ hasLastTimestamp = true;
+ return;
+ }
+ float dt = (t - lastTimestampNs) * 1e-9f;
+ lastTimestampNs = t;
+ if (dt <= 0 || dt > 0.5f) return; // skip invalid or huge gaps
+
+ float deviceRadX = event.values[0];
+ float deviceRadY = event.values[1];
+
+ float radX;
+ float radY;
+ // Offset by +90deg to match aiming orientation.
+ int effectiveRotation = (getDisplayRotation() + 1) & 0x3;
+ switch (effectiveRotation) {
+ case Surface.ROTATION_90:
+ radX = deviceRadY;
+ radY = -deviceRadX;
+ break;
+ case Surface.ROTATION_180:
+ radX = -deviceRadX;
+ radY = -deviceRadY;
+ break;
+ case Surface.ROTATION_270:
+ radX = -deviceRadY;
+ radY = deviceRadX;
+ break;
+ case Surface.ROTATION_0:
+ default:
+ radX = deviceRadX;
+ radY = deviceRadY;
+ break;
+ }
+
+ float dx = -radX * dt * sensitivity;
+ float dy = radY * dt * sensitivity;
+
+ // Clamp per-frame delta for stability
+ dx = clamp(dx, -MAX_DELTA_PER_FRAME, MAX_DELTA_PER_FRAME);
+ dy = clamp(dy, -MAX_DELTA_PER_FRAME, MAX_DELTA_PER_FRAME);
+
+ accumDx += dx;
+ accumDy += dy;
+ int ix = (int) accumDx;
+ int iy = (int) accumDy;
+ if (ix != 0 || iy != 0) {
+ accumDx -= ix;
+ accumDy -= iy;
+ final int fix = ix;
+ final int fiy = iy;
+ mainHandler.post(() -> {
+ if (!running) return;
+ listener.onMouseDelta(fix, fiy);
+ });
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+
+ private int getDisplayRotation() {
+ if (displayManager == null) return Surface.ROTATION_0;
+ Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ if (display == null) return Surface.ROTATION_0;
+ return display.getRotation();
+ }
+
+ private static float clamp(float v, float lo, float hi) {
+ return v < lo ? lo : (v > hi ? hi : v);
+ }
+}
diff --git a/app/src/main/java/com/winlator/widget/TouchpadView.java b/app/src/main/java/com/winlator/widget/TouchpadView.java
index e860a09f11..9d2c604a7f 100644
--- a/app/src/main/java/com/winlator/widget/TouchpadView.java
+++ b/app/src/main/java/com/winlator/widget/TouchpadView.java
@@ -27,6 +27,8 @@
import com.winlator.xserver.XKeycode;
import com.winlator.xserver.XServer;
+import timber.log.Timber;
+
public class TouchpadView extends View implements View.OnCapturedPointerListener {
private static final byte MAX_FINGERS = 4;
private static final short MAX_TWO_FINGERS_SCROLL_DISTANCE = 350;
@@ -111,6 +113,12 @@ public class TouchpadView extends View implements View.OnCapturedPointerListener
// Accumulated deltas for deciding which two-finger gesture to lock into
private float accumulatedPinchDelta, accumulatedPanDelta;
+ // Gyro aiming: device rotation drives relative mouse movement
+ private static final float GYRO_BASE_SENSITIVITY = 400f;
+ private GyroAimingHelper gyroAimingHelper;
+ private boolean gyroAimingEnabled;
+ private float gyroSensitivity = 1f;
+
public TouchpadView(Context context, XServer xServer, boolean capturePointerOnExternalMouse) {
super(context);
this.capturePointerOnExternalMouse = capturePointerOnExternalMouse;
@@ -143,6 +151,12 @@ public TouchpadView(Context context, XServer xServer, boolean capturePointerOnEx
}
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ setGyroAimingEnabled(false);
+ }
+
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
@@ -1301,4 +1315,42 @@ public TouchGestureConfig getGestureConfig() {
public void setTouchscreenMouseDisabled(boolean disabled) {
this.touchscreenMouseDisabled = disabled;
}
+
+ public void setGyroAimingEnabled(boolean enabled) {
+ if (gyroAimingEnabled == enabled) return;
+ gyroAimingEnabled = enabled;
+ Timber.d("GyroAiming: setGyroAimingEnabled(%s)", enabled);
+ if (enabled) {
+ if (gyroAimingHelper == null) {
+ float sens = GYRO_BASE_SENSITIVITY * gyroSensitivity;
+ gyroAimingHelper = new GyroAimingHelper(getContext(), (dx, dy) -> {
+ if (!isEnabled()) return;
+ if (!gyroAimingEnabled) return;
+ if (xServer.isRelativeMouseMovement()) {
+ xServer.getWinHandler().mouseEvent(MouseEventFlags.MOVE, dx, dy, 0);
+ } else {
+ xServer.injectPointerMoveDelta(dx, dy);
+ }
+ }, sens);
+ } else {
+ gyroAimingHelper.setSensitivity(GYRO_BASE_SENSITIVITY * gyroSensitivity);
+ }
+ gyroAimingHelper.start();
+ } else {
+ if (gyroAimingHelper != null) {
+ gyroAimingHelper.stop();
+ }
+ }
+ }
+
+ public void setGyroSensitivity(float sensitivity) {
+ gyroSensitivity = sensitivity > 0 ? sensitivity : 1f;
+ if (gyroAimingHelper != null) {
+ gyroAimingHelper.setSensitivity(GYRO_BASE_SENSITIVITY * gyroSensitivity);
+ }
+ }
+
+ public boolean isGyroAimingEnabled() {
+ return gyroAimingEnabled;
+ }
}
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index af305dd3fd..4e4e93eba3 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -260,6 +260,7 @@
Touchpad-hjælp
Skjul on-screen-kontroller med controller
Skjul automatisk on-screen-kontroller når en fysisk controller er tilsluttet
+ Gyro-mus-sigte
Vælg binding
@@ -530,6 +531,8 @@
Til visuelle romaner og RTS-spil
Shooter-tilstand
Erstat stick-elementer med dynamiske joysticks
+ Gyro-følsomhed
+ Multiplikator for gyro-mus-sigte (når aktiveret in-game)
Aktiver mus
Aktiver sticks
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index af5057ffbe..b57bc7c284 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -325,6 +325,7 @@
Touchpad-Hilfe
On-Screen-Controller bei Gamepad ausblenden
On-Screen-Steuerung automatisch ausblenden, wenn ein physischer Controller verbunden ist
+ Gyro-Mauszielen
Belegung auswählen
Belege: %1$s
@@ -680,6 +681,8 @@
Für Visual Novels und RTS-Spiele
Shooter-Modus
Stick-Elemente durch dynamische Joysticks ersetzen
+ Gyro-Empfindlichkeit
+ Multiplikator für Gyro-Mauszielen (wenn im Spiel aktiviert)
Maus aktivieren
Sticks aktivieren
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index d8ee4df584..32893dfbac 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -347,6 +347,7 @@
Ayuda del touchpad
Ocultar controles táctiles al usar mando
Oculta automáticamente los controles en pantalla cuando se conecta un mando físico.
+ Apuntado con gyro (ratón)
Seleccionar asignación
@@ -755,6 +756,8 @@
Para novelas visuales y juegos de estrategia en tiempo real.
Modo tirador
Reemplaza los sticks por joysticks dinámicos.
+ Sensibilidad gyro
+ Multiplicador para apuntado con gyro/ratón (cuando está activado en el juego)
Activar ratón
Activar sticks
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 1b63a8bc9d..6dcb85d1bb 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -332,6 +332,7 @@
Aide du pavé tactile
Masquer les contrôles à l\'écran avec manette
Masquer automatiquement les contrôles à l\'écran lorsqu\'un contrôleur physique est connecté
+ Visée souris gyro
Sélectionner l\'affectation
@@ -706,6 +707,8 @@
Pour les visual novels et jeux de stratégie en temps réel
Mode tireur
Remplacer les sticks par des joysticks dynamiques
+ Sensibilité gyro
+ Multiplicateur pour la visée souris gyro (quand activé en jeu)
Activer la souris
Activer les sticks
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 9d6be35376..e0d23b583a 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -336,6 +336,7 @@
Aiuto Touchpad
Nascondi controlli a schermo con controller
Nascondi automaticamente i controlli a schermo quando è connesso un controller fisico
+ Mira con gyro (mouse)
Seleziona Associazione
@@ -710,6 +711,8 @@
Per visual novel e giochi RTS
Modalità sparatutto
Sostituisci gli stick con joystick dinamici
+ Sensibilità gyro
+ Moltiplicatore per mira con gyro/mouse (quando attivato in-game)
Attiva mouse
Attiva stick
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index f9eff06fc9..fa3ad5de48 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -345,6 +345,7 @@
터치패드 도움말
컨트롤러 연결 시 화면 컨트롤 숨기기
물리 컨트롤러가 연결되면 화면 컨트롤을 자동으로 숨깁니다
+ 자이로 마우스 조준
바인딩 선택
@@ -720,6 +721,8 @@
비주얼 노벨 및 RTS 게임용
슈터 모드
스틱 요소를 동적 조이스틱으로 교체
+ 자이로 감도
+ 자이로 마우스 조준 배율(인게임에서 활성화 시)
마우스 활성화
스틱 활성화
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index d3c4748801..cb15c772cd 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -344,6 +344,7 @@
Pomoc touchpada
Ukryj kontroler ekranowy przy podłączonym kontrolerze
Automatycznie ukrywa kontroler ekranowy, gdy podłączony jest kontroler fizyczny
+ Celowanie gyro (mysz)
Wybierz przypisanie
@@ -719,6 +720,8 @@
Dla powieści wizualnych i gier RTS
Tryb strzelanki
Zamień drążki na dynamiczne joysticki
+ Czułość żyroskopu
+ Mnożnik celowania gyro myszą (gdy włączone w grze)
Włącz mysz
Włącz drążki
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 80545536e2..bb4db94fad 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -260,6 +260,7 @@
Ajuda Touchpad
Ocultar controles on-screen com controle
Ocultar automaticamente controles on-screen quando um controle físico estiver conectado
+ Mira com gyro (mouse)
Selecionar Binding
@@ -530,6 +531,8 @@
Para visual novels e jogos de estratégia em tempo real
Modo tiro
Substituir sticks por joysticks dinâmicos
+ Sensibilidade do gyro
+ Multiplicador para mira com gyro/mouse (quando ativado no jogo)
Ativar mouse
Ativar sticks
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index c484ef78e5..2b06027c66 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -334,6 +334,7 @@
Ajutor touchpad
Ascunde controalele pe ecran când există controller
Ascunde automat controalele pe ecran când un controller fizic este conectat
+ Țintire mouse gyro
Selectează acțiunea
@@ -711,6 +712,8 @@
Pentru visual novels și jocuri RTS
Mod shooter
Înlocuiește stick-urile cu joystick-uri dinamice
+ Sensibilitate gyro
+ Multiplicator pentru țintire mouse gyro (când este activat în joc)
Activează mouse-ul
Activează stick-urile
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index c1ed94e4b2..021cfe6c4e 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -1019,6 +1019,8 @@ https://gamenative.app
Настройки динамических джойстиков
Режим стрельбы
Автоматически заменять элементы джойстика на динамические джойстики
+ Чувствительность гироскопа
+ Множитель прицеливания гироскопом/мышью (при включении в игре)
Ярлыки
Шифты
Показать FPS
@@ -1179,6 +1181,7 @@ https://gamenative.app
показать подсказку
Общее время игры: %s часов
Справка сенсорной панели
+ Прицеливание гироскопом (мышь)
Режим сенсорного экрана
Для визуальных романов и игр RTS
Введите 5-значный код
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 5b0890c4d8..92d8dba8c7 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -327,6 +327,7 @@
Довідка сенсорної панелі
Приховувати екранні елементи з контролером
Автоматично приховувати екранні елементи керування, коли під\'єднано фізичний контролер
+ Прицілювання гіроскопом (миша)
Вибрати призначення
@@ -701,6 +702,8 @@
Для візуальних романів та ігор RTS
Режим шутера
Замінити джойстики на динамічні
+ Чутливість гіроскопа
+ Множник прицілювання гіроскопом (коли увімкнено в грі)
Увімкнути мишу
Увімкнути джойстики
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 09b469cbbc..3780dda2c9 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -330,6 +330,7 @@
触摸板支持
使用控制器时隐藏屏幕控制器
当实体控制器连接时自动隐藏屏幕控制器
+ 陀螺仪鼠标瞄准
选择绑定
@@ -701,6 +702,8 @@
适用于视觉小说和即时战略游戏
射击模式
用动态摇杆替换摇杆元素
+ 陀螺仪灵敏度
+ 陀螺仪鼠标瞄准倍率(在游戏中启用时)
启用鼠标
启用摇杆
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 8d5d6fc539..afcaf01b94 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -330,6 +330,7 @@
觸摸板支援
使用控制器時隱藏螢幕控制器
當實體控制器連接時自動隱藏螢幕控制器
+ 陀螺儀滑鼠瞄準
選擇綁定
@@ -703,6 +704,8 @@
適用於視覺小說與即時戰略遊戲
射擊模式
以動態搖桿取代搖桿元素
+ 陀螺儀靈敏度
+ 陀螺儀滑鼠瞄準倍率(在遊戲中啟用時)
啟用滑鼠
啟用搖桿
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index feb1d794b1..85bc09f45c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -297,6 +297,7 @@
Clock time
CPU temperature
GPU temperature
+ Gyro mouse aiming
Touchpad Help
Hide on-screen controls with controller
Automatically hide on-screen controls when a physical controller is connected
@@ -710,6 +711,8 @@
For visual novels and RTS games
Shooter Mode
Auto-replace stick elements with dynamic joysticks
+ Gyro sensitivity
+ Multiplier for gyro mouse aiming (when enabled in-game)
Enable Mouse
Enable Sticks