1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
|
From 1b11b2e3f51bbaea5fa10f3103006669a7b29145 Mon Sep 17 00:00:00 2001
From: Fabio Bas <ctrlaltca@gmail.com>
Date: Fri, 18 Jul 2025 16:20:07 +0200
Subject: [PATCH] Use KModifierKeyInfo to detect *lock modifiers' status
RDP: sync {caps,num,lock}lock keystate to remote session on start and at every focusIn
BUG: 349813
---
CMakeLists.txt | 5 ++-
core/CMakeLists.txt | 1 +
core/remoteview.cpp | 34 +++++++++++++++++++
core/remoteview.h | 16 +++++++++
...krdc.desktop => org.kde.krdc.desktop.cmake | 3 +-
rdp/rdpsession.cpp | 24 +++++++++++++
rdp/rdpsession.h | 2 ++
rdp/rdpview.cpp | 9 +++++
rdp/rdpview.h | 1 +
9 files changed, 93 insertions(+), 2 deletions(-)
rename org.kde.krdc.desktop => org.kde.krdc.desktop.cmake (98%)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e446da0a..d556e980 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -51,6 +51,7 @@ find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS
I18n
KIO
Crash
+ GuiAddons
)
find_package(KF6StatusNotifierItem ${KF_MIN_VERSION} REQUIRED)
@@ -230,7 +231,9 @@ if (HAVE_KACTIVITIES)
endif()
install(TARGETS krdc ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
-install(PROGRAMS org.kde.krdc.desktop DESTINATION ${KDE_INSTALL_APPDIR})
+configure_file(org.kde.krdc.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/org.kde.krdc.desktop @ONLY)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.krdc.desktop DESTINATION ${KDE_INSTALL_APPDIR})
install(FILES org.kde.krdc.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
ecm_install_icons(
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index bb8e3b6c..85260d57 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -31,6 +31,7 @@ target_link_libraries(krdccore
KF6::I18n
KF6::ConfigGui
KF6::Completion
+ KF6::GuiAddons
Qt::Gui
Qt::Widgets)
diff --git a/core/remoteview.cpp b/core/remoteview.cpp
index ef76ef3c..d912ae29 100644
--- a/core/remoteview.cpp
+++ b/core/remoteview.cpp
@@ -9,6 +9,9 @@
#include "remoteview.h"
#include "krdc_debug.h"
+#ifndef QTONLY
+#include <KModifierKeyInfo>
+#endif
#include <QApplication>
#include <QBitmap>
#include <QEvent>
@@ -58,6 +61,10 @@ RemoteView::RemoteView(QWidget *parent)
m_clipboard = QApplication::clipboard();
connect(m_clipboard, &QClipboard::dataChanged, this, &RemoteView::localClipboardChanged);
+#ifndef QTONLY
+ m_modifierKeyInfo = new KModifierKeyInfo(this);
+#endif
+
#ifdef HAVE_WAYLAND
if (qGuiApp->platformName() == QLatin1String("wayland")) {
m_inhibition.reset(new WaylandInhibition(window()->windowHandle()));
@@ -568,4 +575,31 @@ void RemoteView::sshErrorMessage(const QString &message)
QWidget::releaseKeyboard();
}
+bool RemoteView::isCapsLockEnabled()
+{
+#ifdef QTONLY
+ return false;
+#else
+ return m_modifierKeyInfo->isKeyLatched(Qt::Key_CapsLock) || m_modifierKeyInfo->isKeyLocked(Qt::Key_CapsLock);
+#endif
+}
+
+bool RemoteView::isNumLockEnabled()
+{
+#ifdef QTONLY
+ return false;
+#else
+ return m_modifierKeyInfo->isKeyLatched(Qt::Key_NumLock) || m_modifierKeyInfo->isKeyLocked(Qt::Key_NumLock);
+#endif
+}
+
+bool RemoteView::isScrollLockEnabled()
+{
+#ifdef QTONLY
+ return false;
+#else
+ return m_modifierKeyInfo->isKeyLatched(Qt::Key_ScrollLock) || m_modifierKeyInfo->isKeyLocked(Qt::Key_ScrollLock);
+#endif
+}
+
#include "moc_remoteview.cpp"
diff --git a/core/remoteview.h b/core/remoteview.h
index c5bf3cbe..bf1483e4 100644
--- a/core/remoteview.h
+++ b/core/remoteview.h
@@ -36,6 +36,7 @@ struct ModifierKey {
};
class HostPreferences;
+class KModifierKeyInfo;
/**
* Generic widget that displays a remote framebuffer.
@@ -263,6 +264,19 @@ public:
*/
virtual QPixmap takeScreenshot();
+ /**
+ * @return status of the caps lock key
+ */
+ bool isCapsLockEnabled();
+ /**
+ * @return status of the num lock key
+ */
+ bool isNumLockEnabled();
+ /**
+ * @return status of the scroll lock key
+ */
+ bool isScrollLockEnabled();
+
#ifndef QTONLY
/**
* Returns the current host preferences of this view.
@@ -456,6 +470,8 @@ protected:
qreal m_factor;
QClipboard *m_clipboard;
QMap<int, ModifierKey> m_modifiers;
+ KModifierKeyInfo *m_modifierKeyInfo;
+
#ifdef HAVE_WAYLAND
std::unique_ptr<ShortcutInhibition> m_inhibition;
#endif
diff --git a/org.kde.krdc.desktop b/org.kde.krdc.desktop.cmake
similarity index 98%
rename from org.kde.krdc.desktop
rename to org.kde.krdc.desktop.cmake
index 29ab2e5c..3beb404c 100755
--- a/org.kde.krdc.desktop
+++ b/org.kde.krdc.desktop.cmake
@@ -1,7 +1,7 @@
# KDE Config File
[Desktop Entry]
Type=Application
-Exec=krdc -qwindowtitle %c %u
+Exec=@CMAKE_INSTALL_PREFIX@/bin/krdc -qwindowtitle %c %u
Icon=krdc
Terminal=false
Name=KRDC
@@ -180,3 +180,4 @@ X-DocPath=krdc/index.html
StartupWMClass=krdc
MimeType=x-scheme-handler/vnc;x-scheme-handler/rdp;application/x-krdc;
Categories=Qt;KDE;Network;RemoteAccess;
+X-KDE-Wayland-Interfaces=org_kde_kwin_keystate
\ No newline at end of file
diff --git a/rdp/rdpsession.cpp b/rdp/rdpsession.cpp
index 25747609..3449092a 100644
--- a/rdp/rdpsession.cpp
+++ b/rdp/rdpsession.cpp
@@ -987,6 +987,10 @@ bool RdpSession::sendEvent(QEvent *event, QWidget *source)
switch (event->type()) {
case QEvent::KeyPress:
case QEvent::KeyRelease: {
+ if (m_needKeyStateSync) {
+ m_needKeyStateSync = false;
+ syncKeyState();
+ }
auto keyEvent = static_cast<QKeyEvent *>(event);
const DWORD vc = GetVirtualKeyCodeFromKeycode(keyEvent->nativeScanCode(), WINPR_KEYCODE_TYPE_XKB);
const DWORD code = GetVirtualScanCodeFromVirtualKeyCode(vc, WINPR_KBD_TYPE_IBM_ENHANCED);
@@ -1090,6 +1094,26 @@ bool RdpSession::sendEvent(QEvent *event, QWidget *source)
return QObject::event(event);
}
+bool RdpSession::syncKeyState()
+{
+ auto input = m_context.rdp->input;
+ if (!input) {
+ return false;
+ }
+
+ UINT16 flags = 0;
+
+ if (m_view->isCapsLockEnabled())
+ flags |= KBD_SYNC_CAPS_LOCK;
+ if (m_view->isNumLockEnabled())
+ flags |= KBD_SYNC_NUM_LOCK;
+ if (m_view->isScrollLockEnabled())
+ flags |= KBD_SYNC_SCROLL_LOCK;
+
+ qCDebug(KRDC) << "Sync key state: " << flags;
+ return freerdp_input_send_synchronize_event(input, flags);
+}
+
void RdpSession::setState(RdpSession::State newState)
{
if (newState == m_state) {
diff --git a/rdp/rdpsession.h b/rdp/rdpsession.h
index 1caf25ae..61e42b60 100644
--- a/rdp/rdpsession.h
+++ b/rdp/rdpsession.h
@@ -103,6 +103,7 @@ public:
void stop();
bool sendEvent(QEvent *event, QWidget *source);
+ bool syncKeyState();
void initializeClipboard(RdpContext *krdp, CliprdrClientContext *cliprdr);
void initializeDisplay(RdpContext *krdp, DispClientContext *disp);
@@ -201,6 +202,7 @@ private:
int m_port = -1;
QSize m_size;
bool m_firstPasswordTry;
+ bool m_needKeyStateSync = true;
std::thread m_thread;
diff --git a/rdp/rdpview.cpp b/rdp/rdpview.cpp
index 1a32bd72..d4583584 100644
--- a/rdp/rdpview.cpp
+++ b/rdp/rdpview.cpp
@@ -512,4 +512,13 @@ void RdpView::handleLocalClipboardChanged(const QMimeData *data)
if (m_session) {
m_session->sendClipboard(data);
}
-}
\ No newline at end of file
+}
+
+void RdpView::focusInEvent(QFocusEvent *event)
+{
+ if (m_session) {
+ m_session->syncKeyState();
+ }
+
+ RemoteView::focusInEvent(event);
+}
diff --git a/rdp/rdpview.h b/rdp/rdpview.h
index 996beecb..c5063125 100644
--- a/rdp/rdpview.h
+++ b/rdp/rdpview.h
@@ -75,6 +75,7 @@ protected:
void handleWheelEvent(QWheelEvent *event) override;
void handleMouseEvent(QMouseEvent *event) override;
void handleLocalClipboardChanged(const QMimeData *data) override;
+ void focusInEvent(QFocusEvent *event) override;
private:
void onRectangleUpdated(const QRect &rect);
--
GitLab
|