RDP session fixes: correct keyboard scancodes, clipboard sync, cursor shapes

Fix RDP keyboard input using FreeRDP's authoritative X11-keycode-to-scancode
table instead of ad hoc bit math, which misread punctuation keys as unrelated
letter keys (e.g. apostrophe as B) because X11 keycode numbering only
coincidentally overlaps PC/AT scancodes.

Add bidirectional clipboard sync (CF_UNICODETEXT) over the cliprdr channel,
and RDP pointer/cursor shape sync so the local cursor reflects what the
remote OS wants displayed (resize handles, text I-beam, etc.) instead of
staying a static arrow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-07 14:53:03 -06:00
co-authored by Claude Sonnet 5
parent 27cc3a3bb2
commit 793fdd9366
8 changed files with 654 additions and 27 deletions
+11
View File
@@ -34,6 +34,7 @@ public slots:
void sendMouseMoveEvent(int x, int y) override;
void sendMouseButtonEvent(int x, int y, int button, bool pressed) override;
void sendMouseWheelEvent(int x, int y, int deltaX, int deltaY) override;
void setClipboardText(const QString& text) override;
private:
enum class InputEventType {
@@ -42,6 +43,7 @@ private:
MouseButton,
MouseWheel,
Resize,
SetClipboardText,
};
struct InputEvent {
@@ -84,6 +86,10 @@ private:
int m_lastResizeWidth;
int m_lastResizeHeight;
std::mutex m_cliprdrMutex;
void* m_cliprdrContext;
QString m_pendingLocalClipboardText;
void setState(SessionState state, const QString& message);
bool validateProfile(QString& message) const;
void startWorker();
@@ -92,12 +98,17 @@ private:
void enqueueInputEvent(const InputEvent& event);
void processInputEvents(rdp_freerdp* instance);
bool sendDisplayResize(rdp_freerdp* instance, int width, int height);
void sendClipboardTextToRemote(rdp_freerdp* instance, const QString& text);
public:
void onChannelConnectedEvent(const char* name, void* channelInterface);
void onChannelDisconnectedEvent(const char* name, void* channelInterface);
void onDisplayControlCaps(uint32_t maxNumMonitors,
uint32_t maxMonitorAreaFactorA,
uint32_t maxMonitorAreaFactorB);
void onCliprdrMonitorReady();
void onCliprdrServerFormatList(bool hasUnicodeText);
void onCliprdrServerFormatDataRequest(uint32_t requestedFormatId);
void onCliprdrServerFormatDataResponse(bool success, const uint8_t* data, uint32_t size);
private:
void emitStateAsync(SessionState state, const QString& message);
void emitConnectionFailureAsync(const QString& displayMessage, const QString& rawMessage);