fufesou 3f4bfe535e Fix/wayland input keyboard layout (#16462)
* fix(linux): respect Wayland keyboard layouts for uinput

Resolve printable keys from GNOME input sources or the Wayland keymap and KDE active layout group. Refresh layout metadata on input at most once per second, and preserve the keycode and owned modifiers until release.

Preserve the original Legacy character on client key release and handle Caps Lock shortcuts without introducing an unwanted Shift modifier.

Validated with GNOME/KDE full-service input and disconnect checks, plus Windows/Linux native keyboard capture and release checks.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): harden Wayland keyboard layout detection

Keep the last usable map on transient discovery failures and preserve the
legacy character path when no map is available, with explicit warnings.
Retain each injected key representation through release and handle IBus
default layout and variant metadata without compiling a layout named default.

Use native GNOME and Plasma sources, including KWin sessions without the
optional layout service. Read the Xwayland keymap and effective group from
the same keyboard on other desktops. Load XCB/XKB libraries dynamically and
accept the unix/:N local display spelling.

Validation: 24/24 temporary Linux production-module and IPC checks passed,
including an actual read-only Xwayland query. The two latest routing/display
regressions failed before their fixes. Rustfmt and git diff --check passed.
No Cargo/Flutter commands or full remote application tests were rerun.

Xwayland state freshness and synchronous desktop I/O remain known limits.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): bound input waits for layout refresh

Run throttled Wayland layout discovery in a single background worker and give the triggering input a 25 ms wait budget. Later input uses the existing map without waiting or queuing more queries. Preserve source error handling and skip known Legacy clipboard-only text.

Document Xwayland freshness and per-character modifier ownership limits. Desktop calls remain uncancelled; the budget bounds input waiting, subject to OS scheduling.

Validation: Linux module compilation with cached dependencies, 23 existing temporary module/IPC checks, and stalled-XCB timing probes passed. Rechecked cache/error/release cases after the final lock-scope change. No permanent regression tests or Cargo/Flutter commands.
Signed-off-by: fufesou <linlong1266@gmail.com>

* docs(linux): record layout query latency measurements

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): reply to failed uinput key state queries

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): prefer non-keypad character mappings

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): preserve text after unmappable uinput characters

Continue processing a text sequence when one character cannot be resolved
in the host layout. Return the first mapping error after the supported
characters are injected, so the existing throttled log still reports failure.

Keep modifier-query, injection and release errors fail-fast. This fixes
German a^bc losing bc without adding clipboard or fixed-US fallback.
The unsupported caret remains an explicit mapping error.

Validation: three temporary Linux checks (nine inputs) passed using the
production resolver and sequence methods, real framed IPC and native XKB
decoding. The suffix check failed before the fix. Formatting and diff checks
passed; no permanent tests, Cargo/Flutter commands or full app build added.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): preserve Latin shortcuts on non-Latin layouts

Detect Ctrl/Alt/Meta independently of CapsLock. If the active XKB map lacks
an ASCII shortcut letter, reuse the existing physical letter mapping while
preserving explicit Shift and the press-time key for release. Existing
layout mappings and unsupported ordinary text retain their behavior.

Honor disable-uinput-layout-fallback and log this compatibility path with
the existing throttle.

Validation: 12 temporary Linux production-module/IPC checks passed,
including 43 non-Latin shortcut/layout/lock/Shift cases. The new checks
failed before the fix. Formatting and git diff --check passed. No real
mobile/compositor session or Cargo/Flutter build was run.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): preserve missing punctuation shortcuts

Allow missing ASCII graphic shortcuts to reuse the existing physical key
table when Ctrl, Alt or Meta is active. This restores Ctrl+[ and Ctrl+]
with a valid Russian layout instead of discarding their character events.

Retain the table's Shift requirement for punctuation and use existing
modifier ownership and press-time release tracking. Uppercase letters do
not synthesize Shift. Active-layout mappings, ordinary text errors and
disable-uinput-layout-fallback retain their behavior.

Validation: 14 temporary Linux production-module/IPC checks passed after
recompiling the final source with rustc and cached dependencies. Includes
19 punctuation/lock/Shift combinations and 43 existing Latin-shortcut
cases. The two new checks failed before the fix. Formatting and
git diff --check passed. No Cargo/Flutter build or real mobile/native
Wayland session was run.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): respect held Shift when resolving shortcuts

