Update xrdp to use new keymap file format
This commit is contained in:
parent
7301b505c9
commit
1cb2ce06cd
@ -42,11 +42,7 @@ test_xrdp_LDADD = \
|
||||
$(top_builddir)/xrdp/xrdp_bitmap_load.o \
|
||||
$(top_builddir)/xrdp/xrdp_bitmap_common.o \
|
||||
$(top_builddir)/xrdp/funcs.o \
|
||||
$(top_builddir)/common/libcommon.la \
|
||||
$(top_builddir)/libipm/libipm.la \
|
||||
$(top_builddir)/libxrdp/libxrdp.la \
|
||||
$(top_builddir)/libpainter/src/libpainter.la \
|
||||
$(top_builddir)/librfxcodec/src/librfxencode.la \
|
||||
$(top_builddir)/xrdp/lang.o \
|
||||
$(top_builddir)/xrdp/xrdp_mm.o \
|
||||
$(top_builddir)/xrdp/xrdp_wm.o \
|
||||
@ -61,6 +57,11 @@ test_xrdp_LDADD = \
|
||||
$(top_builddir)/xrdp/xrdp_process.o \
|
||||
$(top_builddir)/xrdp/xrdp_login_wnd.o \
|
||||
$(top_builddir)/xrdp/xrdp_main_utils.o \
|
||||
$(top_builddir)/libpainter/src/libpainter.la \
|
||||
$(top_builddir)/librfxcodec/src/librfxencode.la \
|
||||
$(top_builddir)/libipm/libipm.la \
|
||||
$(top_builddir)/common/libcommon.la \
|
||||
$(top_builddir)/third_party/tomlc99/libtoml.la \
|
||||
$(PIXMAN_LIBS) \
|
||||
$(IMLIB2_LIBS) \
|
||||
@CHECK_LIBS@ \
|
||||
|
380
xrdp/lang.c
380
xrdp/lang.c
@ -23,47 +23,19 @@
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "xrdp.h"
|
||||
#include "ms-rdpbcgr.h"
|
||||
#include "log.h"
|
||||
#include "string_calls.h"
|
||||
#include "toml.h"
|
||||
|
||||
/* map for rdp to x11 scancodes
|
||||
code1 is regular scancode, code2 is extended scancode */
|
||||
struct codepair
|
||||
{
|
||||
tui8 code1;
|
||||
tui8 code2;
|
||||
};
|
||||
static struct codepair g_map[] =
|
||||
{
|
||||
{ 0, 0 }, { 9, 0 }, { 10, 0 }, { 11, 0 }, { 12, 0 }, /* 0 - 4 */
|
||||
{ 13, 0 }, { 14, 0 }, { 15, 0 }, { 16, 0 }, { 17, 0 }, /* 5 - 9 */
|
||||
{ 18, 0 }, { 19, 0 }, { 20, 0 }, { 21, 0 }, { 22, 0 }, /* 10 - 14 */
|
||||
{ 23, 0 }, { 24, 173 }, { 25, 0 }, { 26, 0 }, { 27, 0 }, /* 15 - 19 */
|
||||
{ 28, 0 }, { 29, 0 }, { 30, 0 }, { 31, 0 }, { 32, 0 }, /* 20 - 24 */
|
||||
{ 33, 171 }, { 34, 0 }, { 35, 0 }, { 36, 108 }, { 37, 109 }, /* 25 - 29 */
|
||||
{ 38, 0 }, { 39, 0 }, { 40, 121 }, { 41, 0 }, { 42, 172 }, /* 30 - 34 */
|
||||
{ 43, 0 }, { 44, 174 }, { 45, 0 }, { 46, 0 }, { 47, 0 }, /* 35 - 39 */
|
||||
{ 48, 0 }, { 49, 0 }, { 50, 0 }, { 51, 0 }, { 52, 0 }, /* 40 - 44 */
|
||||
{ 53, 0 }, { 54, 122 }, { 55, 0 }, { 56, 123 }, { 57, 0 }, /* 45 - 49 */
|
||||
{ 58, 180 }, { 59, 0 }, { 60, 0 }, { 61, 112 }, { 62, 0 }, /* 50 - 54 */
|
||||
{ 63, 111 }, { 64, 113 }, { 65, 0 }, { 66, 0 }, { 67, 0 }, /* 55 - 59 */
|
||||
{ 68, 0 }, { 69, 0 }, { 70, 0 }, { 71, 0 }, { 72, 0 }, /* 60 - 64 */
|
||||
{ 73, 0 }, { 74, 0 }, { 75, 0 }, { 76, 0 }, { 77, 0 }, /* 65 - 69 */
|
||||
{ 78, 0 }, { 79, 97 }, { 80, 98 }, { 81, 99 }, { 82, 0 }, /* 70 - 74 */
|
||||
{ 83, 100 }, { 84, 0 }, { 85, 102 }, { 86, 0 }, { 87, 103 }, /* 75 - 79 */
|
||||
{ 88, 104 }, { 89, 105 }, { 90, 106 }, { 91, 107 }, { 92, 0 }, /* 80 - 84 */
|
||||
{ 93, 0 }, { 94, 0 }, { 95, 0 }, { 96, 0 }, { 97, 0 }, /* 85 - 89 */
|
||||
{ 98, 0 }, { 0, 115 }, { 0, 116 }, { 0, 117 }, { 102, 0 }, /* 90 - 94 */
|
||||
{ 103, 0 }, { 104, 0 }, { 105, 0 }, { 106, 0 }, { 107, 0 }, /* 95 - 99 */
|
||||
{ 108, 0 }, { 109, 225 }, { 110, 164 }, { 111, 181 }, { 112, 136 }, /* 100 - 104 */
|
||||
{ 113, 167 }, { 114, 166 }, { 115, 0 }, { 116, 163 }, { 117, 234 }, /* 105 - 109 */
|
||||
{ 118, 156 }, { 119, 157 }, { 120, 0 }, { 121, 0 }, { 122, 0 }, /* 110 - 114 */
|
||||
{ 123, 0 }, { 124, 0 }, { 125, 0 }, { 126, 0 }, { 127, 0 }, /* 115 - 119 */
|
||||
{ 128, 0 }, { 129, 0 }, { 130, 0 }, { 131, 0 }, { 132, 0 }, /* 120 - 124 */
|
||||
{ 133, 0 }, { 134, 0 }, { 135, 0 } /* 125 - 127 */
|
||||
};
|
||||
// Macro to return 0..15 for a valid isxdigit() character
|
||||
#define XDIGIT_TO_VAL(d) (\
|
||||
isdigit(d) ? (d) - '0' : \
|
||||
((d) >= 'a' && (d) <= 'f') ? (d) - 'a' + 10 : \
|
||||
(d) - 'A' + 10)
|
||||
|
||||
/*****************************************************************************/
|
||||
struct xrdp_key_info *
|
||||
@ -81,20 +53,12 @@ get_key_info_from_scan_code(int device_flags, int scan_code, int *keys,
|
||||
shift = keys[42] || keys[54];
|
||||
altgr = keys[56] & KBD_FLAG_EXT; /* right alt */
|
||||
rv = 0;
|
||||
scan_code = scan_code & 0x7f;
|
||||
index = ext ? g_map[scan_code].code2 : g_map[scan_code].code1;
|
||||
index = INDEX_FROM_SCANCODE(scan_code, ext);
|
||||
|
||||
/* keymap file is created with numlock off so we have to do this */
|
||||
if ((index >= 79) && (index <= 91))
|
||||
if (num_lock &&
|
||||
index >= XR_RDP_SCAN_MIN_NUMLOCK && index <= XR_RDP_SCAN_MAX_NUMLOCK)
|
||||
{
|
||||
if (num_lock)
|
||||
{
|
||||
rv = &(keymap->keys_shift[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = &(keymap->keys_noshift[index]);
|
||||
}
|
||||
rv = &(keymap->keys_numlock[index - XR_RDP_SCAN_MIN_NUMLOCK]);
|
||||
}
|
||||
else if (shift && caps_lock && altgr)
|
||||
{
|
||||
@ -173,58 +137,169 @@ 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
|
||||
*
|
||||
* @param key Table key
|
||||
* @param[out] scancode scancode index value (0..255) if 1 is returned
|
||||
* @return Boolean != 0 if the key is valid
|
||||
*/
|
||||
static int
|
||||
km_read_section(int fd, const char *section_name, struct xrdp_key_info *keymap)
|
||||
is_valid_scancode(const char *key, int *scancode)
|
||||
{
|
||||
struct list *names;
|
||||
struct list *values;
|
||||
int index;
|
||||
int code;
|
||||
int pos1;
|
||||
char *name;
|
||||
char *value;
|
||||
|
||||
names = list_create();
|
||||
names->auto_free = 1;
|
||||
values = list_create();
|
||||
values->auto_free = 1;
|
||||
|
||||
g_memset(keymap, '\0', sizeof(*keymap));
|
||||
if (file_read_section(fd, section_name, names, values) == 0)
|
||||
int rv = 0;
|
||||
int extended = 0;
|
||||
if ((key[0] == 'E' || key[0] == 'e') && key[1] == '0' && key[2] == '_')
|
||||
{
|
||||
for (index = names->count - 1; index >= 0; index--)
|
||||
extended = 1;
|
||||
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);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Tests a value to see if it's a valid KeySym (decimal number)
|
||||
*
|
||||
* @param val
|
||||
* @param[out] keysym. Keysym value if 1 is returned
|
||||
* @return Boolean != 0 if the string is valid
|
||||
*/
|
||||
static int
|
||||
is_valid_keysym(const char *val, int *sym)
|
||||
{
|
||||
int rv = 0;
|
||||
int s = 0;
|
||||
if (*val != '\0')
|
||||
{
|
||||
while (isdigit(*val))
|
||||
{
|
||||
name = (char *)list_get_item(names, index);
|
||||
value = (char *)list_get_item(values, index);
|
||||
|
||||
if ((name != 0) && (value != 0))
|
||||
{
|
||||
if (g_strncasecmp(name, "key", 3) == 0)
|
||||
{
|
||||
code = g_atoi(name + 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
code = g_atoi(name);
|
||||
}
|
||||
|
||||
if ((code >= 0) && (code < 256))
|
||||
{
|
||||
pos1 = g_pos(value, ":");
|
||||
|
||||
if (pos1 >= 0)
|
||||
{
|
||||
keymap[code].chr = g_atoi(value + pos1 + 1);
|
||||
}
|
||||
|
||||
keymap[code].sym = g_atoi(value);
|
||||
}
|
||||
}
|
||||
s = s * 10 + (*val++ - '0');
|
||||
}
|
||||
if (*val == '\0')
|
||||
{
|
||||
*sym = s;
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Tests a value to see if it's a valid unicode character (U+xxxx)
|
||||
*
|
||||
* @param val
|
||||
* @param[out] chr value if 1 is returned
|
||||
* @return Boolean != 0 if the string is valid
|
||||
*/
|
||||
static int
|
||||
is_valid_unicode_char(const char *val, char32_t *chr)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if ((val[0] == 'U' || val[0] == 'u') &&
|
||||
val[1] == '+' && isxdigit(val[2]))
|
||||
{
|
||||
val += 2; // Skip 'U+'
|
||||
const char *p = val;
|
||||
char32_t c = 0;
|
||||
|
||||
while (isxdigit(*p))
|
||||
{
|
||||
c = c * 16 + XDIGIT_TO_VAL(*p);
|
||||
++p;
|
||||
}
|
||||
|
||||
if (*p == '\0' && (p - val) >= 4 && (p - val) <= 6)
|
||||
{
|
||||
rv = 1;
|
||||
*chr = c;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
km_read_section(toml_table_t *tfile, const char *section_name,
|
||||
struct xrdp_key_info *keymap)
|
||||
{
|
||||
toml_table_t *section = toml_table_in(tfile, section_name);
|
||||
g_memset(keymap, '\0', sizeof(*keymap));
|
||||
|
||||
if (section == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Section [%s] not found in keymap file",
|
||||
section_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *key;
|
||||
toml_datum_t val;
|
||||
int index;
|
||||
int scancode; // index value 0..255
|
||||
char *p;
|
||||
const char *unicode_str;
|
||||
for (index = 0 ; (key = toml_key_in(section, index)) != NULL; ++index)
|
||||
{
|
||||
if (!is_valid_scancode(key, &scancode))
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Can't parse value '%s' in [%s] in keymap file",
|
||||
key, section_name);
|
||||
continue;
|
||||
}
|
||||
val = toml_string_in(section, key);
|
||||
if (!val.ok)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Can't read value for [%s]:%s in keymap file",
|
||||
section_name, key);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Does the value contain a unicode character?
|
||||
if ((p = strchr(val.u.s, ':')) != NULL)
|
||||
{
|
||||
unicode_str = (p + 1);
|
||||
*p = '\0'; // val is a copy, writeable by us
|
||||
}
|
||||
else
|
||||
{
|
||||
unicode_str = NULL;
|
||||
}
|
||||
|
||||
/* Parse both values and add them to the keymap, logging any
|
||||
* errors */
|
||||
if (!is_valid_keysym(val.u.s, &keymap[scancode].sym))
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Can't read KeySym for [%s]:%s in keymap file",
|
||||
section_name, key);
|
||||
}
|
||||
|
||||
if (unicode_str != NULL &&
|
||||
!is_valid_unicode_char(unicode_str, &keymap[scancode].chr))
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Can't read unicode character for [%s]:%s in keymap file",
|
||||
section_name, key);
|
||||
}
|
||||
|
||||
free(val.u.s);
|
||||
}
|
||||
}
|
||||
|
||||
list_delete(names);
|
||||
list_delete(values);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -233,83 +308,88 @@ int
|
||||
get_keymaps(int keylayout, struct xrdp_keymap *keymap)
|
||||
{
|
||||
int basic_key_layout = keylayout & 0x0000ffff;
|
||||
char *filename;
|
||||
struct xrdp_keymap *lkeymap;
|
||||
char filename[256];
|
||||
int layout_list[10];
|
||||
int layout_count = 0;
|
||||
int i;
|
||||
|
||||
filename = (char *)g_malloc(256, 0);
|
||||
|
||||
/* check if there is a keymap file e.g. km-e00100411.ini */
|
||||
g_snprintf(filename, 255, "%s/km-%08x.ini", XRDP_CFG_PATH, keylayout);
|
||||
|
||||
/* if the file does not exist, use only lower 16 bits instead */
|
||||
if (!g_file_exist(filename))
|
||||
/* Work out a list of layouts to try to load */
|
||||
layout_list[layout_count++] = keylayout; // Requested layout
|
||||
if (basic_key_layout != keylayout)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Cannot find keymap file %s", filename);
|
||||
/* e.g. km-00000411.ini */
|
||||
g_snprintf(filename, 255, "%s/km-%08x.ini", XRDP_CFG_PATH, basic_key_layout);
|
||||
layout_list[layout_count++] = basic_key_layout; // First fallback
|
||||
}
|
||||
layout_list[layout_count++] = 0x0409; // Last chance 'en-US'
|
||||
|
||||
/* finally, use 'en-us' */
|
||||
if (!g_file_exist(filename))
|
||||
/* search for a loadable layout in the list */
|
||||
for (i = 0; i < layout_count; ++i)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Cannot find keymap file %s", filename);
|
||||
g_snprintf(filename, 255, "%s/km-00000409.ini", XRDP_CFG_PATH);
|
||||
}
|
||||
// Convert key layout to a filename
|
||||
g_snprintf(filename, sizeof(filename),
|
||||
XRDP_CFG_PATH "/km-%08x.toml", layout_list[i]);
|
||||
|
||||
if (g_file_exist(filename))
|
||||
{
|
||||
|
||||
lkeymap = (struct xrdp_keymap *)g_malloc(sizeof(struct xrdp_keymap), 0);
|
||||
/* make a copy of the built-in keymap */
|
||||
g_memcpy(lkeymap, keymap, sizeof(struct xrdp_keymap));
|
||||
|
||||
km_load_file(filename, keymap);
|
||||
|
||||
if (g_memcmp(lkeymap, keymap, sizeof(struct xrdp_keymap)) != 0)
|
||||
if (km_load_file(filename, keymap) == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"local keymap file for 0x%08x found and doesn't match "
|
||||
"built in keymap, using local keymap file", keylayout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_free(lkeymap);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "File does not exist: %s", filename);
|
||||
}
|
||||
|
||||
g_free(filename);
|
||||
/* No luck finding anything */
|
||||
LOG(LOG_LEVEL_ERROR, "Cannot find a usable keymap file");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int km_load_file(const char *filename, struct xrdp_keymap *keymap)
|
||||
int
|
||||
km_load_file(const char *filename, struct xrdp_keymap *keymap)
|
||||
{
|
||||
int fd;
|
||||
FILE *fp;
|
||||
toml_table_t *tfile;
|
||||
char errbuf[200];
|
||||
int rv = 0;
|
||||
|
||||
LOG(LOG_LEVEL_INFO, "Loading keymap file %s", filename);
|
||||
fd = g_file_open_ro(filename);
|
||||
|
||||
if (fd != -1)
|
||||
if ((fp = fopen(filename, "r")) == NULL)
|
||||
{
|
||||
/* read the keymaps */
|
||||
km_read_section(fd, "noshift", keymap->keys_noshift);
|
||||
km_read_section(fd, "shift", keymap->keys_shift);
|
||||
km_read_section(fd, "altgr", keymap->keys_altgr);
|
||||
km_read_section(fd, "shiftaltgr", keymap->keys_shiftaltgr);
|
||||
km_read_section(fd, "capslock", keymap->keys_capslock);
|
||||
km_read_section(fd, "capslockaltgr", keymap->keys_capslockaltgr);
|
||||
km_read_section(fd, "shiftcapslock", keymap->keys_shiftcapslock);
|
||||
km_read_section(fd, "shiftcapslockaltgr", keymap->keys_shiftcapslockaltgr);
|
||||
|
||||
g_file_close(fd);
|
||||
LOG(LOG_LEVEL_ERROR, "Error loading keymap file %s (%s)",
|
||||
filename, g_get_strerror());
|
||||
rv = 1;
|
||||
}
|
||||
else if ((tfile = toml_parse_file(fp, errbuf, sizeof(errbuf))) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Error in keymap file %s - %s", filename, errbuf);
|
||||
fclose(fp);
|
||||
rv = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Error loading keymap file %s (%s)", filename, g_get_strerror());
|
||||
return 1;
|
||||
fclose(fp);
|
||||
LOG(LOG_LEVEL_INFO, "Loading keymap file %s", filename);
|
||||
|
||||
/* read the keymaps */
|
||||
km_read_section(tfile, "noshift", keymap->keys_noshift);
|
||||
km_read_section(tfile, "shift", keymap->keys_shift);
|
||||
km_read_section(tfile, "altgr", keymap->keys_altgr);
|
||||
km_read_section(tfile, "shiftaltgr", keymap->keys_shiftaltgr);
|
||||
km_read_section(tfile, "capslock", keymap->keys_capslock);
|
||||
km_read_section(tfile, "capslockaltgr", keymap->keys_capslockaltgr);
|
||||
km_read_section(tfile, "shiftcapslock", keymap->keys_shiftcapslock);
|
||||
km_read_section(tfile, "shiftcapslockaltgr",
|
||||
keymap->keys_shiftcapslockaltgr);
|
||||
|
||||
/* 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];
|
||||
int i;
|
||||
km_read_section(tfile, "numlock", keys_numlock);
|
||||
for (i = XR_RDP_SCAN_MIN_NUMLOCK; i <= XR_RDP_SCAN_MAX_NUMLOCK; ++i)
|
||||
{
|
||||
keymap->keys_numlock[i - XR_RDP_SCAN_MIN_NUMLOCK] = keys_numlock[i];
|
||||
}
|
||||
|
||||
toml_free(tfile);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
@ -452,6 +452,15 @@ 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];
|
||||
@ -462,6 +471,9 @@ struct xrdp_keymap
|
||||
struct xrdp_key_info keys_capslockaltgr[256];
|
||||
struct xrdp_key_info keys_shiftcapslock[256];
|
||||
struct xrdp_key_info keys_shiftcapslockaltgr[256];
|
||||
// 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];
|
||||
};
|
||||
|
||||
/* the window manager */
|
||||
|
Loading…
Reference in New Issue
Block a user