aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/rfb/VNCSConnectionST.cxx69
-rw-r--r--common/rfb/VNCServer.h4
-rw-r--r--common/rfb/VNCServerST.cxx8
-rw-r--r--common/rfb/VNCServerST.h2
-rw-r--r--unix/xserver/hw/vnc/Input.c6
-rw-r--r--unix/xserver/hw/vnc/Input.h2
-rw-r--r--unix/xserver/hw/vnc/InputXKB.c17
7 files changed, 82 insertions, 26 deletions
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 53dd364a..de41e8fc 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -34,10 +34,12 @@
#include <rfb/Security.h>
#include <rfb/screenTypes.h>
#include <rfb/fenceTypes.h>
+#include <rfb/ledStates.h>
#include <rfb/ServerCore.h>
#include <rfb/ComparingUpdateTracker.h>
#include <rfb/KeyRemapper.h>
#include <rfb/Encoder.h>
+#define XK_LATIN1
#define XK_MISCELLANY
#define XK_XKB_KEYS
#include <rfb/keysymdef.h>
@@ -560,6 +562,73 @@ void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) {
}
}
+ // Avoid lock keys if we don't know the server state
+ if ((server->ledState == ledUnknown) &&
+ ((key == XK_Caps_Lock) ||
+ (key == XK_Num_Lock) ||
+ (key == XK_Scroll_Lock))) {
+ vlog.debug("Ignoring lock key (e.g. caps lock)");
+ return;
+ }
+ // Always ignore ScrollLock though as we don't have a heuristic
+ // for that
+ if (key == XK_Scroll_Lock) {
+ vlog.debug("Ignoring lock key (e.g. caps lock)");
+ return;
+ }
+
+ if (down && (server->ledState != ledUnknown)) {
+ // CapsLock synchronisation heuristic
+ // (this assumes standard interaction between CapsLock the Shift
+ // keys and normal characters)
+ if (((key >= XK_A) && (key <= XK_Z)) ||
+ ((key >= XK_a) && (key <= XK_z))) {
+ bool uppercase, shift, lock;
+
+ uppercase = (key >= XK_A) && (key <= XK_Z);
+ shift = pressedKeys.find(XK_Shift_L) != pressedKeys.end() ||
+ pressedKeys.find(XK_Shift_R) != pressedKeys.end();
+ lock = server->ledState & ledCapsLock;
+
+ if (lock == (uppercase == shift)) {
+ vlog.debug("Inserting fake CapsLock to get in sync with client");
+ server->desktop->keyEvent(XK_Caps_Lock, true);
+ server->desktop->keyEvent(XK_Caps_Lock, false);
+ }
+ }
+
+ // NumLock synchronisation heuristic
+ // (this is more cautious because of the differences between Unix,
+ // Windows and macOS)
+ if (((key >= XK_KP_Home) && (key <= XK_KP_Delete)) ||
+ ((key >= XK_KP_0) && (key <= XK_KP_9)) ||
+ (key == XK_KP_Separator) || (key == XK_KP_Decimal)) {
+ bool number, shift, lock;
+
+ number = ((key >= XK_KP_0) && (key <= XK_KP_9)) ||
+ (key == XK_KP_Separator) || (key == XK_KP_Decimal);
+ shift = pressedKeys.find(XK_Shift_L) != pressedKeys.end() ||
+ pressedKeys.find(XK_Shift_R) != pressedKeys.end();
+ lock = server->ledState & ledNumLock;
+
+ if (shift) {
+ // We don't know the appropriate NumLock state for when Shift
+ // is pressed as it could be one of:
+ //
+ // a) A Unix client where Shift negates NumLock
+ //
+ // b) A Windows client where Shift only cancels NumLock
+ //
+ // c) A macOS client where Shift doesn't have any effect
+ //
+ } else if (lock == (number == shift)) {
+ vlog.debug("Inserting fake NumLock to get in sync with client");
+ server->desktop->keyEvent(XK_Num_Lock, true);
+ server->desktop->keyEvent(XK_Num_Lock, false);
+ }
+ }
+ }
+
// Turn ISO_Left_Tab into shifted Tab.
VNCSConnectionSTShiftPresser shiftPresser(server->desktop);
if (key == XK_ISO_Left_Tab) {
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index 982a4ff5..c5335ad2 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -74,6 +74,10 @@ namespace rfb {
// setName() tells the server what desktop title to supply to clients
virtual void setName(const char* name) = 0;
+
+ // setLEDState() tells the server what the current lock keys LED
+ // state is
+ virtual void setLEDState(unsigned int state) = 0;
};
}
#endif
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index ec5e962f..28f6a62b 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -58,6 +58,7 @@
#include <rfb/Security.h>
#include <rfb/KeyRemapper.h>
#include <rfb/util.h>
+#include <rfb/ledStates.h>
#include <rdr/types.h>
@@ -74,7 +75,7 @@ LogWriter VNCServerST::connectionsLog("Connections");
VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
: blHosts(&blacklist), desktop(desktop_), desktopStarted(false),
- blockCounter(0), pb(0),
+ blockCounter(0), pb(0), ledState(ledUnknown),
name(strDup(name_)), pointerClient(0), comparer(0),
cursor(new Cursor(0, 0, Point(), NULL)),
renderedCursorInvalid(false),
@@ -458,6 +459,11 @@ void VNCServerST::setCursorPos(const Point& pos)
}
}
+void VNCServerST::setLEDState(unsigned int state)
+{
+ ledState = state;
+}
+
// Other public methods
void VNCServerST::approveConnection(network::Socket* sock, bool accept,
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 00f77c73..2dfdbbdb 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -101,6 +101,7 @@ namespace rfb {
virtual void setCursor(int width, int height, const Point& hotspot,
const rdr::U8* data);
virtual void setCursorPos(const Point& p);
+ virtual void setLEDState(unsigned state);
virtual void bell();
@@ -209,6 +210,7 @@ namespace rfb {
int blockCounter;
PixelBuffer* pb;
ScreenSet screenLayout;
+ unsigned int ledState;
CharArray name;
diff --git a/unix/xserver/hw/vnc/Input.c b/unix/xserver/hw/vnc/Input.c
index 33e8604b..1d7183b9 100644
--- a/unix/xserver/hw/vnc/Input.c
+++ b/unix/xserver/hw/vnc/Input.c
@@ -437,12 +437,6 @@ void vncKeyboardEvent(KeySym keysym, int down)
}
}
- /* We don't have lock synchronisation... */
- if (vncIsLockModifier(keycode, new_state)) {
- LOG_DEBUG("Ignoring lock key (e.g. caps lock)");
- return;
- }
-
/* No matches. Will have to add a new entry... */
if (keycode == 0) {
keycode = vncAddKeysym(keysym, state);
diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h
index 11e88710..67b9c8db 100644
--- a/unix/xserver/hw/vnc/Input.h
+++ b/unix/xserver/hw/vnc/Input.h
@@ -53,8 +53,6 @@ size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys);
KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
-int vncIsLockModifier(KeyCode keycode, unsigned state);
-
int vncIsAffectedByNumLock(KeyCode keycode);
KeyCode vncAddKeysym(KeySym keysym, unsigned state);
diff --git a/unix/xserver/hw/vnc/InputXKB.c b/unix/xserver/hw/vnc/InputXKB.c
index 2a3f7afb..a9bd11d1 100644
--- a/unix/xserver/hw/vnc/InputXKB.c
+++ b/unix/xserver/hw/vnc/InputXKB.c
@@ -485,23 +485,6 @@ KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
return 0;
}
-int vncIsLockModifier(KeyCode keycode, unsigned state)
-{
- XkbDescPtr xkb;
- XkbAction *act;
-
- xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-
- act = XkbKeyActionPtr(xkb, keycode, state);
- if (act == NULL)
- return 0;
-
- if (act->type != XkbSA_LockMods)
- return 0;
-
- return 1;
-}
-
int vncIsAffectedByNumLock(KeyCode keycode)
{
unsigned state;