Derive Shift-held candidates from the same XKB keymap and query the
caller's Shift state for character shortcuts. On US layouts, Ctrl+Shift+<
now uses the comma key instead of the extra ISO key that produces >.

Keep caller-held Shift out of synthesized modifier ownership. Preserve
ordinary input and letter-shortcut identity, and do not replace an
ordinary shortcut with a keypad alias to satisfy the held-Shift lookup.

Validation: 16 temporary Linux production-module/IPC checks passed with
native XKB event replay and cached dependencies via rustc. Includes
30 US text/shortcut cases and 40 UK/DE/FR character/lock cases. The new
Ctrl+Shift+< check failed before the fix. Changed sections pass formatting
and git diff --check. No Cargo/Flutter build or real mobile/native Wayland
session was run; device-state and packet-modifier handling use fixtures.

Signed-off-by: fufesou <linlong1266@gmail.com>

* docs(android): document paired-punctuation input limitation

Signed-off-by: fufesou <linlong1266@gmail.com>

* docs(linux): explain Xwayland layout synchronization limits

Document the focus-scoped modifier updates observed on GNOME and KWin. Core and physical X11 keyboards can retain an old layout group while native Wayland windows have focus; reconnecting or waiting cannot request the missing update.

Validation: 16 existing module/IPC probes and the live GNOME mapping probe passed. Live KDE queries reproduced native French versus stale Xwayland US. Formatting and diff checks passed. This is a comment-only change; strict Xwayland-only behavior is preserved.
Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): query native Sway and Hyprland keyboard layouts

Read the uinput keyboard's active layout through compositor IPC and
validate its group against the native Wayland keymap. Match the IPC
server to the Wayland session, and accept numbered Hyprland device
names while rejecting ambiguous keyboard selections.

Validation: 21 temporary production-module and framed-IPC checks passed.
Live Sway US/FR group and a/q mapping checks passed with Xwayland disabled;
the GNOME French layout probe also passed. Formatting checks passed.
A live Hyprland session and a full application build were not tested.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): defer unverified native compositor layout queries

Remove the Sway/Hyprland adapter that paired a uinput device's layout
group with a seat keymap based only on matching layout names. Different
device options can make a synthesized AltGr key toggle CapsLock instead.

Restore the existing best-effort Xwayland source for other desktops and
document the device-keymap information missing from the examined native
queries. GNOME/KDE discovery and injection/cache behavior are unchanged.

Validation: 16 temporary production-module/IPC checks passed after the
removal, plus read-only GNOME French and Xwayland mapping checks. Rust
formatting and diff checks passed. No full application build or mobile
end-to-end test was run for this follow-up.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): reject unreliable GNOME per-window layout sources

GNOME restores per-window layouts without persisting MRU. Reject MRU
selection when per-window input sources are enabled with multiple sources,
and invalidate the cached map and source identity for this typed error.
Transient discovery failures still retain the last valid mapping.

Reuse the existing logged/disableable compatibility policy. This contains
stale-map acceptance; it does not add effective per-window layout discovery.
Single-source and global-source GNOME configurations retain their path.

Validation: the old code failed the temporary stale-cache regression.
All 3 focused production-module checks pass after the fix, covering cache
invalidation/recovery, compatibility modes, single/default source mapping,
UK punctuation, and last-good retention after an IBus connection failure.
Compiled with rustc and cached Linux dependencies; formatting/diff checks
passed. No permanent tests, Cargo/Flutter build or mobile session added.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): reject inactive IBus layout sources

Read the current GlobalEngine description instead of looking up the
persisted MRU engine by name. GNOME can suppress IBus for password entry
without updating MRU, leaving the old engine's layout valid but inactive.

Report an engine-ID mismatch as UnreliableSource so the existing cache
invalidation path drops that mapping. Keep transient query-error handling
and layout/variant normalization. Do not infer a US compositor layout from
GNOME's xkb:us::eng echo engine.

Validation: the old code failed the inactive-engine cache and default-layout
checks. All 3 temporary production-module/D-Bus checks pass with this fix,
covering invalidation/recovery, compatibility policies, metadata sentinels,
query failures and ordinary French XKB selection. Compiled with rustc and
cached Linux dependencies; formatting/diff checks pass. No permanent tests,
Cargo/Flutter build or live password/mobile session added.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): prewarm uinput layout discovery at startup

