Internal
Public Access
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>
120 lines
3.8 KiB
C++
120 lines
3.8 KiB
C++
#ifndef ORBITHUB_RDP_SESSION_BACKEND_H
|
|
#define ORBITHUB_RDP_SESSION_BACKEND_H
|
|
|
|
#include "session_backend.h"
|
|
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <deque>
|
|
#include <mutex>
|
|
#include <thread>
|
|
|
|
struct rdp_freerdp;
|
|
|
|
class RdpSessionBackend : public SessionBackend
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit RdpSessionBackend(const Profile& profile, QObject* parent = nullptr);
|
|
~RdpSessionBackend() override;
|
|
|
|
public slots:
|
|
void connectSession(const SessionConnectOptions& options) override;
|
|
void disconnectSession() override;
|
|
void reconnectSession(const SessionConnectOptions& options) override;
|
|
void sendInput(const QString& input) override;
|
|
void confirmHostKey(bool trustHost) override;
|
|
void updateTerminalSize(int columns, int rows) override;
|
|
void sendKeyEvent(int key,
|
|
quint32 nativeScanCode,
|
|
const QString& text,
|
|
bool pressed,
|
|
int modifiers) override;
|
|
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 {
|
|
Key,
|
|
MouseMove,
|
|
MouseButton,
|
|
MouseWheel,
|
|
Resize,
|
|
SetClipboardText,
|
|
};
|
|
|
|
struct InputEvent {
|
|
InputEventType type = InputEventType::MouseMove;
|
|
int key = 0;
|
|
quint32 nativeScanCode = 0;
|
|
QString text;
|
|
bool pressed = false;
|
|
int modifiers = 0;
|
|
int x = 0;
|
|
int y = 0;
|
|
int button = 0;
|
|
int deltaX = 0;
|
|
int deltaY = 0;
|
|
int width = 0;
|
|
int height = 0;
|
|
};
|
|
|
|
SessionState m_state;
|
|
SessionConnectOptions m_activeOptions;
|
|
std::atomic_bool m_userInitiatedDisconnect;
|
|
|
|
std::atomic_int m_requestedDesktopWidth;
|
|
std::atomic_int m_requestedDesktopHeight;
|
|
|
|
std::thread m_worker;
|
|
std::atomic_bool m_workerRunning;
|
|
std::atomic_bool m_stopRequested;
|
|
|
|
std::mutex m_instanceMutex;
|
|
rdp_freerdp* m_instance;
|
|
|
|
std::mutex m_inputMutex;
|
|
std::deque<InputEvent> m_inputEvents;
|
|
|
|
std::mutex m_displayControlMutex;
|
|
void* m_displayControlContext;
|
|
bool m_displayControlReady;
|
|
bool m_resizeFailureLogged;
|
|
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();
|
|
void stopWorker(bool userInitiated);
|
|
void workerMain();
|
|
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);
|
|
int sanitizeDesktopWidth(int width) const;
|
|
int sanitizeDesktopHeight(int height) const;
|
|
};
|
|
|
|
#endif
|