From c91ef80ca97ef12bd700be1d06079015d4aa84f1 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:57:13 +0100 Subject: [PATCH] Implement scancode indexing The mapping from scancodes to the indexes used in xrdp_keymap is not well designed and contains an implicit dependency on keycode values. This mapping is alse slightly different from the index used for the 'keys' map in the xrdp_wm structure. This commit introduces support for mapping scancodes directly to 'scancode indexes' suitable for indexing into both structures. Some renaming is also done; [MS-RDPBCGR] uses the terms scancode and keyCode interchangeably. An effort is made to use key_code for a raw value from a TS_KEYBOARD_EVENT, and scancode for a value which is produced by the scancode module. --- common/scancode.c | 50 ++++++++++++- common/scancode.h | 94 +++++++++++++++++++++--- common/xrdp_constants.h | 3 - genkeymap/genkeymap.c | 2 +- tests/common/test_scancode.c | 8 +-- xrdp/lang.c | 134 +++++++++++++++++++---------------- xrdp/xrdp.h | 14 ++-- xrdp/xrdp_bitmap.c | 2 +- xrdp/xrdp_types.h | 32 ++++----- xrdp/xrdp_wm.c | 91 ++++++++++++++++-------- xup/xup.c | 12 +--- 11 files changed, 298 insertions(+), 144 deletions(-) diff --git a/common/scancode.c b/common/scancode.c index c7225ba6..90f96db4 100644 --- a/common/scancode.c +++ b/common/scancode.c @@ -326,9 +326,48 @@ const struct map_settings global_settings[] = // Default mapping set is "evdev" const struct map_settings *settings = &global_settings[SI_EVDEV]; +/*****************************************************************************/ +int +scancode_to_index(unsigned short scancode) +{ + if (scancode <= 0x7f) + { + return scancode; + } + if (scancode <= 0xff) + { + // 0x80 - 0xff : Invalid code + return -1; + } + if (scancode <= 0x17f) + { + // 01x100 - 0x17f : Move bit 9 to bit 8 + return (scancode & 0x7f) | 0x80; + } + + return -1; +} + /*****************************************************************************/ unsigned short -scancode_to_keycode(unsigned short scancode) +scancode_from_index(int index) +{ + index &= 0xff; + unsigned short result; + if (index < 0x80) + { + result = index; + } + else + { + result = (index & 0x7f) | 0x100; + } + return result; +} + +/*****************************************************************************/ +unsigned short +scancode_to_x11_keycode(unsigned short scancode) { unsigned int min = 0; unsigned int max = settings->size; @@ -419,3 +458,12 @@ scancode_get_keycode_set(void) { return settings->name; } + +/*****************************************************************************/ +const char * +scancode_get_xkb_rules(void) +{ + // Currently supported keycods map directly to the same name for + // the rules which use them. + return settings->name; +} diff --git a/common/scancode.h b/common/scancode.h index 6c76f086..b13c40cd 100644 --- a/common/scancode.h +++ b/common/scancode.h @@ -18,13 +18,32 @@ * @file common/scancode.h * @brief Scancode handling * - * Convert between RDP scancodes and X11 keycodes. + * This module provides functionality for the following:- + * 1) Mapping from TS_KEYBOARD_EVENT PDU values to an 'RDP scancode' + * 2) Handling RDP scancodes + * 3) Convert between RDP scancodes and X11 keycodes. * - * RDP scancodes are largely the same as Windows scancodes. These are - * indirectly documented in the Microsoft "Keyboard Scan Code Specification", - * Rev 1.3a (March 16th 2000) and are otherwise known as "Scan code set - * 1" scancodes. This document no longer appears to be available directly from - * the Microsoft website. + * The values received in TS_KEYBOARD_EVENT PDUs are largely the same as + * Windows scancodes. These are indirectly documented in the Microsoft + * "Keyboard Scan Code Specification", Rev 1.3a (March 16th 2000) and + * are otherwise known as "Scan code set 1" scancodes. This document no + * longer appears to be available directly from the Microsoft website. + * + * A TS_KEYBOARD_EVENT_PDU contains two important values:- + * 1) key_code This is not unique. For example, left-shift and + * right-shift share a key_code of 0x2a + * 2) keyboard_flags Among other flags, contains KBDFLAGS_EXTENDED and + * KBDFLAGS_EXTENDED1. These combine with the key_code + * to allow a specific key to be determined. + * + * An 'RDP scancode' as defined by this module is a mapping of the + * Windows key_code and keyboard_flags into a single value which + * represents a unique key. For example:- + * Left control : key_code=0x1d, KBDFLAGS_EXTENDED=0 scancode = 0x1d + * Right control : key_code=0x1d, KBDFLAGS_EXTENDED=1 scancode = 0x11d + * + * This model of unique keys more closely maps what X11 does with its + * own keycodes. * * X11 keycodes are the X11 equivalent of RDP scancodes. In general, these * are specific to an X server. In practice however, these are nowadays @@ -39,15 +58,63 @@ #if !defined(SCANCODE_H) #define SCANCODE_H +enum +{ + /** + * Maximum value returned by scancode_to_index() + */ + SCANCODE_MAX_INDEX = 255 +}; + +// 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)) + +// Convert a scancode used by this module back into a +// TS_KEYBOARD_EVENT keyCode value +#define SCANCODE_TO_KBD_EVENT_KEY_CODE(scancode) ((scancode) & 0x7f) + +// 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) + /** - * Looks up an RDP scancode + * Convert a scancode to an index + * @param scancode scancode in the range 0x00 - 0x1ff + * @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, + * independent of the currently loaded keymap + * + * For scancodes in the range 0x00 - 0x7f, the index is identical to the + * scancode. This includes scancodes for all the keys affected by + * numlock. + */ +int +scancode_to_index(unsigned short scancode); + +/** + * Convert an index back to a scancode. + * @param index in the range 0..SCANCODE_MAX_INDEX + * + * @result scancode which is mapped to the index value + * + * The result is always a valid scancode, even if the index is + * not valid. + */ +unsigned short +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). * @return keycode, or 0 for no keycode */ unsigned short -scancode_to_keycode(unsigned short scancode); +scancode_to_x11_keycode(unsigned short scancode); /** * Gets the next valid scancode from the list of valid scancodes @@ -84,4 +151,13 @@ scancode_set_keycode_set(const char *kk_set); const char * scancode_get_keycode_set(void); +/** + * Gets the XKB rules set which can be used to access the currently + * loaded keycode set + * + * @result "evdev", or "base" + */ +const char * +scancode_get_xkb_rules(void); + #endif /* SCANCODE_H */ diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h index 9cefbcbc..e1720178 100644 --- a/common/xrdp_constants.h +++ b/common/xrdp_constants.h @@ -63,9 +63,6 @@ #define XRDP_MAX_BITMAP_CACHE_IDX 2000 #define XRDP_BITMAP_CACHE_ENTRIES 2048 -#define XR_MIN_KEY_CODE 8 -#define XR_MAX_KEY_CODE 256 - /* * Constants come from ITU-T Recommendations */ diff --git a/genkeymap/genkeymap.c b/genkeymap/genkeymap.c index 53b447db..e4a06290 100644 --- a/genkeymap/genkeymap.c +++ b/genkeymap/genkeymap.c @@ -279,7 +279,7 @@ output_file_section(FILE *outf, continue; } - e.keycode = scancode_to_keycode(scancode); + e.keycode = scancode_to_x11_keycode(scancode); nbytes = XLookupString(&e, text, 255, &ks, NULL); if (ks == NoSymbol) { diff --git a/tests/common/test_scancode.c b/tests/common/test_scancode.c index 4e328353..bdc40b15 100644 --- a/tests/common/test_scancode.c +++ b/tests/common/test_scancode.c @@ -31,7 +31,7 @@ START_TEST(test_scancode__evdev_all_values_returned) iter = 0; while ((scancode = scancode_get_next(&iter)) != 0) { - unsigned short keycode = scancode_to_keycode(scancode); + unsigned short keycode = scancode_to_x11_keycode(scancode); ck_assert_int_ne(keycode, 0); } } @@ -57,7 +57,7 @@ START_TEST(test_scancode__evdev_bad_values_mapped_to_0) { if (!valid[scancode]) { - ck_assert_int_eq(scancode_to_keycode(scancode), 0); + ck_assert_int_eq(scancode_to_x11_keycode(scancode), 0); } } } @@ -74,7 +74,7 @@ START_TEST(test_scancode__base_all_values_returned) iter = 0; while ((scancode = scancode_get_next(&iter)) != 0) { - unsigned short keycode = scancode_to_keycode(scancode); + unsigned short keycode = scancode_to_x11_keycode(scancode); ck_assert_int_ne(keycode, 0); } } @@ -100,7 +100,7 @@ START_TEST(test_scancode__base_bad_values_mapped_to_0) { if (!valid[scancode]) { - ck_assert_int_eq(scancode_to_keycode(scancode), 0); + ck_assert_int_eq(scancode_to_x11_keycode(scancode), 0); } } } diff --git a/xrdp/lang.c b/xrdp/lang.c index 933b9873..ca6c1bdb 100644 --- a/xrdp/lang.c +++ b/xrdp/lang.c @@ -39,58 +39,64 @@ /*****************************************************************************/ struct xrdp_key_info * -get_key_info_from_scan_code(int device_flags, int scan_code, int *keys, +get_key_info_from_kbd_event(int keyboard_flags, int key_code, int *keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap *keymap) { struct xrdp_key_info *rv; int shift; + int altgr_scancode; int altgr; - int ext; int index; - ext = device_flags & KBD_FLAG_EXT; /* 0x0100 */ shift = keys[42] || keys[54]; - altgr = keys[56] & KBD_FLAG_EXT; /* right alt */ + altgr_scancode = SCANCODE_FROM_KBD_EVENT(56, KBD_FLAG_EXT); + altgr = keys[scancode_to_index(altgr_scancode)]; /* right alt */ rv = 0; - index = INDEX_FROM_SCANCODE(scan_code, ext); - if (num_lock && - index >= XR_RDP_SCAN_MIN_NUMLOCK && index <= XR_RDP_SCAN_MAX_NUMLOCK) + index = scancode_to_index(SCANCODE_FROM_KBD_EVENT(key_code, keyboard_flags)); + if (index >= 0) { - rv = &(keymap->keys_numlock[index - XR_RDP_SCAN_MIN_NUMLOCK]); - } - else if (shift && caps_lock && altgr) - { - rv = &(keymap->keys_shiftcapslockaltgr[index]); - } - else if (shift && caps_lock) - { - rv = &(keymap->keys_shiftcapslock[index]); - } - else if (shift && altgr) - { - rv = &(keymap->keys_shiftaltgr[index]); - } - else if (shift) - { - rv = &(keymap->keys_shift[index]); - } - else if (caps_lock && altgr) - { - rv = &(keymap->keys_capslockaltgr[index]); - } - else if (caps_lock) - { - rv = &(keymap->keys_capslock[index]); - } - else if (altgr) - { - rv = &(keymap->keys_altgr[index]); - } - else - { - rv = &(keymap->keys_noshift[index]); + // scancode_to_index() guarantees to map numlock scancodes + // to the same index values. + if (num_lock && + index >= XR_RDP_SCAN_MIN_NUMLOCK && + index <= XR_RDP_SCAN_MAX_NUMLOCK) + { + rv = &(keymap->keys_numlock[index - XR_RDP_SCAN_MIN_NUMLOCK]); + } + else if (shift && caps_lock && altgr) + { + rv = &(keymap->keys_shiftcapslockaltgr[index]); + } + else if (shift && caps_lock) + { + rv = &(keymap->keys_shiftcapslock[index]); + } + else if (shift && altgr) + { + rv = &(keymap->keys_shiftaltgr[index]); + } + else if (shift) + { + rv = &(keymap->keys_shift[index]); + } + else if (caps_lock && altgr) + { + rv = &(keymap->keys_capslockaltgr[index]); + } + else if (caps_lock) + { + rv = &(keymap->keys_capslock[index]); + } + else if (altgr) + { + rv = &(keymap->keys_altgr[index]); + } + else + { + rv = &(keymap->keys_noshift[index]); + } } return rv; @@ -98,13 +104,13 @@ get_key_info_from_scan_code(int device_flags, int scan_code, int *keys, /*****************************************************************************/ int -get_keysym_from_scan_code(int device_flags, int scan_code, int *keys, +get_keysym_from_kbd_event(int keyboard_flags, int key_code, int *keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap *keymap) { struct xrdp_key_info *ki; - ki = get_key_info_from_scan_code(device_flags, scan_code, keys, + ki = get_key_info_from_kbd_event(keyboard_flags, key_code, keys, caps_lock, num_lock, scroll_lock, keymap); @@ -118,13 +124,13 @@ get_keysym_from_scan_code(int device_flags, int scan_code, int *keys, /*****************************************************************************/ char32_t -get_char_from_scan_code(int device_flags, int scan_code, int *keys, +get_char_from_kbd_event(int keyboard_flags, int key_code, int *keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap *keymap) { struct xrdp_key_info *ki; - ki = get_key_info_from_scan_code(device_flags, scan_code, keys, + ki = get_key_info_from_kbd_event(keyboard_flags, key_code, keys, caps_lock, num_lock, scroll_lock, keymap); @@ -138,28 +144,29 @@ get_char_from_scan_code(int device_flags, int scan_code, int *keys, /*****************************************************************************/ /** - * Tests a table key to see if it's a valid scancode + * Converts a table key to a scancode index value * * @param key Table key - * @param[out] scancode scancode index value (0..255) if 1 is returned - * @return Boolean != 0 if the key is valid + * @return index >= 0, or < 0 for an invalid key */ static int -is_valid_scancode(const char *key, int *scancode) +key_to_scancode_index(const char *key) { - int rv = 0; - int extended = 0; - if ((key[0] == 'E' || key[0] == 'e') && key[1] == '0' && key[2] == '_') + int rv = -1; + int keyboard_flags = 0; + if ((key[0] == 'E' || key[0] == 'e') && key[2] == '_') { - extended = 1; - key += 3; + if (key[1] == '0') + { + keyboard_flags |= KBD_FLAG_EXT; + key += 3; + } } if (isxdigit(key[0]) && isxdigit(key[1]) && key[2] == '\0') { - rv = 1; - *scancode = XDIGIT_TO_VAL(key[0]) * 16 + XDIGIT_TO_VAL(key[1]); - *scancode = INDEX_FROM_SCANCODE(*scancode, extended); + int code = XDIGIT_TO_VAL(key[0]) * 16 + XDIGIT_TO_VAL(key[1]); + rv = scancode_to_index(SCANCODE_FROM_KBD_EVENT(code, keyboard_flags)); } return rv; } @@ -248,13 +255,14 @@ km_read_section(toml_table_t *tfile, const char *section_name, { const char *key; toml_datum_t val; - int index; - int scancode; // index value 0..255 + int i; char *p; const char *unicode_str; - for (index = 0 ; (key = toml_key_in(section, index)) != NULL; ++index) + for (i = 0 ; (key = toml_key_in(section, i)) != NULL; ++i) { - if (!is_valid_scancode(key, &scancode)) + // Get a scancode index from the key if possible + int sindex = key_to_scancode_index(key); + if (sindex < 0) { LOG(LOG_LEVEL_WARNING, "Can't parse value '%s' in [%s] in keymap file", @@ -283,7 +291,7 @@ km_read_section(toml_table_t *tfile, const char *section_name, /* Parse both values and add them to the keymap, logging any * errors */ - if (!is_valid_keysym(val.u.s, &keymap[scancode].sym)) + if (!is_valid_keysym(val.u.s, &keymap[sindex].sym)) { LOG(LOG_LEVEL_WARNING, "Can't read KeySym for [%s]:%s in keymap file", @@ -291,7 +299,7 @@ km_read_section(toml_table_t *tfile, const char *section_name, } if (unicode_str != NULL && - !is_valid_unicode_char(unicode_str, &keymap[scancode].chr)) + !is_valid_unicode_char(unicode_str, &keymap[sindex].chr)) { LOG(LOG_LEVEL_WARNING, "Can't read unicode character for [%s]:%s in keymap file", @@ -385,7 +393,7 @@ km_load_file(const char *filename, struct xrdp_keymap *keymap) /* The numlock map is much smaller and offset by * XR_RDP_SCAN_MAX_NUMLOCK. Read the section into a temporary * area and copy it over */ - struct xrdp_key_info keys_numlock[256]; + struct xrdp_key_info keys_numlock[SCANCODE_MAX_INDEX + 1]; int i; for (i = XR_RDP_SCAN_MIN_NUMLOCK; i <= XR_RDP_SCAN_MAX_NUMLOCK; ++i) { diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 84e27295..8ae54b9a 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -147,8 +147,14 @@ int xrdp_wm_mouse_touch(struct xrdp_wm *self, int gesture, int param); int xrdp_wm_mouse_click(struct xrdp_wm *self, int x, int y, int but, int down); +/** + * Handle a TS_KEYBOARD_EVENT ([MS-RDPBCGR] 2.2.8.1.1.3.1.1.1) + * + * @param device_flags keyboardFlags value from PDU + * @param key_code keyCode value from PDU + */ int -xrdp_wm_key(struct xrdp_wm *self, int device_flags, int scan_code); +xrdp_wm_key(struct xrdp_wm *self, int keyboard_flags, int key_code); int xrdp_wm_key_sync(struct xrdp_wm *self, int device_flags, int key_flags); int @@ -424,15 +430,15 @@ set_string(char **in_str, const char *in); /* in lang.c */ struct xrdp_key_info * -get_key_info_from_scan_code(int device_flags, int scan_code, int *keys, +get_key_info_from_kbd_event(int keyboard_flags, int key_code, int *keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap *keymap); int -get_keysym_from_scan_code(int device_flags, int scan_code, int *keys, +get_keysym_from_kbd_event(int keyboard_flags, int key_code, int *keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap *keymap); char32_t -get_char_from_scan_code(int device_flags, int scan_code, int *keys, +get_char_from_kbd_event(int keyboard_flags, int key_code, int *keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap *keymap); int diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c index 572464ce..cf397f4d 100644 --- a/xrdp/xrdp_bitmap.c +++ b/xrdp/xrdp_bitmap.c @@ -1226,7 +1226,7 @@ xrdp_bitmap_def_proc(struct xrdp_bitmap *self, int msg, } else { - char32_t c = get_char_from_scan_code + char32_t c = get_char_from_kbd_event (param2, scan_code, self->wm->keys, self->wm->caps_lock, self->wm->num_lock, self->wm->scroll_lock, &(self->wm->keymap)); diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 6ffa0fce..a13b09bd 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -28,6 +28,7 @@ #include "xrdp_constants.h" #include "fifo.h" #include "guid.h" +#include "scancode.h" #include "xrdp_client_info.h" #define MAX_NR_CHANNELS 16 @@ -452,25 +453,17 @@ struct xrdp_key_info char32_t chr; }; -/** - * Keyboard description - * - * Each section maps an RDP scancode to a KeySym and a Unicode - * character. - */ -#define INDEX_FROM_SCANCODE(scancode,extended) \ - (((scancode) & 0x7f) | ((extended) ? 0x80 : 0)) - struct xrdp_keymap { - struct xrdp_key_info keys_noshift[256]; - struct xrdp_key_info keys_shift[256]; - struct xrdp_key_info keys_altgr[256]; - struct xrdp_key_info keys_shiftaltgr[256]; - struct xrdp_key_info keys_capslock[256]; - struct xrdp_key_info keys_capslockaltgr[256]; - struct xrdp_key_info keys_shiftcapslock[256]; - struct xrdp_key_info keys_shiftcapslockaltgr[256]; + // These arrays are indexed by a return from scancode_to_index() + struct xrdp_key_info keys_noshift[SCANCODE_MAX_INDEX + 1]; + struct xrdp_key_info keys_shift[SCANCODE_MAX_INDEX + 1]; + struct xrdp_key_info keys_altgr[SCANCODE_MAX_INDEX + 1]; + struct xrdp_key_info keys_shiftaltgr[SCANCODE_MAX_INDEX + 1]; + struct xrdp_key_info keys_capslock[SCANCODE_MAX_INDEX + 1]; + struct xrdp_key_info keys_capslockaltgr[SCANCODE_MAX_INDEX + 1]; + struct xrdp_key_info keys_shiftcapslock[SCANCODE_MAX_INDEX + 1]; + struct xrdp_key_info keys_shiftcapslockaltgr[SCANCODE_MAX_INDEX + 1]; // NumLock is restricted to a much smaller set of keys struct xrdp_key_info keys_numlock[XR_RDP_SCAN_MAX_NUMLOCK - XR_RDP_SCAN_MIN_NUMLOCK + 1]; @@ -554,11 +547,12 @@ struct xrdp_wm int current_pointer; int mouse_x; int mouse_y; - /* keyboard info */ - int keys[256]; /* key states 0 up 1 down*/ + /* keyboard info (indexed by a return from scancode_to_index()) */ + int keys[SCANCODE_MAX_INDEX + 1]; /* key states 0 up 1 down*/ int caps_lock; int scroll_lock; int num_lock; + /* Unicode input */ int last_high_surrogate_key_up; int last_high_surrogate_key_down; diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index 3038da3f..7ee5f086 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -1569,15 +1569,26 @@ xrdp_wm_mouse_click(struct xrdp_wm *self, int x, int y, int but, int down) /*****************************************************************************/ int -xrdp_wm_key(struct xrdp_wm *self, int device_flags, int scan_code) +xrdp_wm_key(struct xrdp_wm *self, int keyboard_flags, int key_code) { int msg; struct xrdp_key_info *ki; LOG_DEVEL(LOG_LEVEL_DEBUG, - "xrdp_wm_key: RDP scancode:0x%04x, flags: 0x%04x", - scan_code, device_flags); - scan_code = scan_code % 128; + "xrdp_wm_key: RDP key_code:0x%04x, keyboard_flags: 0x%04x", + key_code, keyboard_flags); + int scancode = SCANCODE_FROM_KBD_EVENT(key_code, keyboard_flags); + int keyup = ((keyboard_flags & KBD_FLAG_UP) != 0); + + int sindex = scancode_to_index(scancode); + if (sindex < 0) + { + // The scancode doesn't map to an index, so we can't handle it here. + // Log this so we can investigate + LOG(LOG_LEVEL_WARNING, "Ignoring unusable scancode %x (%s)", + scancode, (keyup ? "up" : "down")); + return 0; + } if (self->popup_wnd != 0) { @@ -1585,24 +1596,17 @@ xrdp_wm_key(struct xrdp_wm *self, int device_flags, int scan_code) return 0; } - // workaround odd shift behavior - // see https://github.com/neutrinolabs/xrdp/issues/397 - if (scan_code == 42 && device_flags == (KBD_FLAG_UP | KBD_FLAG_EXT)) + if (keyup) { - return 0; - } - - if (device_flags & KBD_FLAG_UP) /* 0x8000 */ - { - self->keys[scan_code] = 0; + self->keys[sindex] = 0; msg = WM_KEYUP; } else /* key down */ { - self->keys[scan_code] = 1 | device_flags; + self->keys[sindex] = 1; msg = WM_KEYDOWN; - switch (scan_code) + switch (key_code) { case 58: self->caps_lock = !self->caps_lock; @@ -1618,24 +1622,28 @@ xrdp_wm_key(struct xrdp_wm *self, int device_flags, int scan_code) if (self->mm->mod != 0) { + // Backend module loaded... if (self->mm->mod->mod_event != 0) { - ki = get_key_info_from_scan_code - (device_flags, scan_code, self->keys, self->caps_lock, + // ..and able to take events. Check the scancode maps to + // a real key in the currently loaded keymap + ki = get_key_info_from_kbd_event + (keyboard_flags, key_code, self->keys, self->caps_lock, self->num_lock, self->scroll_lock, &(self->keymap)); if (ki != 0) { self->mm->mod->mod_event(self->mm->mod, msg, ki->chr, ki->sym, - scan_code, device_flags); + key_code, keyboard_flags); } } } else if (self->focused_window != 0) { + // Pass keypress on to a widget in the login window xrdp_bitmap_def_proc(self->focused_window, - msg, scan_code, device_flags); + msg, key_code, keyboard_flags); } return 0; @@ -1720,6 +1728,29 @@ get_unicode_character(struct xrdp_wm *self, int device_flags, char16_t c16) return c32; } +/*****************************************************************************/ +/** + * Takes a scancode index and fakes a keyboard event to represent it + * @param self module pointer + * @param device_flags default flags to pass in for the keyboard event. + * @param scancode index + * + * Some of the device_flags are overridden by the scancode derived from the + * scancode index + */ +static void +fake_kbd_event_from_scancode_index(struct xrdp_wm *self, int device_flags, + int index) +{ + int scancode = scancode_from_index(index); + int key_code = SCANCODE_TO_KBD_EVENT_KEY_CODE(scancode); + + device_flags &= ~(KBD_FLAG_EXT | KBD_FLAG_EXT1); + device_flags |= SCANCODE_TO_KBD_EVENT_KBD_FLAGS(scancode); + + xrdp_wm_key(self, device_flags, key_code); +} + /*****************************************************************************/ static int xrdp_wm_key_unicode(struct xrdp_wm *self, int device_flags, char32_t c16) @@ -1734,40 +1765,40 @@ xrdp_wm_key_unicode(struct xrdp_wm *self, int device_flags, char32_t c16) // See if we can find the character in the existing keymap, // and if so, generate normal key event(s) for it - for (index = XR_MIN_KEY_CODE; index < XR_MAX_KEY_CODE; index++) + for (index = 0; index <= SCANCODE_MAX_INDEX; ++index) { if (c32 == self->keymap.keys_noshift[index].chr) { - xrdp_wm_key(self, device_flags, index - XR_MIN_KEY_CODE); + fake_kbd_event_from_scancode_index(self, device_flags, index); return 0; } } - for (index = XR_MIN_KEY_CODE; index < XR_MAX_KEY_CODE; index++) + for (index = 0; index <= SCANCODE_MAX_INDEX; ++index) { if (c32 == self->keymap.keys_shift[index].chr) { if (device_flags & KBD_FLAG_UP) { - xrdp_wm_key(self, device_flags, index - XR_MIN_KEY_CODE); + fake_kbd_event_from_scancode_index(self, device_flags, index); xrdp_wm_key(self, KBD_FLAG_UP, XR_RDP_SCAN_LSHIFT); } else { xrdp_wm_key(self, KBD_FLAG_DOWN, XR_RDP_SCAN_LSHIFT); - xrdp_wm_key(self, device_flags, index - XR_MIN_KEY_CODE); + fake_kbd_event_from_scancode_index(self, device_flags, index); } return 0; } } - for (index = XR_MIN_KEY_CODE; index < XR_MAX_KEY_CODE; index++) + for (index = 0; index <= SCANCODE_MAX_INDEX; ++index) { if (c32 == self->keymap.keys_altgr[index].chr) { if (device_flags & KBD_FLAG_UP) { - xrdp_wm_key(self, device_flags, index - XR_MIN_KEY_CODE); + fake_kbd_event_from_scancode_index(self, device_flags, index); xrdp_wm_key(self, KBD_FLAG_UP | KBD_FLAG_EXT, XR_RDP_SCAN_ALT); } @@ -1775,19 +1806,19 @@ xrdp_wm_key_unicode(struct xrdp_wm *self, int device_flags, char32_t c16) { xrdp_wm_key(self, KBD_FLAG_DOWN | KBD_FLAG_EXT, XR_RDP_SCAN_ALT); - xrdp_wm_key(self, device_flags, index - XR_MIN_KEY_CODE); + fake_kbd_event_from_scancode_index(self, device_flags, index); } return 0; } } - for (index = XR_MIN_KEY_CODE; index < XR_MAX_KEY_CODE; index++) + for (index = 0; index <= SCANCODE_MAX_INDEX; ++index) { if (c32 == self->keymap.keys_shiftaltgr[index].chr) { if (device_flags & KBD_FLAG_UP) { - xrdp_wm_key(self, device_flags, index - XR_MIN_KEY_CODE); + fake_kbd_event_from_scancode_index(self, device_flags, index); xrdp_wm_key(self, KBD_FLAG_UP | KBD_FLAG_EXT, XR_RDP_SCAN_ALT); xrdp_wm_key(self, KBD_FLAG_UP, XR_RDP_SCAN_LSHIFT); } @@ -1796,7 +1827,7 @@ xrdp_wm_key_unicode(struct xrdp_wm *self, int device_flags, char32_t c16) xrdp_wm_key(self, KBD_FLAG_DOWN, XR_RDP_SCAN_LSHIFT); xrdp_wm_key(self, KBD_FLAG_DOWN | KBD_FLAG_EXT, XR_RDP_SCAN_ALT); - xrdp_wm_key(self, device_flags, index - XR_MIN_KEY_CODE); + fake_kbd_event_from_scancode_index(self, device_flags, index); } return 0; } diff --git a/xup/xup.c b/xup/xup.c index 8bada6ba..317ddeaf 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -266,6 +266,7 @@ lib_mod_event(struct mod *mod, int msg, tbus param1, tbus param2, int len; int key; int rv; + int scancode; LOG_DEVEL(LOG_LEVEL_TRACE, "in lib_mod_event"); make_stream(s); @@ -311,15 +312,8 @@ lib_mod_event(struct mod *mod, int msg, tbus param1, tbus param2, /* xup doesn't need the Unicode character mapping in param1. Send * the X11 scancode instead, so xorgxrdp doesn't have to do this * work again */ - if ((param4 & KBD_FLAG_EXT) != 0) - { - // Extended key - set bit 9 of the scancode for the lookup - param1 = scancode_to_keycode(param3 | 0x100); - } - else - { - param1 = scancode_to_keycode(param3); - } + scancode = SCANCODE_FROM_KBD_EVENT(param3, param4); + param1 = scancode_to_x11_keycode(scancode); } init_stream(s, 8192);