diff --git a/common/scancode.c b/common/scancode.c index 90f96db4..a25df79d 100644 --- a/common/scancode.c +++ b/common/scancode.c @@ -167,7 +167,8 @@ static const struct scancode_to_keycode { 0x165, 225 }, // VK_BROWSER_SEARCH I225 (KEY_SEARCH) { 0x166, 164 }, // VK_BROWSER_FAVORITES I164 (KEY_BOOKMARKS) { 0x16b, 165 }, // VK_LAUNCH_APP1 I165 (KEY_COMPUTER) - { 0x16c, 163 } // VK_LAUNCH_MAIL I163 (KEY_MAIL) + { 0x16c, 163 }, // VK_LAUNCH_MAIL I163 (KEY_MAIL) + { 0x21d, 127 } // VK_PAUSE PAUS (KEY_PAUSE) }; // Sources:- @@ -291,7 +292,8 @@ static const struct scancode_to_keycode { 0x153, 107 }, // VK_DELETE DELE { 0x15b, 115 }, // VK_LWIN LWIN { 0x15c, 116 }, // VK_RWIN RWIN - { 0x15d, 117 } // VK_APPS COMP + { 0x15d, 117 }, // VK_APPS COMP + { 0x21d, 110 } // VK_PAUSE PAUS (KEY_PAUSE) }; struct map_settings @@ -339,12 +341,23 @@ scancode_to_index(unsigned short scancode) // 0x80 - 0xff : Invalid code return -1; } - if (scancode <= 0x17f) + if (scancode <= 0x177) { - // 01x100 - 0x17f : Move bit 9 to bit 8 + // 01x100 - 0x177 : Move bit 9 to bit 8 return (scancode & 0x7f) | 0x80; } + if (scancode == SCANCODE_PAUSE_KEY) + { + return SCANCODE_INDEX_PAUSE_KEY; + } + + // This leaves the following which are all rejected + // 0x178 - 0x17f (currently unused). These would map to indexes 0xf8 + // to 0xff which we are reserving for extended1 keys. + // 0x180 - 0x1ff Illegal format + // >0x200 Anything not mentioned explicitly above (e.g. + // SCANCODE_PAUSE_KEY) return -1; } @@ -354,7 +367,11 @@ scancode_from_index(int index) { index &= 0xff; unsigned short result; - if (index < 0x80) + if (index == SCANCODE_INDEX_PAUSE_KEY) + { + result = SCANCODE_PAUSE_KEY; + } + else if (index < 0x80) { result = index; } diff --git a/common/scancode.h b/common/scancode.h index 939a4589..a63cd1ee 100644 --- a/common/scancode.h +++ b/common/scancode.h @@ -75,6 +75,7 @@ enum SCANCODE_BACKSPACE_KEY = 0x0e, SCANCODE_ENTER_KEY = 0x1c, SCANCODE_TAB_KEY = 0x0f, + SCANCODE_PAUSE_KEY = 0x21d, SCANCODE_KP_ENTER_KEY = 0x11c, SCANCODE_KP_DEL_KEY = 0x53, @@ -99,6 +100,8 @@ enum SCANCODE_INDEX_LSHIFT_KEY = SCANCODE_LSHIFT_KEY, SCANCODE_INDEX_RSHIFT_KEY = SCANCODE_RSHIFT_KEY, SCANCODE_INDEX_RALT_KEY = (SCANCODE_RALT_KEY & 0x7f) | 0x80, + SCANCODE_INDEX_PAUSE_KEY = 0xf8, + // 0xf9 - 0xff reserved for future extended1 mappings /** * Keys affected by numlock @@ -116,7 +119,7 @@ enum // Convert key_code and flags values received from a TS_KEYBOARD_EVENT // into a value suitable for use by this module #define SCANCODE_FROM_KBD_EVENT(key_code,keyboard_flags) \ - (((key_code) & 0x7f) | ((keyboard_flags) & 0x100)) + (((key_code) & 0x7f) | ((keyboard_flags) & 0x300)) // Convert a scancode used by this module back into a // TS_KEYBOARD_EVENT keyCode value @@ -124,16 +127,18 @@ enum // Convert a scancode used by this module back into a // TS_KEYBOARD_EVENT keyboardFlags value -#define SCANCODE_TO_KBD_EVENT_KBD_FLAGS(scancode) ((scancode) & 0x100) +#define SCANCODE_TO_KBD_EVENT_KBD_FLAGS(scancode) ((scancode) & 0x300) /** * Convert a scancode to an index - * @param scancode scancode in the range 0x00 - 0x1ff + * @param scancode scancode in the range 0x00 - 0x2ff * @return index in the range 0..SCANCODE_MAX_INDEX (inclusive) or -1 * - * This function converts a 9-bit scancode into an 8-bit array index, + * This function converts a 10-bit scancode into an 8-bit array index, * independent of the currently loaded keymap * + * This is possible as the scancodes from 0x80 - 0x2ff are sparsely allocated. + * * For scancodes in the range 0x00 - 0x7f, the index is identical to the * scancode. This includes scancodes for all the keys affected by * numlock. @@ -157,7 +162,8 @@ scancode_from_index(int index); * Looks up an RDP scancode and converts to an x11 keycode * * @param scancode Scancode. Extended scancodes have bit 9 set - * (i.e. are in 0x100 - 0x1ff). + * (i.e. are in 0x100 - 0x1ff). Extended1 scancodes + * (currently just the pause key) are in the range 0x200-0x2ff * @return keycode, or 0 for no keycode */ unsigned short diff --git a/genkeymap/genkeymap.c b/genkeymap/genkeymap.c index b4322983..badc75aa 100644 --- a/genkeymap/genkeymap.c +++ b/genkeymap/genkeymap.c @@ -299,7 +299,11 @@ output_file_section(FILE *outf, unicode = wtext[0]; } - if (scancode > 0xff) + if (scancode > 0x1ff) + { + fputs("E1_", outf); + } + else if (scancode > 0xff) { fputs("E0_", outf); } diff --git a/tests/common/test_scancode.c b/tests/common/test_scancode.c index 675ca905..a764ae1d 100644 --- a/tests/common/test_scancode.c +++ b/tests/common/test_scancode.c @@ -8,7 +8,7 @@ #include "test_common.h" // Max supported scancode value -#define MAX_SUPPORTED_SCANCODE 0x1ff +#define MAX_SUPPORTED_SCANCODE 0x2ff // Checks conversions to-and-from scancode indexes START_TEST(test_scancode__scancode_to_index) @@ -27,18 +27,35 @@ START_TEST(test_scancode__scancode_to_index) ck_assert_int_eq(scancode_to_index(i), -1); } - // 0x100 - 0x17f map to 0x80 - 0xff - for (i = 0x100; i <= 0x17f; ++i) + // 0x100 - 0x177 map to 0x80 - 0xf7 + for (i = 0x100; i <= 0x177; ++i) { ck_assert_int_eq(scancode_to_index(i), i - 0x80); ck_assert_int_eq(scancode_from_index(i - 0x80), i); } - // Scancodes from 0x180 - MAX_SUPPORTED_SCANCODE are not supported - for (i = 0x180; i <= MAX_SUPPORTED_SCANCODE; ++i) + // Scancodes from 0x178 - 0x1ff are not supported + for (i = 0x178; i <= 0x1ff; ++i) { ck_assert_int_eq(scancode_to_index(i), -1); } + + // In the range 0x200 up, only SCANCODE_PAUSE_KEY is + // supported + ck_assert_int_ge(SCANCODE_PAUSE_KEY, 0x200); + ck_assert_int_le(SCANCODE_PAUSE_KEY, MAX_SUPPORTED_SCANCODE); + for (i = 0x200; i <= MAX_SUPPORTED_SCANCODE; ++i) + { + if (i == SCANCODE_PAUSE_KEY) + { + ck_assert_int_eq(scancode_to_index(i), SCANCODE_INDEX_PAUSE_KEY); + ck_assert_int_eq(scancode_from_index(SCANCODE_INDEX_PAUSE_KEY), i); + } + else + { + ck_assert_int_eq(scancode_to_index(i), -1); + } + } } // Checks all returned evdev scancodes are mapped to a keycode diff --git a/vnc/Makefile.am b/vnc/Makefile.am index 93a11bcd..ee5ab23a 100644 --- a/vnc/Makefile.am +++ b/vnc/Makefile.am @@ -5,6 +5,8 @@ AM_CPPFLAGS = \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ -I$(top_srcdir)/common +AM_CFLAGS = $(X_CFLAGS) + module_LTLIBRARIES = \ libvnc.la diff --git a/vnc/vnc.c b/vnc/vnc.c index 09de00d2..13d71bb4 100644 --- a/vnc/vnc.c +++ b/vnc/vnc.c @@ -30,6 +30,8 @@ #include #endif +#include + #include "vnc.h" #include "vnc_clip.h" #include "rfb.h" @@ -443,13 +445,90 @@ resize_server_to_client_layout(struct vnc *v) return error; } +/*****************************************************************************/ +/** + * Process keysym messages + * @param v Module + * @param keysym Keysym of keypress + * @param keydown boolean - is key down? + * @return != 0 for error + */ +static int +process_keysym_msg(struct vnc *v, int keysym, int keydown) +{ + struct stream *s = NULL; + int error = 0; + + if (keysym > 0) + { + make_stream(s); + + /* Break key processing [MS-RDPBCGR] 2.2.8.1.1.3.1.1.1 */ + if (v->ignore_next_numlock) + { + v->ignore_next_numlock = 0; + if (keysym == XK_Num_Lock) + { + goto end_keysym_msg; + } + } + + if (keysym == XK_ISO_Level3_Shift) /* altgr */ + { + if (v->shift_state) + { + /* fix for mstsc sending left control down with altgr */ + init_stream(s, 64); + out_uint8(s, RFB_C2S_KEY_EVENT); + out_uint8(s, 0); /* down flag */ + out_uint8s(s, 2); + out_uint32_be(s, XK_Control_L); /* left control */ + s_mark_end(s); + error = lib_send_copy(v, s); + if (error != 0) + { + goto end_keysym_msg; + } + } + } + + init_stream(s, 64); + out_uint8(s, RFB_C2S_KEY_EVENT); + out_uint8(s, keydown ? 1 : 0); + out_uint8s(s, 2); + out_uint32_be(s, keysym); + s_mark_end(s); + error = lib_send_copy(v, s); + + switch (keysym) + { + case XK_Control_L: /* left control */ + v->shift_state = keydown; + break; + + case XK_Pause: + // [MS-RDPBCGR] 2.2.8.1.1.3.1.1.1 - A pause key scancode + // (up or down) is always immediately followed by a + // numlock key which we should ignore + v->ignore_next_numlock = 1; + break; + + default: + break; + } + } + +end_keysym_msg: + free_stream(s); + return error; +} + /*****************************************************************************/ static int lib_mod_event(struct vnc *v, int msg, long param1, long param2, long param3, long param4) { struct stream *s; - int key; int error; int x; int y; @@ -492,38 +571,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2, } else if ((msg >= 15) && (msg <= 16)) /* key events */ { - key = param2; - - if (key > 0) - { - if (key == 65027) /* altgr */ - { - if (v->shift_state) - { - /* fix for mstsc sending left control down with altgr */ - init_stream(s, 8192); - out_uint8(s, RFB_C2S_KEY_EVENT); - out_uint8(s, 0); /* down flag */ - out_uint8s(s, 2); - out_uint32_be(s, 65507); /* left control */ - s_mark_end(s); - lib_send_copy(v, s); - } - } - - init_stream(s, 8192); - out_uint8(s, RFB_C2S_KEY_EVENT); - out_uint8(s, msg == 15); /* down flag */ - out_uint8s(s, 2); - out_uint32_be(s, key); - s_mark_end(s); - error = lib_send_copy(v, s); - - if (key == 65507) /* left control */ - { - v->shift_state = msg == 15; - } - } + error = process_keysym_msg(v, param2, (msg == 15)); } /* mouse events * @@ -613,7 +661,6 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2, error = lib_send_copy(v, s); } } - free_stream(s); return error; } diff --git a/vnc/vnc.h b/vnc/vnc.h index 39a19f22..85e943f7 100644 --- a/vnc/vnc.h +++ b/vnc/vnc.h @@ -170,6 +170,7 @@ struct vnc char port[256]; int sck_closed; int shift_state; /* 0 up, 1 down */ + int ignore_next_numlock; /* Used in pause key processing */ int keylayout; int clip_chanid; struct vnc_clipboard_data *vc; diff --git a/xrdp/lang.c b/xrdp/lang.c index 4ef23e56..6a3f8acc 100644 --- a/xrdp/lang.c +++ b/xrdp/lang.c @@ -159,6 +159,11 @@ key_to_scancode_index(const char *key) keyboard_flags |= KBDFLAGS_EXTENDED; key += 3; } + else if (key[1] == '1') + { + keyboard_flags |= KBDFLAGS_EXTENDED1; + key += 3; + } } if (isxdigit(key[0]) && isxdigit(key[1]) && key[2] == '\0')