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.
This commit is contained in:
matt335672 2024-06-19 21:40:36 +01:00
parent 5779edd23f
commit 7fe5b3ea34
8 changed files with 149 additions and 50 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -5,6 +5,8 @@ AM_CPPFLAGS = \
-DXRDP_PID_PATH=\"${localstatedir}/run\" \
-I$(top_srcdir)/common
AM_CFLAGS = $(X_CFLAGS)
module_LTLIBRARIES = \
libvnc.la

115
vnc/vnc.c
View File

@ -30,6 +30,8 @@
#include <config_ac.h>
#endif
#include <X11/keysym.h>
#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;
}

View File

@ -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;

View File

@ -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')