From 7fe5b3ea34f077d4a6516461b62798bd519690c9 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:40:36 +0100 Subject: [PATCH] Move pause key processing from xorgxrdp This commit moves processing of the pause key from xorgxrdp back to xrdp itself, so that the key can be passed to the VNC backend. --- common/scancode.c | 27 ++++++-- common/scancode.h | 16 +++-- genkeymap/genkeymap.c | 6 +- tests/common/test_scancode.c | 27 ++++++-- vnc/Makefile.am | 2 + vnc/vnc.c | 115 ++++++++++++++++++++++++----------- vnc/vnc.h | 1 + xrdp/lang.c | 5 ++ 8 files changed, 149 insertions(+), 50 deletions(-) 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')