diff --git a/doc/rdesktop.1 b/doc/rdesktop.1
index c48fc0c..30042f8 100644
--- a/doc/rdesktop.1
+++ b/doc/rdesktop.1
@@ -92,6 +92,11 @@ size, in pixels. The special word "standard" means 18 pixels.
.BR "-T
"
Sets the window title.
.TP
+.BR "-N"
+Enable numlock syncronization between the Xserver and the remote RDP
+session. This is useful with applications that looks at the numlock
+state, but might cause problems with some Xservers like Xvnc.
+.TP
.BR "-a "
Sets the colour depth for the connection (8, 15, 16 or 24).
More than 8 bpp are only supported when connecting to Windows XP
diff --git a/keymaps/common b/keymaps/common
index f773de6..f53c885 100644
--- a/keymaps/common
+++ b/keymaps/common
@@ -116,38 +116,38 @@ KP_Subtract 0x4a
KP_Add 0x4e
KP_Enter 0x9c
-KP_Decimal 0x53
-KP_Separator 0x53
+KP_Decimal 0x53 numlock
+KP_Separator 0x53 numlock
KP_Delete 0x53
-KP_0 0x52
+KP_0 0x52 numlock
KP_Insert 0x52
-KP_1 0x4f
+KP_1 0x4f numlock
KP_End 0x4f
-KP_2 0x50
+KP_2 0x50 numlock
KP_Down 0x50
-KP_3 0x51
+KP_3 0x51 numlock
KP_Next 0x51
-KP_4 0x4b
+KP_4 0x4b numlock
KP_Left 0x4b
-KP_5 0x4c
+KP_5 0x4c numlock
KP_Begin 0x4c
-KP_6 0x4d
+KP_6 0x4d numlock
KP_Right 0x4d
-KP_7 0x47
+KP_7 0x47 numlock
KP_Home 0x47
-KP_8 0x48
+KP_8 0x48 numlock
KP_Up 0x48
-KP_9 0x49
+KP_9 0x49 numlock
KP_Prior 0x49
#
diff --git a/keymaps/pt-br b/keymaps/pt-br
index 46a96ce..54bafc5 100644
--- a/keymaps/pt-br
+++ b/keymaps/pt-br
@@ -60,7 +60,7 @@ period 0x34
greater 0x34 shift
semicolon 0x35
colon 0x35 shift
-comma 0x53
+comma 0x53 numlock
backslash 0x56
bar 0x56 shift
slash 0x73
diff --git a/rdesktop.c b/rdesktop.c
index 6ad5905..1463885 100644
--- a/rdesktop.c
+++ b/rdesktop.c
@@ -66,6 +66,7 @@ BOOL g_grab_keyboard = True;
BOOL g_hide_decorations = False;
BOOL g_use_rdp5 = True;
BOOL g_console_session = False;
+BOOL g_numlock_sync = False;
extern BOOL g_owncolmap;
#ifdef WITH_RDPSND
@@ -110,6 +111,7 @@ usage(char *program)
fprintf(stderr, " -K: keep window manager key bindings\n");
fprintf(stderr, " -S: caption button size (single application mode)\n");
fprintf(stderr, " -T: window title\n");
+ fprintf(stderr, " -N: enable numlock syncronization\n");
fprintf(stderr, " -a: connection colour depth\n");
fprintf(stderr, " -r: enable specified device redirection (currently: sound)\n");
fprintf(stderr, " -0: attach to console\n");
@@ -229,7 +231,7 @@ main(int argc, char *argv[])
#define VNCOPT
#endif
- while ((c = getopt(argc, argv, VNCOPT "u:d:s:c:p:n:k:g:fbeEmCDKS:T:a:r:045h?")) != -1)
+ while ((c = getopt(argc, argv, VNCOPT "u:d:s:c:p:n:k:g:fbeEmCDKS:T:Na:r:045h?")) != -1)
{
switch (c)
{
@@ -368,6 +370,10 @@ main(int argc, char *argv[])
STRNCPY(g_title, optarg, sizeof(g_title));
break;
+ case 'N':
+ g_numlock_sync = True;
+ break;
+
case 'a':
g_server_bpp = strtol(optarg, NULL, 10);
if (g_server_bpp != 8 && g_server_bpp != 16 && g_server_bpp != 15
diff --git a/xkeymap.c b/xkeymap.c
index ba25e22..c5be513 100644
--- a/xkeymap.c
+++ b/xkeymap.c
@@ -44,6 +44,7 @@ extern int keylayout;
extern int g_win_button_size;
extern BOOL g_enable_compose;
extern BOOL g_use_rdp5;
+extern BOOL g_numlock_sync;
static BOOL keymap_loaded;
static key_translation keymap[KEYMAP_SIZE];
@@ -186,6 +187,11 @@ xkeymap_read(char *mapname)
MASK_ADD_BITS(modifiers, MapLeftShiftMask);
}
+ if (strstr(line_rest, "numlock"))
+ {
+ MASK_ADD_BITS(modifiers, MapNumLockMask);
+ }
+
if (strstr(line_rest, "localstate"))
{
MASK_ADD_BITS(modifiers, MapLocalStateMask);
@@ -361,6 +367,12 @@ handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pres
if (g_win_button_size
&& (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
return True;
+ case XK_Num_Lock:
+ /* FIXME: We might want to do RDP_INPUT_SYNCHRONIZE here, if g_numlock_sync */
+ if (!g_numlock_sync)
+ /* Inhibit */
+ return True;
+
}
return False;
@@ -507,6 +519,33 @@ ensure_remote_modifiers(uint32 ev_time, key_translation tr)
if (is_modifier(tr.scancode))
return;
+ if (!g_numlock_sync)
+ {
+ /* NumLock */
+ if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
+ != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
+ {
+ /* The remote modifier state is not correct */
+ uint16 new_remote_state;
+
+ if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
+ {
+ DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
+ new_remote_state = KBD_FLAG_NUMLOCK;
+ remote_modifier_state = MapNumLockMask;
+ }
+ else
+ {
+ DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
+ new_remote_state = 0;
+ remote_modifier_state = 0;
+ }
+
+ rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
+ }
+ }
+
+
/* Shift. Left shift and right shift are treated as equal; either is fine. */
if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
!= MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
@@ -613,7 +652,8 @@ reset_modifier_keys()
reset_winkey(ev_time);
- rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
+ if (g_numlock_sync)
+ rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
}
@@ -652,6 +692,18 @@ update_modifier_state(uint8 scancode, BOOL pressed)
case SCANCODE_CHAR_RWIN:
MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
break;
+ case SCANCODE_CHAR_NUMLOCK:
+ /* KeyReleases for NumLocks are sent immediately. Toggle the
+ modifier state only on Keypress */
+ if (pressed && !g_numlock_sync)
+ {
+ BOOL newNumLockState;
+ newNumLockState =
+ (MASK_HAS_BITS
+ (remote_modifier_state, MapNumLockMask) == False);
+ MASK_CHANGE_BIT(remote_modifier_state,
+ MapNumLockMask, newNumLockState);
+ }
}
#ifdef WITH_DEBUG_KBD