Start the existing layout worker when the uinput keyboard client connects,
before the server accepts remote input. Reuse its throttle and single-worker
logic; keep the existing 25 ms input wait and background completion policy.
Prewarming reduces cold-start fallback without introducing input queues or
promising readiness while a desktop query remains outstanding.

Verified with three temporary Linux production-module checks using cached
dependencies: a 125 ms query resolves UK @ before first input, a 200 ms
outstanding query stays nonblocking and publishes its map, and a failed
startup query retries successfully. All three fail their startup assertions
before the change. No permanent tests or Cargo/Flutter builds were added.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): preserve first input wait during layout prewarming

Keep the startup query's completion receiver until the first relevant input
takes it. That input can wait for the already-running query within the
existing 25 ms deadline, without holding the receiver handoff lock. Later
input remains nonblocking and the existing single-worker guard is unchanged.
Prefer a due refresh to an old completed startup notification.

Verified with four temporary Linux production-module checks compiled with
rustc -C opt-level=3 and cached dependencies: joining a pending UK query,
one bounded wait followed by nonblocking input, due refresh after prewarm,
and recovery after query failure. Both lost-wait checks fail before the fix.
Formatting and git diff --check pass. No permanent tests or full build added.

An unoptimized delayed-query probe still exceeded 25 ms and used fallback;
this restores the wait opportunity, not an initial-readiness guarantee.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(uinput): remove unnecessary change

Signed-off-by: fufesou <linlong1266@gmail.com>

* refactor(linux): simplify uinput character releases

Release the mapping stored for the same character. Linux character input already pairs down/up events, so opposite-case matching is unnecessary.

Validation: git diff --check passed. Static comparisons confirmed that Map-mode dispatch, raw-key injection and keycode offsets match the PR base. No Cargo/Flutter commands or live-session tests were run.
Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): normalize Unicode CapsLock shortcuts

Normalize single-scalar Unicode lowercase for CapsLock shortcuts without adding Shift. For lowercase expansions, resolve the original symbol with the actual CapsLock state instead of truncating it. Document the existing first-seat discovery limitation.

Validation: two temporary Rust context checks against lookup fixtures failed before the fix and passed afterward. No Cargo/Flutter build or end-to-end input test was run.
Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): derive CapsLock shortcut keys from XKB

Keep the actual CapsLock state when resolving shortcut characters. Use the existing Caps-off and Caps+Shift mappings to omit generated Shift only when XKB confirms the same physical key and remaining modifiers, preserving the Turkish I/ı and İ/i key identities.

Validation: three temporary production-module checks passed on 192.168.5.32 with native libxkbcommon; two failed before this fix. Covered Turkish, German, Cyrillic and ASCII shortcuts, explicit Shift, ordinary text and UK punctuation. No full application build, IPC or end-to-end input test was run.
Signed-off-by: fufesou <linlong1266@gmail.com>

* refactor(linux): remove CapsLock shortcut special cases

Use the existing lock-state synchronization and ordinary XKB mappings for mobile soft-keyboard input. Remove CapsLock-specific shortcut remapping and compatibility-path lowercasing while retaining held-Shift punctuation handling.

Validation: rebuilt the Linux Rust library and reused the unchanged Flutter UI. Actual Android Gboard input matched UK punctuation on GNOME and KDE; French/German switching on KDE passed after the refresh interval. The user confirmed real iPad input on both hosts, including smart quotes. Formatting and whitespace checks passed. The optional Ctrl/Shift toolbar automation was inconclusive and is not counted as passing coverage.
Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): press Level3 before Shift for uinput characters

Preserve mapping candidate preference while storing generated modifiers in Level3-before-Shift order. This avoids activating Compose with lv3:ralt_switch_multikey; releases retain their existing reverse order.

Verified on Linux with temporary production-mapper/libxkbcommon tests: Lithuanian ! fails before this change and passes afterward; all 24 UK punctuation/lock-state cases pass with released modifiers and unchanged lock state. Formatting and diff checks pass. No full application build or mobile end-to-end test was run for this change.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): preserve legacy uinput IPC without a keymap

Send sequences and character clicks through their original IPC messages when the layout cache is unavailable, avoiding unnecessary synchronous key-state queries. Keep throttled fallback warnings and leave layout discovery, retry policy, and key-down/up pairing unchanged.

Verified with three temporary production-method checks on Linux using a recording transport and injected query errors. The unavailable-map routing check fails before the fix and passes afterward; raw-click routing and available-map query-error handling remain unchanged. Changed-code formatting and diff checks pass. No full application build or end-to-end input test was run.

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(linux): skip layout queries for legacy uinput fallback

