Skip to content

Avoid control-key collisions when typing literal text - #77

Merged
atx merged 1 commit into
atx:masterfrom
tijszwinkels:fix/printable-keycodes
Oct 20, 2026
Merged

atx merged 1 commit into
atx:masterfrom
tijszwinkels:fix/printable-keycodes

Conversation

@tijszwinkels

@tijszwinkels tijszwinkels commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Addresses #71 for literal-only invocations.

wtype assigns each distinct character the next sequential keycode, starting at evdev 1 / XKB 9. This can put printable characters on physical control-key positions. Chromium can then interpret a character as an editing command despite its assigned keysym.

This PR was created with help from the Pi coding agent and the Astra model. I have reviewed the changes and tested them extensively.

Problem

For example, on Arch with Hyprland 0.56.2, wtype 0.4-2 and Chromium 153.0.8010.36 on Wayland:

wtype -d 1 -- "let's just keep it open."
# Before: let's just keep it ope
# After:  let's just keep it open.

The period is the 14th distinct character, so stock wtype assigns it evdev 14 / XKB 22: physical Backspace. Chromium reports key=".", code="Backspace", keyCode=8, followed by deleteContentBackward.

Solution

This patch assigns literal text only to the 48 physical keycodes in the printable section of a PC keyboard, avoiding Escape, Backspace, Tab, Enter and modifier positions. The character assignments remain generated from the input, so text is not restricted to a particular keyboard layout.

For inputs with more than 48 distinct characters, the patch divides the character list into groups and uploads the required group's keymap before typing. The same physical codes are reused for each group. Switching happens only between complete press/release pairs, and returning to an earlier group reloads its map. Characters within the active group require no switch.

Limitations

  • Any invocation containing -k, -P, -p, -M or -m retains the original upstream path, preserving explicit key and modifier behavior. This also means literal text mixed with those options remains unfixed. Literal argv and stdin input, delays and sleeps remain supported.

  • Frequently alternating between groups adds keymap-upload overhead.

  • The separately observed Chromium corruption of non-BMP characters such as emoji remains unfixed.

Sequential synthetic keycodes can put a printable character on a physical
control key. In Chromium, a period assigned to evdev 14 can produce
Backspace editing behavior despite its printable keysym.

For literal-only invocations, map characters to 48 printable evdev positions
and upload bounded keymaps between completed press/release pairs. Keep the
existing mapping for invocations with explicit key or modifier commands,
including literal text mixed into those invocations, so held keys and
explicit chords retain their existing behavior.

This does not address Chromium's separate supplementary-Unicode limitation.

Refs: atx#71
@alexcampbelling

Copy link
Copy Markdown

Heya @tijszwinkels,

I just found this PR as it fixes my current, and same, issue. However this project looks to be unmaintained.

I have shifted my scripts from wtype to ydotool.

Having also using the same display server protocol and OS, I recommend it highly :)

@fedesapuppo

Copy link
Copy Markdown

Another case this fixes: a single space typed into the Chromium omnibox.

Flux (bjarneo/flux) types phone keyboard input with one wtype - per keystroke, so every character is the first in its keymap and lands on evdev 1 (Escape). The omnibox drops a space on that code. Letters survive.

Repro on Hyprland, wtype 0.4-2, Chrome stable, clean profile, omnibox focused:

for c in h o l a ' ' c o m o; do printf '%s' "$c" | wtype -; done
# omnibox shows: holacomo

A text field in a web page receives key=" " code="Escape" and keeps the space. Only the omnibox drops it.

With this PR built (99e8e15), the same loop types hola como in the omnibox.

mellotanica added a commit to mellotanica/community-plugins that referenced this pull request Oct 18, 2026
…dotool (v2.7.0)

