* feat(gamescope): a three way switch for relative mouse motion Games that confine the cursor and warp it back to read movement never reach the nested hints rule, so their aim stays bounded by the screen. The convar defaults to 0 and leaves that rule alone; 1 forces relative motion for the focused game, 2 keeps the pointer absolute even when the rule would apply. (cherry picked from commitdb3d7555e0) * feat(input): the session carries a relative mouse mode per game Reads the mode from the game's gesture config, hands it to gamescope as gamescope_relative_mouse, and pushes a change to the running session through gamescopectl. (cherry picked from commite350d88464) * feat(drawer): the relative mouse switch is a three way choice Auto leaves it to the game, on forces relative motion, off keeps the pointer absolute. Named in all 32 locales so none of the three falls back to English. (cherry picked from commite96a187e02) * fix(input): follow the focused game's relative mouse mode Switching to a game whose saved mode differs left the session on the previous game's mode, since only the drawer state was refreshed. The requests also ran on a thread per selection, so two quick picks could reach gamescope out of order. (cherry picked from commit7ff8c5d568) * fix(input): retry the relative mouse mode gamescope did not take The drawer state moved before the request ran, so a failed request left the two out of step and the next focus change skipped the resend. (cherry picked from commitcf0f82d8cd) * fix(input): the relative mouse mode tracks the latest choice The guest agent answers ok when it handled the exec, so a failing gamescopectl was recorded as applied. Reconcile the newest desired mode on the worker thread after each request, and only mark applied when the command really exited zero. (cherry picked from commit5f5e3bd52e) * gamescope: a hidden cursor under any pointer constraint is relative Games that hide the cursor and confine the pointer had no lock hint, so the nested pointer stayed absolute and the camera froze. * Treat a hardware mouse as a real mouse in sessions A mouse now moves the guest pointer by relative motion for the whole session through pointer capture, so it no longer stops at screen edges or reaches system gestures. Its cursor stays visible in every touch mode, follows the game showing or hiding it, and clicks no longer press on-screen controls. * gamescope: use the mouse test release * Direct touch turns the camera while a game holds the pointer A swipe in direct touch now sends relative motion when a game has the pointer locked, including when the lock starts during the swipe, as when a game hides the cursor while a button is held. * Address review findings on mouse and touch input Keep touchpad taps on on-screen controls, cancel a pending long press during a locked swipe, let the three-finger gesture cancel a locked swipe, refresh capture when the output changes, and use the menu's key for the relative mouse setting. * Keep locked touches inside the game picture and free the mouse in touch editors * End touch editor ownership when the editor goes away * Bring the mouse cursor back when a touch editor closes * Release a pointer lock at the game's pointer * gamescope: use the pointer position test release * Fit the X screen to a fullscreen window larger than it * gamescope: use the X screen fit test release * Return the X screen when no game window has focus * gamescope: use the X screen return test release * ci: avoid redundant gamescope builds * fix: hardware mouse in Desktop and pointer warping games KWin nested on the host only reads relative motion while its own pointer lock is on, so a program that locked the pointer in Desktop (Blender orbit and pan) stopped receiving motion. A captured hardware mouse now turns that lock on, and a real Right Ctrl no longer toggles it. Gamescope follows a game's pointer warps instead of overriding them, and absolute motion also sends raw motion. Also retries relative mouse requests, tidies the unplug path, passes side buttons and fits a second oversized window correctly. * chore: use the gamescope build with patch 0131 * fix: Desktop mouse lock keeps retrying after early attempts fail * fix: hold the key that turns on the Desktop mouse lock KWin ignores a press and release delivered together. * fix: gamescope enters warp following sooner and keeps steady motion * chore: use gamescope p26 * Capture system keys in a focused session and keep the first Desktop mouse motion in place * Use the p27 gamescope build * Update the system keys row test * Recognise a captured mouse so the Desktop grab can start * Keep touch warps out of relative motion * Send Esc from keyboards that report it as Back * Use the p28 gamescope build * Release captured keys on pause, forward motion during a grab and wait for a pending screen fit * Use the p29 gamescope build * fix(input): keep held system keys consumed until they are released Copy each captured key event, since the service owns the original only for the callback, and consume the physical release of a key already released to the guest. Use the published gamescope p20. * fix(input): capture a system key only from its first press --------- Co-authored-by: kingokksa <kingokksa@qq.com> Co-authored-by: maxjivi05 <6025299+maxjivi05@users.noreply.github.com>
DroidDeck brings the SteamOS experience to Android: Steam Gaming Mode, full Linux desktop, integration with GOG, Epic Games, Xbox, and other storefronts, Steam VR, and more!
100% open source. No ads. No telemetry. No source withheld.
DroidDeck has no website. Only download it from this repository's Releases.
Install
- Android 9 or newer on Adreno 730 or newer, or any 8xx. Adreno 6xx is experimental. Mali, Xclipse, PowerVR and Adreno 710 are unsupported. No root needed.
- About 3 GB free for the runtime, plus 1.1 GB for the desktop and emulators.
- Install the APK, install the Linux runtime, press Play and sign in to Steam.
- On Android 14 and newer, turn on Disable child process restrictions in Developer options. On Android 12 and 13, Steam's first launch shows a Fix it for me button that walks you through it.
Smart glasses setup is in the support matrix. Release notes are in docs/releases.
Help, Preview builds and device reports are on Discord. For bugs, post in #bug-reports with the zip from Share logs.
Build
Needs Docker, Java 17, the Android SDK and NDK, Rust via rustup, GitHub CLI, Python 3 and zstd.
tools/build_local.sh
The APK lands in app/build/outputs/apk/release/. Install it with tools/deploy_local.sh. After the first run, ./gradlew :app:assembleRelease reuses the prepared inputs. Unit tests run with ./gradlew -PskipRust=true :app:testDebugUnitTest, and the helper and preload suite with bash tools/test_local.sh.
On Windows, see tools/run_windows.ps1 and tools/prepare_windows_runtime.py.
Limits
Compatibility and performance vary by device. Desktop compositing is software rendered, and Firefox sandboxing is reduced under proot.
Credits and licence
DroidDeck is GPL-3.0. Steam and Proton belong to Valve Corporation. VITURE, RayNeo, XREAL, Rokid, REDMAGIC, Nintendo Switch and Joy-Con are trademarks of their owners. This project is not affiliated with any of them.
Runtime, Wine and Proton
- Runtime, shim, input and controller work build on WinNative and Bannerlator by maxjivi05.
- mmap ring buffer controller input by ribbit384 (WinNative #345).
- FEX (MIT) runs x86 code. DroidDeck's build puts the platform name under
AT_PLATFORMso sharun AppImages by VHSgunzo (MIT) start through its userland-execve loader (MIT). FEX's code disk cache was checked in its source. - x86 AppImages, and arm64 ones whose runtime can't unpack on Android, are unpacked with uruntime by VHSgunzo (MIT), shipped unmodified with its licence.
- x86 programs linking OpenSSL 3 use the copy in the Steam Linux Runtime 4.0. x86 Linux games get the
/etc/asound.confthat pressure-vessel writes. WriteProcessMemoryhooks fall back to/proc/<pid>/memthe way Wine'sserver/ptrace.cdid before Wine 11.- Wine write watches use userfaultfd support in Proton's
dlls/ntdll/unix/virtual.c(LGPL-2.1-or-later). libblsession supplies the arm64 syscall number and answersPAGEMAP_SCANfrom/proc/self/pagemap. - libblsession runs Wine's arm64
SIGUSR2context handler (dlls/ntdll/unix/signal_arm64.c, LGPL-2.1-or-later) in place on a frame laid out like Linux'sarch/arm64/kernel/signal.c, and servesfill_vm_countersindlls/ntdll/unix/process.cthe kernel's own/proc/<pid>/status. - droiddeck-ntsync follows the Linux ntsync semantics in
Documentation/userspace-api/ntsync.rst(GPL-2.0). - The proot fast path orders bindings like PRoot's
path/binding.c(GPL-2.0-or-later). - DiRT 3 and DiRT Showdown keep their telemetry socket the way RoccoC's DiRTTelemetryErrorFix (MIT) does, based on the fix by Carsten Gottschling.
- Games use Mesa Turnip's per render pass memory choice. The Steam client keeps
TU_DEBUG=sysmem. - Black Ops III and Dark Souls Remastered start without umu-protonfixes (BSD-2-Clause), whose
311210.pyand570940.pyfail under ARM64 Proton. - ReSkate (GPL-3.0) by Dingo Shenanigans uses the launch option from its README and D3D12 feature level 12_1.
- The arm64 client's sign in was checked by reading Steam's saved token with the
ConnectCacheformat from deadlock-api-ingest.
Stores
- Epic Games and GOG build on Phobos's adaptation of Legendary and gogdl. GOG install script registry entries are read the way Heroic Games Launcher (GPL-3.0) reads them.
- Epic's official Linux launcher preview runs through FEX. That setup is outside Epic's listed Linux support.
- Battle.net is by @kayakyakr. It runs Blizzard's own client in Proton (downloaded from Blizzard, not included) and shows key art from the Battle.net Shop. Without Steam, its games see the pad as an Xbox 360 controller via
PROTON_SPOOF_STEAMINPUT_VIDPIDin Proton'sdlls/winebus.sys. - Battle.net installs drive Blizzard's Agent the way @barncastle's Battle.Net-Installer does, with requests from wowdev.wiki. Read without taking code: @mubaraknumann's unifideck, @djmittens's neo-mittens
bnetswitch, @BCD1210's soju and Lutris'sproduct.dbreader. - Xbox games load @domsvoboda's xodus-nexus modules (LGPL-2.1-or-later), including
wintypes.dll. Minecraft's GameInput setup was checked against @Wyze3306's BedrockOnLinux (MIT). - The Xbox Cloud Gaming player uses the WebRTC client of @unknownskl's Greenlight (MIT), and its offer tweaks and sharpening follow @redphx's Better xCloud (MIT). See
tools/xcloud-player/NOTICE.md. - The itch.io butler pack ships butler's
7z.so, itch.io's build of 7-Zip by Igor Pavlov (LGPL-2.1, unRAR restriction on RAR code), unmodified. Other archives use Apache Commons Compress and the runtime's bsdtar (libarchive). - The Store uses Flatpak (LGPL-2.1) through DroidDeck's own bubblewrap shim. Chromium and Electron apps start directly, since zypak by @refi64 (BSD-3-Clause) always uses Flatpak's spawn portal.
- Folder sync runs Syncthing (MPL-2.0), built from @researchxxl's syncthing-android fork (MPL-2.0).
Audio, video and HUD
- Steam audio goes through @The412Banner's DirectAudio PulseAudio sink (LGPL-2.1-or-later), built from
tools/directaudio/sink. - The DroidDeck HUD is @The412Banner's FusionHUD (GPL-3.0 with an attribution term). Its readings match Valve's MangoHud build (MIT), with frame times from gamescope patch 0125.
- The HUD's CPU, GPU load, thermal and battery readers come from @xXJSONDeruloXx's work.
- LSFG frame generation comes from Camille LaVey and the Eden project, following lsfg-vk, ported by @maxjivi05. It needs your own copy of Lossless Scaling and ships none of its shaders.
- Remote Play decodes through Android's MediaCodec or the FFmpeg (LGPL-2.1-or-later) in Steam's runtime. Qualcomm low latency settings follow Moonlight (GPL-3.0).
- PipeWire (MIT) sockets use the settings in its
module-access.c, and WirePlumber (MIT) keeps those clients at full permissions.
Desktop
- The KDE pacman repository snapshots Arch Linux ARM and installs with pacman (GPL-2.0-or-later).
- KWin (GPL-2.0-or-later) is patched to pass on the scroll data its
wayland_backend.cppleaves as a TODO. - Read without taking code: Qt's
qwaylandinputdevice.cppandqguiapplication.cpp, Konsole'sTerminalDisplay.cpp, and Mesa'su_threaded_context.candzink_resource.c. - The Steam Keyboard window rule follows Valve's
steamdeck-kde-presetswith Bazzite's0001-steam-virtual-keyboard.patch. - Steam's Browse buttons open a GTK 3 file chooser via PyGObject (LGPL-2.1-or-later), shown over Steam by gamescope (BSD-2-Clause) through
GetAppIdFromReaper. - The AYN Odin 2 phantom second display was confirmed by @SapphireRhodonite's WatermelonDS 0.0.5 notes and iiSU #363, without taking their code.
Smart glasses
- Builds on WinNative's VITURE work. Protocol checked against @wheaney's XRLinuxDriver, @badicsalex's ar-drivers-rs and go-macos/iokit. The optional VITURE SDK is not included.
- The VITURE protocol V2 frames adapt @elasticjava's viture-v2 (MIT) by Holger Bartnick. See
docs/third-party/viture-v2. - RayNeo adapts @informalTechCode's RayNeo-Air-Series-3DoF-Scaffold (Apache-2.0) and references @verncat's RayNeo-Air-3S-Pro-OpenVR (MIT) and Monado (BSL-1.0). See docs/third-party/rayneo.
- XREAL 1S references XRLinuxDriver and xrealOneDeviceKit by @wheaney, @rohitsangwan01's xreal_one_driver (MIT) and @0xcaff's xr-tools.
- Rokid follows ar-drivers-rs, @badicsalex's Void Computing write-ups and Monado's Rokid driver.
- REDMAGIC display findings draw on @mekhontsev's MagicDesk investigation and @Coding-BR's decompiled Nubia kernel.
VR, Joy-Con and hand tracking
- Joy-Con VR ports the arm model from Google's GVR SDK for Unity (Apache-2.0) and adapts the hand skeleton from Valve's OpenVR
handskeletonsimulationsample (BSD-3-Clause), which follows Moshi Turner's work in Monado. Index offsets come from Monado'svive_poses.c(BSL-1.0). - Joy-Con research: Linux's hid-nintendo by Daniel J. Ogorchock, @dekuNukem's Nintendo_Switch_Reverse_Engineering, SDL and AOSP. Checked against ALVR, OpenComposite, PSMoveSteamVRBridge, @F8LEFT's JoyConVr, @krnelpan1c's Daydream-Controller-SteamVR, @yoyobuae's joyconvr, Moonlight and Dolphin. See docs/third-party/joycon.
- Camera hand tracking runs Google's MediaPipe Pose Landmarker (Lite), BlazePose GHUM 3D and Hand Landmarker (Apache-2.0) on CameraX frames (Apache-2.0), with usage reports off. Checked against JoyConVr's camera app (MIT).
- Tracking math: the GVR arm model's accelerometer mode, Eric Foxlin's zero velocity updates, Frosio, Pedersini and Borghese's accelerometer autocalibration, a Kalman filter (Kalman, 1960), Horn's quaternion method (1987) and the 1€ filter (Casiez, Roussel and Vogel, 2012).
- Gestures follow ALVR's
hand_gestures.rs(MIT) and Meta Quest's menu pinch, tuned on HaGRID photos (CC BY-SA 4.0, not included). - The glove model follows OpenVR's render model reference, is meshed with surface nets (Gibson, 1998; Mikola Lysenko), and uses Inigo Quilez's smooth minimum, distance field ambient occlusion and polygon distance (MIT). See docs/third-party/handtracking.