When no keymap is available, single-character input must use the legacy
KeyDown/KeyUp path without querying lock or modifier state first. Retain
the legacy key in the existing press record so discovery completing
before a repeat or release cannot change the selected representation.

Validated with four temporary production-method checks on Linux using a
controlled cache/resolver and recording transport: missing-map fallback
with query failures, press/release across cache transitions, unchanged
raw-key dispatch, and Ctrl+C without extra Shift or queries. The initial
fallback check failed before this change. Valid-map errors still surface.

Changed-code formatting and git diff --check pass. No full Cargo/Flutter
build or live service/mobile test was run for this change.

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-10-09 11:17:04 +08:00
2026-06-18 22:37:15 +08:00
2026-09-22 16:12:11 +08:00
2026-09-06 00:21:28 +08:00
…
…
2026-08-25 19:53:56 +08:00

RustDesk - Your remote desktop
Build • Docker • Structure • Screenshots
[Українська] | [česky] | [中文] | [Magyar] | [Español] | [فارسی] | [Français] | [Deutsch] | [Polski] | [Indonesian] | [Suomi] | [മലയാളം] | [日本語] | [Nederlands] | [Italiano] | [Русский] | [Português (Brasil)] | [Esperanto] | [한국어] | [العربي] | [Tiếng Việt] | [Dansk] | [Ελληνικά] | [Türkçe] | [Norsk] | [Română]
We need your help to translate this README, RustDesk UI and RustDesk Doc to your native language

Caution

Misuse Disclaimer:
The developers of RustDesk do not condone or support any unethical or illegal use of this software. Misuse, such as unauthorized access, control or invasion of privacy, is strictly against our guidelines. The authors are not responsible for any misuse of the application.

Chat with us: Discord | Twitter | Reddit | YouTube

RustDesk Server Pro

Yet another remote desktop solution, written in Rust. Works out of the box with no configuration required. You have full control of your data, with no concerns about security. You can use our rendezvous/relay server, set up your own, or write your own rendezvous/relay server.

image

RustDesk welcomes contribution from everyone. See CONTRIBUTING.md for help getting started.

FAQ

BINARY DOWNLOAD

NIGHTLY BUILD

Get it on F-Droid Get it on Flathub

Dependencies

Desktop versions use Flutter or Sciter (deprecated) for GUI. This tutorial is for Sciter only, since it is easier and more friendly to start. Check out our CI for building the Flutter version.

Please download Sciter dynamic library yourself.

Windows | Linux | macOS

Raw Steps to build

  • Prepare your Rust development env and C++ build env

  • Install vcpkg, and set VCPKG_ROOT env variable correctly

    • Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
    • Linux/macOS: vcpkg install libvpx libyuv opus aom
  • run cargo run

Build

How to Build on Linux

Ubuntu 18 (Debian 10)

sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
        libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
        libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev

openSUSE Tumbleweed

sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel

Fedora 28 (CentOS 8)

sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel

Arch (Manjaro)

sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pipewire

Install vcpkg

git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 2023.04.15
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus aom

Fix libvpx (For Fedora)

cd vcpkg/buildtrees/libvpx/src
cd *
./configure
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
make
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd

Build

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run

How to build with Docker

Begin by cloning the repository and building the Docker container:

git clone https://github.com/rustdesk/rustdesk
cd rustdesk
git submodule update --init --recursive
docker build -t "rustdesk-builder" .

Then, each time you need to build the application, run the following command:

docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder

Note that the first build may take longer before dependencies are cached, subsequent builds will be faster. Additionally, if you need to specify different arguments to the build command, you may do so at the end of the command in the <OPTIONAL-ARGS> position. For instance, if you wanted to build an optimized release version, you would run the command above followed by --release. The resulting executable will be available in the target folder on your system, and can be run with:

target/debug/rustdesk

Or, if you're running a release executable:

target/release/rustdesk

Please ensure that you run these commands from the root of the RustDesk repository, or the application may not find the required resources. Also note that other cargo subcommands such as install or run are not currently supported via this method as they would install or run the program inside the container instead of the host.

File Structure

Screenshots

Connection Manager

Connected to a Windows PC

File Transfer

TCP Tunneling

Languages
Rust 70.4%
Dart 21.5%
Python 1.8%
C++ 1.6%
C 1.5%
Other 3%