wtype is unmaintained and mistypes some punctuation sequences (atx/wtype#71,
fix in the unmerged atx/wtype#77). ydotool injects through /dev/uinput via
its ydotoold daemon, so it is display-server agnostic (issue noctalia-dev#995).

- Type rows, Autotype and the type-* / autotype quick actions now run
  `ydotool type -e 0 -d <keyDelay> -- <value>`. `-e 0` is required: ydotool
  interprets backslash escapes in argv strings by default, which would turn
  a `\n` / `\t` inside a password into Enter / Tab.
- Autotype separator / submit keys use `ydotool key <code>:1 <code>:0` with
  raw input-event keycodes (Tab 15, Enter 28) instead of wtype keysyms.
- A failed run whose stderr mentions ydotoold gets a dedicated
  "ydotoold is not running" notification body (new
  notification.ydotoold-not-running key, en + it).
- Setting `wtypeDelay` renamed to `keyDelay` (settings.key-delay.*);
  manifest dependency wtype -> ydotool; version 2.7.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ItsLemmy pushed a commit to noctalia-dev/community-plugins that referenced this pull request Oct 18, 2026
…fix #995) (#1059)

* feat(launcher-pass): switch the Type/Autotype backend from wtype to ydotool (v2.7.0)

wtype is unmaintained and mistypes some punctuation sequences (atx/wtype#71,
fix in the unmerged atx/wtype#77). ydotool injects through /dev/uinput via
its ydotoold daemon, so it is display-server agnostic (issue #995).

- Type rows, Autotype and the type-* / autotype quick actions now run
  `ydotool type -e 0 -d <keyDelay> -- <value>`. `-e 0` is required: ydotool
  interprets backslash escapes in argv strings by default, which would turn
  a `\n` / `\t` inside a password into Enter / Tab.
- Autotype separator / submit keys use `ydotool key <code>:1 <code>:0` with
  raw input-event keycodes (Tab 15, Enter 28) instead of wtype keysyms.
- A failed run whose stderr mentions ydotoold gets a dedicated
  "ydotoold is not running" notification body (new
  notification.ydotoold-not-running key, en + it).
- Setting `wtypeDelay` renamed to `keyDelay` (settings.key-delay.*);
  manifest dependency wtype -> ydotool; version 2.7.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(launcher-pass): document the ydotool typing backend in the README

Replace every wtype reference with ydotool, document the ydotoold daemon /
uinput requirement and the "ydotoold is not running" notification, warn about
ydotool's US-layout key mapping, and note the wtypeDelay -> keyDelay setting
rename.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(launcher-pass): update CLAUDE.md for the ydotool typing backend

Describe ydotoolTypeArgv / ydotoolKeyArgv / typeFailed / runTypeSteps, the
mandatory `-e 0`, raw keycodes for Tab/Enter, the ydotoold and US-layout
caveats, the keyDelay setting rename, and record the wtype -> ydotool design
decision. The cmdline-leak open point now names the stdin path
(`ydotool type -f -`) to adopt once runAsync can feed stdin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(launcher-pass): selectable typing backend (ydotool / wtype)

ydotool is display-server agnostic but maps every character onto a US-layout
keycode, so symbols come out wrong on other active layouts; wtype uploads its
own keymap and follows any layout, but needs the Wayland virtual-keyboard
protocol. Neither strictly wins, so a new `typeBackend` select setting picks
the tool (default ydotool, per #995).

- TYPE_BACKENDS holds each backend's binary, text argv, Tab/Enter key argv
  and optional daemon hint; typeTextArgv / typeKeyArgv / typeFailed route
  every Type row, Autotype and type-* / autotype quick action through it.
- typerAvailable probes the selected backend's binary (memoised per binary),
  so the Type / Autotype rows follow the selection.
- The "ydotoold is not running" hint only applies to ydotool.
- wtype is back in the manifest dependencies; en + it strings for the new
  setting; README / CLAUDE.md describe both backends. CLAUDE.md records that
  noctalia main (plugin_api 34) still has no native typing / paste path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(launcher-pass): run user-paced pass/edit calls without runAsync's 60 s cap

noctalia.runAsync clamps its timeout to [50 ms, 60 s] and on expiry SIGTERMs
then SIGKILLs the child's whole process group (verified in noctalia v5.2.1
and main @ 47945ec). The plugin asked for 5 min (decrypts) and 24 h (Edit),
both silently cut to 60 s: an Edit terminal was killed a minute in, losing
the unsaved buffer, and a pinentry wait past 60 s failed the action.

- New runUnbounded(argv, cb): builds a `sh -c` string from the argv (shq per
  element, stdin from /dev/null, stderr to a per-call side file under
  pluginDataDir), runs it with noctalia.runStream (no timeout) and appends
  a per-call, per-VM marker line carrying `$?`. On the marker it calls cb
  with a runAsync-shaped {exitCode, stdout, stderr, timedOut = false},
  stdout rebuilt byte-exact, and removes the side file.
- pass show (detail view + withEntryData), pass -c / pass otp -c, pass otp
  (Type OTP, Autotype), pass generate [-i], and both `pass edit` terminal
  runs now go through it. Short runs stay on runAsync.
- Falls back to a 60 s runAsync (logged) when runStream is missing or its
  4-streams-per-VM cap is hit.
- DECRYPT_TIMEOUT_MS / EDIT_TIMEOUT_MS replaced by RUNASYNC_MAX_TIMEOUT_MS
  (fallback only). CLAUDE.md runtime reference corrected (runAsync clamp,
  runStream, readFile / removeFile); README notes the wrapper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(launcher-pass): preferred typing backend with automatic fallback

The typeBackend setting now names the *preferred* backend ("Preferred typing
backend"); the other installed one is used automatically when the preferred
one is missing or can't type in this session. This keeps ydotool as the
default without breaking Type / Autotype for users who haven't set up
ydotoold but have wtype installed (and vice versa on compositors without the
virtual-keyboard protocol).

- typeBackends() lists the installed backends in try order (preferred
  first); the Type / Autotype rows now show when at least one is installed.
- runTypeSteps runs backend-neutral steps ({text} / {key}) and, when step 1
  fails with a backend's "unavailable" stderr (ydotool: ydotoold not
  running; wtype: no virtual-keyboard protocol / no Wayland connection),
  replays the whole list on the next backend. Both errors come from the
  connect phase, before any key is sent, so nothing is typed twice; a
  mid-chain failure still aborts. The fallback is logged, not notified.
- Failure bodies: notification.no-typing-backend when every installed
  backend was unavailable, else the backend's own message
  (ydotoold-not-running / new wtype-unsupported), else the entry name.
- en + it strings; README / CLAUDE.md document the fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(launcher-pass): drop wtype compositor-support handling

Noctalia only runs on Wayland compositors that provide the protocols wtype
relies on, so wtype has no realistic "can't type here" state:

- wtype's unavailableHints ("virtual keyboard protocol", "Wayland
  connection failed") are now empty, so the automatic fallback is
  ydotool → wtype only (when ydotoold is not running).
- Removed the now-unreachable notification.wtype-unsupported and
  notification.no-typing-backend strings (en, it); an unavailable backend
  with nothing left to try reports its own unavailableKey.
- Dropped the "any compositor" / "virtual-keyboard protocol" wording from
  comments, the typeBackend setting description and option labels, the
  README backend table and CLAUDE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(launcher-pass): show the resolved typing backend on the Autotype row

The Autotype row subtitle now names the backend that will be tried first
(typeBackends()[1]: the preferred one if installed, else the other), e.g.
"Type username, password, and OTP in sequence with ydotool", so the user
can see which tool — and therefore which layout behaviour — applies. A
runtime fallback (ydotoold not running) is only discovered when the action
runs, so it isn't reflected here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(launcher-pass): show the resolved typing backend on the Type rows

Every Type row (password, OTP, username, fields) now appends the backend
that will be tried first to its subtitle via the new action.type-subtitle
key ("{subtitle} · {backend}"), e.g. "jdoe · ydotool", matching the
Autotype row. type-password-desc is shortened to "Type password" since
the backend name now follows it ("Type password · wtype"). Copy rows are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(launcher-pass): detect ydotoold-down from ydotool's stdout

ydotool 1.0.4 prints "failed to connect socket … Please check if ydotoold
is running." on stdout, not stderr (verified: exit 2, empty stderr).
backendUnavailable only searched stderr, so a stopped daemon was treated
as a generic failure: no fallback to wtype, and the type-failed
notification showed the entry name instead of "ydotoold is not running".

Unavailable hints are now matched against stdout and stderr, and the
fallback log line includes both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(launcher-pass): re-probe typing backends and terminal while running

backendInstalled and detectedTerminal memoised their PATH scan for the
whole plugin session, so installing / removing ydotool or wtype (or the
terminal) was only noticed after a plugin reload: removed tools kept their
Type rows and a restored one stayed hidden. That contradicted the
documented "missing preferred backend → the other is used" behaviour.

Both probes are now cached for PROBE_TTL_MS (2 s) only. Rendering one view
still shares a single scan, and a change shows up on the next view without
a reload. commandExists is a few access() calls per PATH entry, so the
re-probe is cheap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(launcher-pass): show wtype on Type rows when ydotoold is down

The Type / Autotype subtitles named the preferred backend even when
ydotoold wasn't running, although the action would then fall back to
wtype. They now name the backend that will actually type.

probeYdotoold runs `ydotool debug`, which connects to the daemon socket
before doing anything and sends no input events: exit 0 when ydotoold
answers, exit 2 with "Please check if ydotoold is running." on stdout when
not (verified against a live daemon and a bogus YDOTOOL_SOCKET). Checking
the socket file isn't enough: a stopped daemon leaves it behind
("Connection refused"). The probe is async and cached for PROBE_TTL_MS; it
is kicked from renderDetailRows, and when the shown backend flips, the open
detail view is re-rendered from the warm cache.

Display only: actions still try the preferred backend first and fall back
on its real connect error, so a daemon started meanwhile is used at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@sawy3r

sawy3r commented Oct 20, 2026

Copy link
Copy Markdown

Confirming the same bug on COSMIC: Pop!_OS 24.04, cosmic-comp 0.1~1791227611, wtype 0.4-3, Google Chrome 154.0.8037.92 (Flatpak).

Dictated text piped through wtype - lost every full stop along with the letter before it ("It mostly looks right." came out as "It mostly looks righ"). In that transcript the period is the 14th distinct character, so it landed on evdev 14 (Backspace), matching the analysis here. It happened in Chrome text fields and in a terminal as well, so it is not limited to Chromium and Electron.

We fixed it in our own tool by taking the same approach as this PR: literal characters only go on the printable key positions, space, Return and Tab go on their real keys, and the keymap switches once there are more than 48 distinct characters. +1 for getting this merged.

@tijszwinkels

Copy link
Copy Markdown
Contributor Author

@atx By now, quite a few people have looked at this and are waiting for this. I understand this is not your focus, but could you merge?

@atx
atx merged commit 82bca82 into atx:master Oct 20, 2026
@atx

atx commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Right, LGTM! My worry here was that it used to be that some clients really hated the keymap getting switched from under them repeatedly. But doing some casual testing this is probably no longer the case as of 2026

@sawy3r

sawy3r commented Oct 20, 2026

Copy link
Copy Markdown

Thanks @atx for merging, and @tijszwinkels for the fix!

@tijszwinkels

Copy link
Copy Markdown
Contributor Author

Super @atx ! Thanks for merging this!

Hancock33 added a commit to Hancock33/batocera.piboy that referenced this pull request Oct 25, 2026
--------------------------------------------------------------------------------------------------------
batocera-emulationstation.mk b2ceb55a7e3d205a11f055b7d93c8be50cd6f9c9 # Version: Commits on Oct 21, 2026
--------------------------------------------------------------------------------------------------------
update po
Signed-off-by: Nicolas Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>,

-------------------------------------------------------------
armsx2.mk nightly-20261021 # Version: Commits on Oct 21, 2026
-------------------------------------------------------------
Automated nightly build for community testing (unsigned).
Every download is named `ARMSX2-nightly-DATE-COMMIT-PLATFORM`, so builds
from different nights stay distinguishable after you have downloaded them.
- macOS arm64: macOS-arm64.tar.xz
- Linux arm64: Linux-arm64-4K-pages.AppImage on most distros, or the 16K one on Asahi Linux and other Apple Silicon kernels (run getconf PAGESIZE if unsure)
- Windows arm64: Windows-arm64.zip
- RetroArch on Linux arm64: Linux-arm64-libretro-core.tar.zst, a 4K-page build
- Bare-display kmsdrm handhelds: Linux-arm64-SDL-handheld.tar.zst, a 4K-page build (Rocknix and Batocera run compositors, so use the Qt AppImage there instead)
- Android: Android-arm64.apk (installs as ARMSX2 Nightly, alongside the stable app)
- iOS: iOS-arm64.ipa, unsigned, sideload it (installs as ARMSX2 Nightly, alongside the stable app)
Coming from an old nightly? Nightlies are now a separate app, ARMSX2 Nightly, next to stable.
- Android: stable cannot install over an old nightly. Back up your saves and memory cards, uninstall the old nightly, then install the stable APK.
- iOS: your old nightly is the ARMSX2 iOS app and still has your saves. Copy them into ARMSX2 Nightly with the Files app.
## What's new
- GameDB back-thread hint: withheld when the IOP thread is on
- GameDB: a back thread recommendation, set for Spider-Man 3, Sly 3 and Up Your Arsenal
- GS back thread: the busiest emulation thread gets the prime core alone
- GS/HW: an opaque draw whose blend was elided as the identity keeps the previous blended draw's pipeline
- GS/HW: retire a target whose dirty rectangles together cover it, not only one that a single rectangle covers
- GS/SW: CollectSprites takes the minify option at compile time
- GS/SW: gather the 32-bit texel copy's rows with the tap counts fixed at compile time
- GS/SW: the 32-bit texel copy takes bilinear lookups whose weights are zero or a half
- GS/SW: copy 32-bit texture sprite draws into 32-bit frames straight from local memory
- Android: changing a setting auto-tune moves, in a game's settings, turns auto-tune off for that game
- Big Picture: changing a setting auto-tune moves, in a game's settings, turns auto-tune off for that game
- Qt: changing a setting auto-tune moves, in a game's properties, turns auto-tune off for that game
- AutoTune: a setting the player changes by hand turns auto-tune off for that game
- Android: the setup page's driver card shows the release name at full width
- Android: the library list shows each game's file name
- Android: home screen shortcuts use the game's cover
- Android: the themed app icon shows the tower
- Touch: Tight L1/L2/R1/R2 touch areas option
- Android: Volume and Mute in the in-game menu's Options page
- Audio: Recording-compatible audio setting
Full changelog: ARMSX2/ARMSX2@nightly-20261020...65fd14b

------------------------------------------------------------------------------------------
duckstation.mk 48a1028f9a2f3a3c907cca82ce41d30c9ef2d747 # Version: Commits on Oct 21, 2026
------------------------------------------------------------------------------------------
Data: Add simple-color-adjustments postfx shader,

--------------------------------------------------------------------------------------
flycast.mk a9bd1c74fd207aabdc917824afb93b3a571dd5c4 # Version: Commits on Oct 21, 2026
--------------------------------------------------------------------------------------
empty commit,

----------------------------------------------------
pcsx2.mk v2.9.135 # Version: Commits on Oct 21, 2026
----------------------------------------------------
- [Achievements: Fix default sound effect path on AppImage](PCSX2/pcsx2#15075)
,

-------------------------------------------------------------------------------------
ppsspp.mk e1610adf54e8b83322c8e873ed7e56623a484c1d # Version: Commits on Oct 21, 2026
-------------------------------------------------------------------------------------
Merge pull request #22714 from hrydgard/vsh-umd
VSH: UMD discs and UMD Video in the XMB,

-------------------------------------------------------------------------------------
vita3k.mk ed0b71271fa9632c2d81532ef87da0cddf2bc970 # Version: Commits on Oct 21, 2026
-------------------------------------------------------------------------------------
kernel: prepare the sync object wait protocol (#4280)
* ci: run the latest VitaAutotests
* kernel: hand out each sync object's resource in one place
The semaphore, mutex, rwlock, event flag and simple event each move the code that gives waiters
what they wait for into a private serve(), which their signal, unlock and set calls use.
No behavior change.
* kernel: run a wait's callbacks from the wait loop
ThreadState::wait ran notified callbacks itself before returning. It now returns NOTIFY_CALLBACK,
and each wait loop runs them with run_callbacks() at the same point, so the loop decides what the
waiter does around them. No behavior change.
* kernel: let a waiter that leaves give its turn to the waiters behind it
A wait that ended by its timeout or its thread's end took nothing, but the waiters behind it
weren't served what they could take then. Each sync object now waits through wait_on(), which
then asks the object to serve() its other waiters, as a signal does. serve() becomes a sync object
virtual that does nothing by default, for the condition variable, the timer and the message pipe,
which keeps its own loop for now.
* kernel: write a sync object wait's time left back in wait_on
Every sync object wait computed its deadline from the guest timeout before wait_on() and wrote
the time left back after it. wait_on() now takes the guest timeout and does both, as the wait
protocol's own step. No behavior change.
* kernel: note two Vita behaviors the sync objects don't copy
A send that hands bytes to a waiting DONT_REMOVE receive leaves a Vita's message pipe out of step,
and a lightweight mutex deleted before a signaled condition waiter gets back to it leaves that
waiter blocked. Both stay out on purpose.,

-----------------------------------------------------------------------------------------
xenia-edge.mk 9677e195593cf92ac80213089b9c669875a353c3 # Version: Commits on Oct 21, 2026
-----------------------------------------------------------------------------------------
[XAM] Support content headers in canary's current format
Canary now rewrites a package's .header file as the full container header
followed by the save's file name, and moves the thumbnail into it. Reading
that layout when the file starts with an XContent magic keeps those saves
and DLC usable here without converting them on disk. Deriving each header
path from the package actually resolved makes every reader agree on which
header belongs to which package. The display name fallback also reached
only 11 of the 12 language slots so fixing that too.,

-------------------------------------------------------------------------------------------
jazz2-native.mk be7f99084245ac868a466ff2cfb6181d6ac5460b # Version: Commits on Oct 21, 2026
-------------------------------------------------------------------------------------------
Fixed build,

------------------------------------------------
7zip.mk 26.05 # Version: Commits on Oct 21, 2026
------------------------------------------------
26.05,

------------------------------------------------------
syncthing.mk v2.1.7 # Version: Commits on Oct 21, 2026
------------------------------------------------------
## What's Changed
Built with Go 1.27.3.
### Fixes
* fix: handle missing max-sequence file entries by @calmh in syncthing/syncthing#10912
* fix(sqlite): avoid early garbage collection of deleted recv-enc files by @calmh in syncthing/syncthing#10916
* fix(sqlite): do not generate unbounded prepared statements (ref #10913) by @calmh in syncthing/syncthing#10915
* fix(discover): skip unnecessary identical global announce updates; obey retry-after by @calmh in syncthing/syncthing#10918
* fix(protocol): convert panics on bad data to protocol errors by @calmh in syncthing/syncthing#10923
* fix(model): verify local change before applying metadata shortcut (fixes #10924) by @calmh in syncthing/syncthing#10925
* fix(model): ensure parent ownership is copied properly (fixes #8399) by @calmh in syncthing/syncthing#10926
* fix(model): properly compare blocks when reconciling receive-only (fixes #10928) by @calmh in syncthing/syncthing#10929
### Other
* build(deps): update dependencies by @calmh in syncthing/syncthing#10917
* chore(protocol): add protovalidate validation of incoming messages, reasonable limits by @calmh in syncthing/syncthing#10838
**Full Changelog**: syncthing/syncthing@v2.1.6...v2.1.7,

------------------------------------------------
wtype.mk v0.5 # Version: Commits on Oct 20, 2026
------------------------------------------------
## What's Changed
* Avoid control-key collisions when typing literal text by @tijszwinkels in atx/wtype#77
* Add additional modifier keys by @tmccombs in atx/wtype#57
**Full Changelog**: atx/wtype@v0.4...v0.5,

----------------------------------------------------------------------------------------
retroarch.mk 793afc25f4d6176128efb8e443e06d821a54838c # Version: Commits on Oct 21, 2026
----------------------------------------------------------------------------------------
test: isolate VT Main10 edge padding and parameter headers,

----------------------------------------------------------------------------------------
doomretro.mk 917d1b7f2950aa846ce872de87857646a11e9600 # Version: Commits on Oct 21, 2026
----------------------------------------------------------------------------------------
Implement soft shadows,

--------------------------------------------------------------------------------------
yquake2.mk bce5c05c40f706b46d4b76268b42eabde6c74cb5 # Version: Commits on Oct 20, 2026
--------------------------------------------------------------------------------------
protocol: svc_configstring in 25 version
Looks like its same as with Quake 2 original 26 version.,

------------------------------------------------------------------------------------------
xash3d-fwgs.mk d6b54aaf6c1d8518e08404a842f3f6ee02cef3cc # Version: Commits on Oct 21, 2026
------------------------------------------------------------------------------------------
3rdparty: extras: update submodule,

----------------------------------------------------------------------------------------------
libretro-anybor.mk cde9634630b8d1014468aed0a35c749a8cec09bd # Version: Commits on Oct 21, 2026
----------------------------------------------------------------------------------------------
fix(render): guard optional sprite masks
Keep optional masks safe during top clipping and transform traversal without changing pixels. Collect macOS regression failures and close font-probe streams.,

----------------------------------------------------------------------
libretro-armsx2.mk nightly-20261021 # Version: Commits on Oct 21, 2026
----------------------------------------------------------------------
Automated nightly build for community testing (unsigned).
Every download is named `ARMSX2-nightly-DATE-COMMIT-PLATFORM`, so builds
from different nights stay distinguishable after you have downloaded them.
- macOS arm64: macOS-arm64.tar.xz
- Linux arm64: Linux-arm64-4K-pages.AppImage on most distros, or the 16K one on Asahi Linux and other Apple Silicon kernels (run getconf PAGESIZE if unsure)
- Windows arm64: Windows-arm64.zip
- RetroArch on Linux arm64: Linux-arm64-libretro-core.tar.zst, a 4K-page build
- Bare-display kmsdrm handhelds: Linux-arm64-SDL-handheld.tar.zst, a 4K-page build (Rocknix and Batocera run compositors, so use the Qt AppImage there instead)
- Android: Android-arm64.apk (installs as ARMSX2 Nightly, alongside the stable app)
- iOS: iOS-arm64.ipa, unsigned, sideload it (installs as ARMSX2 Nightly, alongside the stable app)
Coming from an old nightly? Nightlies are now a separate app, ARMSX2 Nightly, next to stable.
- Android: stable cannot install over an old nightly. Back up your saves and memory cards, uninstall the old nightly, then install the stable APK.
- iOS: your old nightly is the ARMSX2 iOS app and still has your saves. Copy them into ARMSX2 Nightly with the Files app.
## What's new
- GameDB back-thread hint: withheld when the IOP thread is on
- GameDB: a back thread recommendation, set for Spider-Man 3, Sly 3 and Up Your Arsenal
- GS back thread: the busiest emulation thread gets the prime core alone
- GS/HW: an opaque draw whose blend was elided as the identity keeps the previous blended draw's pipeline
- GS/HW: retire a target whose dirty rectangles together cover it, not only one that a single rectangle covers
- GS/SW: CollectSprites takes the minify option at compile time
- GS/SW: gather the 32-bit texel copy's rows with the tap counts fixed at compile time
- GS/SW: the 32-bit texel copy takes bilinear lookups whose weights are zero or a half
- GS/SW: copy 32-bit texture sprite draws into 32-bit frames straight from local memory
- Android: changing a setting auto-tune moves, in a game's settings, turns auto-tune off for that game
- Big Picture: changing a setting auto-tune moves, in a game's settings, turns auto-tune off for that game
- Qt: changing a setting auto-tune moves, in a game's properties, turns auto-tune off for that game
- AutoTune: a setting the player changes by hand turns auto-tune off for that game
- Android: the setup page's driver card shows the release name at full width
- Android: the library list shows each game's file name
- Android: home screen shortcuts use the game's cover
- Android: the themed app icon shows the tower
- Touch: Tight L1/L2/R1/R2 touch areas option
- Android: Volume and Mute in the in-game menu's Options page
- Audio: Recording-compatible audio setting
Full changelog: ARMSX2/ARMSX2@nightly-20261020...65fd14b

-----------------------------------------------------------------------------------------------------
libretro-beetle-saturn.mk d0d841784845da0278a9a49554cc4cc01597ee2c # Version: Commits on Oct 21, 2026
-----------------------------------------------------------------------------------------------------
Add selectable 4MB Saturn backup memory (#94),

---------------------------------------------------------------------------------------------
libretro-cap32.mk 8e61dd69d948cea16c3bad734f7b9d0c2a018cc8 # Version: Commits on Oct 21, 2026
---------------------------------------------------------------------------------------------
fix(timing): adjust reported FPS to match exact hardware frame rate
Aligns the reported frontend FPS with the true Z80 frame rate
(19968us per frame). This eliminates the 0.14% mismatch and
removes the need for constant DRC audio resampling in RetroArch.,

---------------------------------------------------------------------------------------------
libretro-fbneo.mk 2b0c1c0679df115cada7df9199ea2762222e58fd # Version: Commits on Oct 21, 2026
---------------------------------------------------------------------------------------------
(libretro) update files,

-----------------------------------------------------------------------------------------------
libretro-flycast.mk a9bd1c74fd207aabdc917824afb93b3a571dd5c4 # Version: Commits on Oct 21, 2026
-----------------------------------------------------------------------------------------------
empty commit,

--------------------------------------------------------------------------------------------------
libretro-gearcoleco.mk 23f30ac9ee21c3142291e644908e55a924d7f384 # Version: Commits on Oct 20, 2026
--------------------------------------------------------------------------------------------------
Ask for version, frontend and log in Issue Triage,

-------------------------------------------------------------------------------------------------
libretro-geargrafx.mk b476273bc8271ba3a056b535922342f5919e5d7c # Version: Commits on Oct 20, 2026
-------------------------------------------------------------------------------------------------
Ask for version, frontend and log in Issue Triage,

--------------------------------------------------------------------------------------------------
libretro-gearsystem.mk b1cf2c4af6fb17651f8d3a5a2e0a3ba07865be05 # Version: Commits on Oct 20, 2026
--------------------------------------------------------------------------------------------------
Ask for version, frontend and log in Issue Triage,

-----------------------------------------------------------------------------------------------------
libretro-mame2003-plus.mk d708f399f75766ebbe924f1752bbe57036b4376d # Version: Commits on Oct 21, 2026
-----------------------------------------------------------------------------------------------------
Tecmo TPS (COH-1002M): all MAME sets playable with sound (#2094)
The Tecmo TPS games on the ZN-1 board code from #2081, with the sets and
file names of current MAME. Replaces the old non-working tps sets.
- zn.c: TPS board (2 MB VRAM, 8 MB game ROM banks at 0x1f000000, bank
  register at 0x1fb00006, four coin counters), CAT702 keys read from the
  MG01 / MGnn dumps in the sets, PSX SPU sound.
- Cool Boarders Arcade Jam: sound board with a Z80, a YMZ280B and the two
  IDT7202 FIFOs to the main CPU.
- 1 on 1 Government: the factory EEPROM of the set is used when there is
  no NVRAM yet (else: \loading backup data failed\).
- Gallop Racer 2 Link HW: link board ROM in the set, CPU not emulated
  (not connected to anything in MAME either).
- Old protection hack and link machine removed; BIOS is coh1002m (was tps).
- metadata/mame2003-plus.xml: TPS entries regenerated.
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
Co-authored-by: Claude <noreply@anthropic.com>,

----------------------------------------------------------------------------------------------
libretro-ppsspp.mk e1610adf54e8b83322c8e873ed7e56623a484c1d # Version: Commits on Oct 21, 2026
----------------------------------------------------------------------------------------------
Merge pull request #22714 from hrydgard/vsh-umd
VSH: UMD discs and UMD Video in the XMB,

---------------------------------------------------------------------------------------------
libretro-vba-m.mk 3924aab43a646b6291ae29a26cb3bd7f67a0d297 # Version: Commits on Oct 21, 2026
---------------------------------------------------------------------------------------------
Fix CI warnings,

-------------------------------------------------------------------------------------------
glsl-shaders.mk ad947689af01544f2857591a0e3e171ac30e9dff # Version: Commits on Oct 20, 2026
-------------------------------------------------------------------------------------------
Add xBRZ crisp (GLSL version) (#576)
* xBRZ freescale multipass: add minimum contrast, threshold parameters and port fixes
Add an xbrz-crisp preset that uses the same two passes with a minimum
contrast of 16, equal color tolerance 15 and steep/shallow threshold 3.0.
The multipass defaults keep the current look: the new parameters default
to 0, 30 and 2.2. The output pass now applies the four corners in the
order of the reference xBRZ, resolves blend color ties the same way, and
takes the output scale from the image size instead of the texture size.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NoUuzh3YspgqPacroVBWQ7
* xBRZ freescale multipass: default to tolerance 15 and steep threshold 3.0
At tolerance 30 small dark holes in stone textures get merged into the
surrounding color, and at 2.2 a 1-pixel step on a vertical edge is read
as a sloped line. 15 and 3.0 keep both closer to the original art. The
xbrz-crisp preset now only sets the minimum contrast. The old look is
still available with XBRZ_TOL 30 and XBRZ_STEEP 2.2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NoUuzh3YspgqPacroVBWQ7
---------
Co-authored-by: Michel <13533421+ele3131@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>,

--------------------------------------------------------------------------------------------
slang-shaders.mk eef0df221e440b1ad1bd2f9019552ea3359a51e2 # Version: Commits on Oct 21, 2026
--------------------------------------------------------------------------------------------
Update geom.slang (#972),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants