5cf69732ef fix(input): make a hardware mouse and keyboard work like a PC (#2053)
* 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 commit db3d7555e0)

* 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 commit e350d88464)

* 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 commit e96a187e02)

* 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 commit 7ff8c5d568)

* 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 commit cf0f82d8cd)

* 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 commit 5f5e3bd52e)

* 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>
2026-11-04 13:27:08 -05:00
2026-10-13 21:27:42 -04:00
2026-11-01 12:58:09 -05:00
2026-10-13 21:27:42 -04:00
2026-10-13 21:27:42 -04:00
2026-10-13 21:27:42 -04:00

DroidDeck

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.

Download DroidDeck 0.6.7 Join the DroidDeck Discord

Star History Rank

Droid-Deck%2FDroidDeck | Trendshift Droid-Deck%2FDroidDeck | Trendshift

On a Retroid Pocket Duo: Play Steam from the DroidDeck launcher, open Pac-Man in Steam Big Picture and play it, exit the game, then Switch to Desktop from the Power menu

DroidDeck has no website. Only download it from this repository's Releases.

The Library switching source chips, changing the card size and opening the Filter menu A Windows game running through Proton with the on-screen controls Two controllers playing split screen on one handheld The Kubuntu desktop with Discover open

Install

  1. 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.
  2. About 3 GB free for the runtime, plus 1.1 GB for the desktop and emulators.
  3. Install the APK, install the Linux runtime, press Play and sign in to Steam.
  4. 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_PLATFORM so 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.conf that pressure-vessel writes.
  • WriteProcessMemory hooks fall back to /proc/<pid>/mem the way Wine's server/ptrace.c did 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 answers PAGEMAP_SCAN from /proc/self/pagemap.
  • libblsession runs Wine's arm64 SIGUSR2 context handler (dlls/ntdll/unix/signal_arm64.c, LGPL-2.1-or-later) in place on a frame laid out like Linux's arch/arm64/kernel/signal.c, and serves fill_vm_counters in dlls/ntdll/unix/process.c the 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.py and 570940.py fail 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 ConnectCache format 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_VIDPID in Proton's dlls/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's product.db reader.
  • 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.cpp leaves as a TODO.
  • Read without taking code: Qt's qwaylandinputdevice.cpp and qguiapplication.cpp, Konsole's TerminalDisplay.cpp, and Mesa's u_threaded_context.c and zink_resource.c.
  • The Steam Keyboard window rule follows Valve's steamdeck-kde-presets with Bazzite's 0001-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
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 handskeletonsimulation sample (BSD-3-Clause), which follows Moshi Turner's work in Monado. Index offsets come from Monado's vive_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.

Star history

Star history chart
S
Description
No description provided
Readme GPL-3.0
840 MiB
0 Stars 1 Watchers 0 Forks
Languages
Kotlin 50.6%
Python 16.7%
C 14%
C++ 8.5%
Rust 3.6%
Other 6.4%