Repository navigation
feat(agent): add clipboard-get and clipboard-set operations - #1863
Merged
Marc-André Moreau (mamoreau-devolutions) merged 1 commit intoSep 1, 2026
Conversation
Greg Lamberson (glamberson)
temporarily deployed
to
llm-providers
September 1, 2026 00:42 — with
GitHub Actions
Inactive
Contributor
|
text is a good first step, but it would be great to support images as well, even in the daemon |
Contributor
Author
|
Marc-André Moreau (@mamoreau-devolutions) Agreed. I'll get that done shortly. |
Wires an in-memory CLIPRDR backend into ironrdp-daemon: clipboard-get prints the last text received from the remote clipboard, clipboard-set writes the local clipboard text and advertises it to the remote. Plain CF_UNICODETEXT only, no file transfer, no HTML or image formats. Resolves the TODO left in ironrdp-rpc's Request enum. A headless daemon has no host clipboard of its own, so the backend just holds the last text pushed by clipboard-set as its local content and the last text received from the remote as its remote content, both behind a lock shared with the daemon's IPC handlers. client_capabilities() advertises no file-transfer flags, matching that scope. Enables the clipboard Cargo feature on ironrdp-daemon's ironrdp-client dependency, which was previously off there, so the CLIPRDR channel fell back to StubClipboard and did nothing with remote clipboard content. Verified live against a real RDP server end to end: clipboard-set text landed in the server's OS clipboard, and a clipboard change made directly on the server's side was correctly fetched by clipboard-get.
Greg Lamberson (glamberson)
force-pushed
the
feat/agent-clipboard
branch
from
September 1, 2026 10:41
aa4a772 to
0a0f85f
Compare
Greg Lamberson (glamberson)
temporarily deployed
to
llm-providers
September 1, 2026 10:41 — with
GitHub Actions
Inactive
Marc-André Moreau (mamoreau-devolutions)
approved these changes
Sep 1, 2026
Marc-André Moreau (mamoreau-devolutions)
merged commit Sep 1, 2026
3955003
into
Devolutions:master
44 checks passed
Greg Lamberson (glamberson)
added a commit
to lamco-admin/IronRDP
that referenced
this pull request
Sep 3, 2026
Extends the daemon clipboard-get/clipboard-set operations added in Devolutions#1863 to images: clipboard-get-image writes the last image received from the remote clipboard to a PNG file, clipboard-set-image reads a PNG file and advertises it to the remote as CF_DIB/CF_DIBV5. The daemon stores images as PNG bytes and converts to/from the wire's DIB byte layout via ironrdp-cliprdr-format's existing png_to_cf_dib(v5) and dib(v5)_to_png. Both DIB variants are advertised when offering an image (DIBV5 is richer but not every peer understands it); on paste, DIBV5 is preferred over DIB, and image is preferred over text when the remote offers both. Replaces ClipboardState's two Option<String> fields with a small ClipboardContent enum (Text/Image) so local and remote clipboard content is a single logical item, matching how each clipboard-set* call replaces whatever was there before. New Request::ClipboardGetImage/ClipboardSetImage and Payload::ClipboardImage wire variants. Adds the two new variants to ironrdp-activex's exhaustive match on Request, same treatment as the existing ClipboardGet/ClipboardSet arm (unavailable through the ActiveX automation surface). Behavior change: clipboard-get now prints (empty) if the last remote copy was an image rather than text, since local/remote content is a single logical item. Previously it always reflected the last text. Review round (CBenoit, Copilot): Seven issues addressed. - MAX_CLIPBOARD_IMAGE_BYTES is now derived from ironrdp-rpc's own transport::MAX_MESSAGE_LEN (16 MiB) minus framing headroom, instead of an unrelated 64 MiB that the RPC transport could never actually carry. - Fixed a real, pre-existing bug in ironrdp-cliprdr-format::bitmap:: decode_png: It requested ALPHA | EXPAND but not STRIP_16, and this png crate version declares a GRAY_TO_RGB transform flag but never implements it, so grayscale and 16-bit-per-channel PNGs decoded to a buffer layout the RGBA-only conversion downstream silently misread. Added STRIP_16, a manual GrayscaleAlpha-to-RGBA expansion, a MAX_BUFFER_SIZE re-check for that expansion, and grayscale/16-bit regression tests. - The CLIPRDR backend now serializes paste requests: on_remote_copy no longer issues a second SendInitiatePaste while one is outstanding (a stale response could otherwise be misinterpreted as the answer to a newer request, since FormatDataResponse carries no correlation ID). A newer copy is queued and issued once the outstanding one resolves, or after a 5-second timeout if the peer never answers. - The daemon now checks a converted remote image against MAX_CLIPBOARD_IMAGE_BYTES before storing it, so a legitimate but oversized image from the remote can't get stuck in a state where clipboard-get-image can never send it back. - clipboard_set/clipboard_set_image now write local and advertise to a connected session as one atomic step under the clipboard mutex, so concurrent IPC callers can't interleave their state write and their advertisement. - clipboard-set-image reads at most MAX_CLIPBOARD_IMAGE_BYTES + 1 bytes via Read::take instead of loading the whole file before checking its size. - Extended the Debug-redaction test to also cover the pre-existing text variants, which the original PR body claimed but the test didn't exercise. cargo xtask check fmt/lints/tests/typos/locks all pass. Not yet verified against a live remote client; that check is still owed before merge.
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves the TODO in ironrdp-rpc's Request enum for clipboard support: read the remote clipboard text and set it, so an LLM (or any daemon caller) can copy and paste to and from the session.
The backend is deliberately text only. A headless daemon has no host clipboard, so it holds the last text pushed by clipboard-set as its local content and the last text received from the remote as its remote content, both behind a lock shared with the daemon's IPC handlers. client_capabilities() advertises no file transfer flags, matching that scope.
The clipboard Cargo feature on ironrdp-daemon's ironrdp-client dependency was previously off, so the CLIPRDR channel fell back to StubClipboard on non-Windows and did nothing with remote clipboard content. This enables it and supplies a real backend factory.
Verified live against a running RDP server: clipboard-set text landed in the server's own OS clipboard, and a clipboard change made directly on the server side was correctly fetched by clipboard-get.