Replace xrdp_keyboard.ini with xrdp_keyboard.toml
This commit is contained in:
+1
-1
@@ -113,7 +113,7 @@ SUFFIXES = .in
|
||||
|
||||
dist_xrdpsysconf_DATA = \
|
||||
gfx.toml \
|
||||
xrdp_keyboard.ini
|
||||
xrdp_keyboard.toml
|
||||
|
||||
nodist_xrdpsysconf_DATA = \
|
||||
xrdp.ini
|
||||
|
||||
+317
-217
@@ -498,47 +498,318 @@ km_load_file(const char *filename, struct xrdp_keymap *keymap)
|
||||
|
||||
/*****************************************************************************/
|
||||
/***
|
||||
* looks up a keylayout in a list of values
|
||||
* reverse-looks up a keylayout in a TOML table
|
||||
*
|
||||
* @param keylayout (e.g. 000000409)
|
||||
* @param items List of items (one of which is returned)
|
||||
* @param values List of hexadecimal lookup values
|
||||
* @param keylayout (e.g. 0x000000409)
|
||||
* @param table TOML table
|
||||
* @param rdp_layout Buffer for result
|
||||
* @param rdp_layout_len Size of rdp_layout
|
||||
* @return != 0 for a successful lookup
|
||||
*/
|
||||
static int
|
||||
lookup_keylayout(int keylayout,
|
||||
const struct list *items,
|
||||
const struct list *values,
|
||||
toml_table_t *table,
|
||||
char rdp_layout[], unsigned int rdp_layout_len)
|
||||
{
|
||||
int index;
|
||||
for (index = 0; index < items->count; index++)
|
||||
int i;
|
||||
const char *key;
|
||||
toml_datum_t datum;
|
||||
toml_array_t *arr;
|
||||
|
||||
for (i = 0 ; (key = toml_key_in(table, i)) != NULL ; ++i)
|
||||
{
|
||||
const char *item = (const char *)list_get_item(items, index);
|
||||
const char *value = (const char *)list_get_item(values, index);
|
||||
if (g_atoix(value) == keylayout)
|
||||
if ((datum = toml_int_in(table, key)).ok)
|
||||
{
|
||||
strlcpy(rdp_layout, item, rdp_layout_len);
|
||||
return 1;
|
||||
/* It's an integer */
|
||||
if ((int)datum.u.i == keylayout)
|
||||
{
|
||||
strlcpy(rdp_layout, key, rdp_layout_len);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ((arr = toml_array_in(table, key)) != NULL)
|
||||
{
|
||||
/* It's an array */
|
||||
int nelem = toml_array_nelem(arr);
|
||||
int j;
|
||||
for (j = 0 ; j < nelem; ++j)
|
||||
{
|
||||
if ((datum = toml_int_at(arr, j)).ok)
|
||||
{
|
||||
/* It's an integer */
|
||||
if ((int)datum.u.i == keylayout)
|
||||
{
|
||||
strlcpy(rdp_layout, key, rdp_layout_len);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"%s:%d in table [%s] is not a valid value",
|
||||
key, j + 1, toml_table_key(table));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Key '%s' in table [%s] is neither an integer or an array",
|
||||
key, toml_table_key(table));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Looks up a string in a TOML table based on a key
|
||||
* @param arr TOML table
|
||||
* @param key Key to look up
|
||||
* @param out Buffer for result
|
||||
* @param out_size Length of buffer for result
|
||||
* @return != 0 if a string was read
|
||||
*/
|
||||
static int
|
||||
get_toml_string(const toml_table_t *arr, const char *key,
|
||||
char out[], unsigned int out_size)
|
||||
{
|
||||
toml_datum_t datum = toml_string_in(arr, key);
|
||||
if (datum.ok)
|
||||
{
|
||||
strlcpy(out, datum.u.s, out_size);
|
||||
free(datum.u.s);
|
||||
}
|
||||
return datum.ok;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Looks up an integer in a TOML table based on a key
|
||||
* @param arr TOML table
|
||||
* @param key Key to look up
|
||||
* @param default_val Default to return if no match
|
||||
*
|
||||
* @return value for key, or default_val
|
||||
*/
|
||||
static int
|
||||
get_toml_int(const toml_table_t *arr, const char *key, int default_val)
|
||||
{
|
||||
toml_datum_t datum = toml_int_in(arr, key);
|
||||
return (datum.ok) ? (int)datum.u.i : default_val;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Reads settable parameters from a TOML table
|
||||
*
|
||||
* @param table Table
|
||||
* @param layouts Buffer to get 'layouts' parameter
|
||||
* @param layouts_size Size of the above
|
||||
* @param map Buffer to get 'map' parameter
|
||||
* @param map_size Size of the above
|
||||
* @param model Buffer to get 'model' parameter
|
||||
* @param model_size Size of the above
|
||||
* @param variant Buffer to get 'variant' parameter
|
||||
* @param variant_size Size of the above
|
||||
* @param options Buffer to get 'options' parameter
|
||||
* @param options_size Size of the above
|
||||
*/
|
||||
static void
|
||||
read_param_set(toml_table_t *table,
|
||||
char layouts[], unsigned int layouts_size,
|
||||
char map[], unsigned int map_size,
|
||||
char model[], unsigned int model_size,
|
||||
char variant[], unsigned int variant_size,
|
||||
char options[], unsigned int options_size)
|
||||
{
|
||||
(void)get_toml_string(table, "layouts", layouts, layouts_size);
|
||||
(void)get_toml_string(table, "map", map, map_size);
|
||||
(void)get_toml_string(table, "model", model, model_size);
|
||||
(void)get_toml_string(table, "variant", variant, variant_size);
|
||||
(void)get_toml_string(table, "options", options, options_size);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Scans the [overrides.kb_type] sub-tables
|
||||
*
|
||||
* Looks for matches on keyboard type/subtype, and sets the keyboard
|
||||
* parameters appropriately.
|
||||
*
|
||||
* @param kb_type TOML source table
|
||||
* @param client_info Client info pointer
|
||||
* @param layouts_table_str Buffer to receive name of layouts table
|
||||
* @param layouts_table_str_len Length of above buffer
|
||||
* @param map_table_str Buffer to receive name of map table
|
||||
* @param map_table_str_len Length of above buffer
|
||||
*/
|
||||
static void
|
||||
scan_overrides_kbtype_tables(toml_table_t *kb_type,
|
||||
struct xrdp_client_info *client_info,
|
||||
char layouts_table_str[],
|
||||
unsigned int layouts_table_str_len,
|
||||
char map_table_str[],
|
||||
unsigned int map_table_str_len)
|
||||
{
|
||||
int i;
|
||||
const char *key;
|
||||
|
||||
for (i = 0 ; (key = toml_key_in(kb_type, i)) != NULL ; ++i)
|
||||
{
|
||||
toml_table_t *subtable = toml_table_in(kb_type, key);
|
||||
if (subtable == NULL)
|
||||
{
|
||||
continue; // Guard - shouldn't happen
|
||||
}
|
||||
int kb_type = get_toml_int(subtable, "type", 0);
|
||||
int kb_subtype = get_toml_int(subtable, "subtype", 0);
|
||||
if (kb_type == 0 && kb_subtype == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Keyboard config - table "
|
||||
"[overrides.kbtype.%s] is missing both type and subtype",
|
||||
key);
|
||||
continue;
|
||||
}
|
||||
if (kb_type != 0 && kb_type != client_info->keyboard_type)
|
||||
{
|
||||
continue; // Table specified a type which doesn't match
|
||||
}
|
||||
if (kb_subtype != 0 && kb_subtype != client_info->keyboard_subtype)
|
||||
{
|
||||
continue; // Table specified a subtype which doesn't match
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "Keyboard config - "
|
||||
"Matched overrides table [overrides.kb_type.%s]", key);
|
||||
|
||||
// Override any values we can find in the subtable
|
||||
read_param_set(subtable,
|
||||
layouts_table_str, layouts_table_str_len,
|
||||
map_table_str, map_table_str_len,
|
||||
client_info->model, sizeof(client_info->model),
|
||||
client_info->variant, sizeof(client_info->variant),
|
||||
client_info->options, sizeof(client_info->options));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static void
|
||||
read_toml_config(struct xrdp_client_info *client_info,
|
||||
const char filename[],
|
||||
toml_table_t *tfile)
|
||||
{
|
||||
char layouts_table_str[64];
|
||||
char map_table_str[64];
|
||||
char layout_name[64];
|
||||
|
||||
toml_table_t *defaults;
|
||||
toml_table_t *overrides;
|
||||
toml_table_t *layouts_table;
|
||||
toml_table_t *map_table;
|
||||
|
||||
|
||||
/* Step 1 - Parse the [defaults] table looking for the
|
||||
* layouts table name, the map table name, and (optionally) the
|
||||
* XKB model, variant and options
|
||||
*/
|
||||
if ((defaults = toml_table_in(tfile, "defaults")) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Keyboard config - can't find [defaults] table");
|
||||
return;
|
||||
}
|
||||
|
||||
layouts_table_str[0] = '\0';
|
||||
map_table_str[0] = '\0';
|
||||
read_param_set(defaults,
|
||||
layouts_table_str, sizeof(layouts_table_str),
|
||||
map_table_str, sizeof(map_table_str),
|
||||
client_info->model, sizeof(client_info->model),
|
||||
client_info->variant, sizeof(client_info->variant),
|
||||
client_info->options, sizeof(client_info->options));
|
||||
|
||||
if (layouts_table_str[0] == '\0' || map_table_str[0] == '\0')
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Keyboard config - "
|
||||
"[defaults] table is missing layouts and/or map keys");
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2 - Now scan the [overrides] table, looking for
|
||||
// subtables
|
||||
if ((overrides = toml_table_in(tfile, "overrides")) != NULL)
|
||||
{
|
||||
toml_table_t *kb_type = toml_table_in(overrides, "kb_type");
|
||||
if (kb_type != NULL)
|
||||
{
|
||||
// Look for overrides on type and/or subtype
|
||||
scan_overrides_kbtype_tables(kb_type,
|
||||
client_info,
|
||||
layouts_table_str,
|
||||
sizeof(layouts_table_str),
|
||||
map_table_str, sizeof(map_table_str));
|
||||
}
|
||||
}
|
||||
|
||||
/* Check we have valid layouts and map tables */
|
||||
if ((layouts_table = toml_table_in(tfile, layouts_table_str)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't find layouts table ['%s'] in %s",
|
||||
layouts_table_str, filename);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((map_table = toml_table_in(tfile, map_table_str)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't find map table ['%s'] in %s",
|
||||
map_table_str, filename);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Step 2 - Look up the keylayout passed from the client to get a
|
||||
* layout_name */
|
||||
layout_name[0] = '\0';
|
||||
if (!lookup_keylayout(client_info->keylayout, layouts_table,
|
||||
layout_name, sizeof(layout_name)))
|
||||
{
|
||||
if ((client_info->keylayout & ~0xffff) != 0)
|
||||
{
|
||||
// We failed to match the layout, but we may be able
|
||||
// to match on the lower 16-bits
|
||||
int alt_layout = client_info->keylayout & 0xffff;
|
||||
if (lookup_keylayout(alt_layout, layouts_table,
|
||||
layout_name, sizeof(layout_name)))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Failed to match layout 0x%08X, but matched 0x%04X to %s",
|
||||
client_info->keylayout, alt_layout, layout_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layout_name[0] == '\0')
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't find layout %08x in layout table %s",
|
||||
client_info->keylayout, layouts_table_str);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 3 - use the layout name we matched from the layouts table to
|
||||
// lookup the corresponding X11 layout in the map table, e.g. if we
|
||||
// matched 0xe0200411 to 'rdp_layout_jp, copy 'jp' for the client.
|
||||
if (!get_toml_string(map_table, layout_name,
|
||||
client_info->layout, sizeof(client_info->layout)))
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't find layout name %s in map table %s",
|
||||
layout_name, map_table_str);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void
|
||||
xrdp_init_xkb_layout(struct xrdp_client_info *client_info)
|
||||
{
|
||||
int fd;
|
||||
int index = 0;
|
||||
struct list *names = NULL;
|
||||
struct list *items = NULL;
|
||||
struct list *values = NULL;
|
||||
const char *item = NULL;
|
||||
const char *value = NULL;
|
||||
const char *q = NULL;
|
||||
const char *keyboard_cfg_file = XRDP_CFG_PATH "/xrdp_keyboard.ini";
|
||||
FILE *fp;
|
||||
const char *keyboard_cfg_file = XRDP_CFG_PATH "/xrdp_keyboard.toml";
|
||||
|
||||
const struct xrdp_keyboard_overrides *ko =
|
||||
&client_info->xrdp_keyboard_overrides;
|
||||
@@ -573,12 +844,7 @@ xrdp_init_xkb_layout(struct xrdp_client_info *client_info)
|
||||
client_info->model[0] = '\0';
|
||||
client_info->variant[0] = '\0';
|
||||
strlcpy(client_info->layout, "us", sizeof(client_info->layout));
|
||||
if (client_info->keyboard_subtype == 3)
|
||||
{
|
||||
/* macintosh keyboard */
|
||||
strlcpy(client_info->variant, "mac", sizeof(client_info->variant));
|
||||
}
|
||||
else if (client_info->keyboard_subtype == 0)
|
||||
if (client_info->keyboard_subtype == 0)
|
||||
{
|
||||
/* default - standard subtype */
|
||||
client_info->keyboard_subtype = 1;
|
||||
@@ -586,199 +852,33 @@ xrdp_init_xkb_layout(struct xrdp_client_info *client_info)
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "keyboard_cfg_file %s", keyboard_cfg_file);
|
||||
|
||||
fd = g_file_open_ro(keyboard_cfg_file);
|
||||
|
||||
if (fd >= 0)
|
||||
if ((fp = fopen(keyboard_cfg_file, "r")) == NULL)
|
||||
{
|
||||
int section_found = -1;
|
||||
char section_rdp_layouts[256];
|
||||
char section_layouts_map[256];
|
||||
char rdp_layout[256];
|
||||
|
||||
section_rdp_layouts[0] = '\0';
|
||||
section_layouts_map[0] = '\0';
|
||||
rdp_layout[0] = '\0';
|
||||
|
||||
names = list_create();
|
||||
names->auto_free = 1;
|
||||
items = list_create();
|
||||
items->auto_free = 1;
|
||||
values = list_create();
|
||||
values->auto_free = 1;
|
||||
|
||||
file_read_sections(fd, names);
|
||||
for (index = 0; index < names->count; index++)
|
||||
{
|
||||
q = (const char *)list_get_item(names, index);
|
||||
if (g_strcasecmp("default", q) != 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
file_read_section(fd, q, items, values);
|
||||
|
||||
for (i = 0; i < items->count; i++)
|
||||
{
|
||||
item = (const char *)list_get_item(items, i);
|
||||
value = (const char *)list_get_item(values, i);
|
||||
LOG(LOG_LEVEL_DEBUG, "xrdp_init_xkb_layout: item %s value %s",
|
||||
item, value);
|
||||
if (g_strcasecmp(item, "keyboard_type") == 0)
|
||||
{
|
||||
int v = g_atoi(value);
|
||||
if (v == client_info->keyboard_type)
|
||||
{
|
||||
section_found = index;
|
||||
}
|
||||
}
|
||||
else if (g_strcasecmp(item, "keyboard_subtype") == 0)
|
||||
{
|
||||
int v = g_atoi(value);
|
||||
if (v != client_info->keyboard_subtype &&
|
||||
section_found == index)
|
||||
{
|
||||
section_found = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (g_strcasecmp(item, "rdp_layouts") == 0)
|
||||
{
|
||||
if (section_found != -1 && section_found == index)
|
||||
{
|
||||
strlcpy(section_rdp_layouts, value,
|
||||
sizeof(section_rdp_layouts));
|
||||
}
|
||||
}
|
||||
else if (g_strcasecmp(item, "layouts_map") == 0)
|
||||
{
|
||||
if (section_found != -1 && section_found == index)
|
||||
{
|
||||
strlcpy(section_layouts_map, value,
|
||||
sizeof(section_layouts_map));
|
||||
}
|
||||
}
|
||||
else if (g_strcasecmp(item, "model") == 0)
|
||||
{
|
||||
if (section_found != -1 && section_found == index)
|
||||
{
|
||||
strlcpy(client_info->model, value,
|
||||
sizeof(client_info->model));
|
||||
}
|
||||
}
|
||||
else if (g_strcasecmp(item, "variant") == 0)
|
||||
{
|
||||
if (section_found != -1 && section_found == index)
|
||||
{
|
||||
strlcpy(client_info->variant, value,
|
||||
sizeof(client_info->variant));
|
||||
}
|
||||
}
|
||||
else if (g_strcasecmp(item, "options") == 0)
|
||||
{
|
||||
if (section_found != -1 && section_found == index)
|
||||
{
|
||||
strlcpy(client_info->options, value,
|
||||
sizeof(client_info->options));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* mixing items from different sections will result in
|
||||
* skipping over current section.
|
||||
*/
|
||||
LOG(LOG_LEVEL_DEBUG, "xrdp_init_xkb_layout: skipping "
|
||||
"configuration item - %s, continuing to next "
|
||||
"section", item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_clear(items);
|
||||
list_clear(values);
|
||||
}
|
||||
}
|
||||
|
||||
if (section_found == -1)
|
||||
{
|
||||
// read default section
|
||||
strlcpy(section_rdp_layouts, "default_rdp_layouts",
|
||||
sizeof(section_rdp_layouts));
|
||||
strlcpy(section_layouts_map, "default_layouts_map",
|
||||
sizeof(section_layouts_map));
|
||||
|
||||
file_read_section(fd, "default", items, values);
|
||||
for (index = 0; index < items->count; index++)
|
||||
{
|
||||
item = (const char *)list_get_item(items, index);
|
||||
value = (const char *)list_get_item(values, index);
|
||||
if (g_strcasecmp(item, "rdp_layouts") == 0)
|
||||
{
|
||||
strlcpy(section_rdp_layouts, value,
|
||||
sizeof(section_rdp_layouts));
|
||||
}
|
||||
else if (g_strcasecmp(item, "layouts_map") == 0)
|
||||
{
|
||||
strlcpy(section_layouts_map, value,
|
||||
sizeof(section_layouts_map));
|
||||
}
|
||||
}
|
||||
list_clear(items);
|
||||
list_clear(values);
|
||||
}
|
||||
|
||||
/* load the map */
|
||||
file_read_section(fd, section_rdp_layouts, items, values);
|
||||
if (!lookup_keylayout(client_info->keylayout, items, values,
|
||||
rdp_layout, sizeof(rdp_layout)))
|
||||
{
|
||||
if ((client_info->keylayout & ~0xffff) != 0)
|
||||
{
|
||||
// We failed to match the layout, but we may be able
|
||||
// to match on the lower 16-bits
|
||||
int alt_layout = client_info->keylayout & 0xffff;
|
||||
if (lookup_keylayout(alt_layout, items, values,
|
||||
rdp_layout, sizeof(rdp_layout)))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Failed to match layout 0x%08X, but matched 0x%04X to %s",
|
||||
client_info->keylayout, alt_layout, rdp_layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
list_clear(items);
|
||||
list_clear(values);
|
||||
|
||||
// If we found a layout in the rdp layouts section, copy the
|
||||
// corresponding X11 layout name to the client layout, e.g. if we
|
||||
// matched 0xe0200411 to 'rdp_layout_jp, copy 'jp' for the client.
|
||||
if (rdp_layout[0] != '\0')
|
||||
{
|
||||
file_read_section(fd, section_layouts_map, items, values);
|
||||
for (index = 0; index < items->count; index++)
|
||||
{
|
||||
item = (const char *)list_get_item(items, index);
|
||||
value = (const char *)list_get_item(values, index);
|
||||
if (g_strcasecmp(item, rdp_layout) == 0)
|
||||
{
|
||||
strlcpy(client_info->layout, value,
|
||||
sizeof(client_info->layout));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
list_delete(names);
|
||||
list_delete(items);
|
||||
list_delete(values);
|
||||
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_init_xkb_layout: model [%s] variant [%s] "
|
||||
"layout [%s] options [%s]", client_info->model,
|
||||
client_info->variant, client_info->layout, client_info->options);
|
||||
g_file_close(fd);
|
||||
LOG(LOG_LEVEL_ERROR, "Error loading keyboard config file %s (%s)",
|
||||
keyboard_cfg_file, g_get_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_init_xkb_layout: error opening %s",
|
||||
keyboard_cfg_file);
|
||||
char errbuf[200];
|
||||
toml_table_t *tfile = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
||||
fclose(fp); // No longer need this open
|
||||
fp = NULL;
|
||||
|
||||
if (tfile == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Error in keyboard config file %s - %s",
|
||||
keyboard_cfg_file, errbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
read_toml_config(client_info, keyboard_cfg_file, tfile);
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_init_xkb_layout: model [%s] variant [%s] "
|
||||
"layout [%s] options [%s]",
|
||||
client_info->model, client_info->variant,
|
||||
client_info->layout, client_info->options);
|
||||
toml_free(tfile);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise the rules and a few keycodes for xorgxrdp
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
;
|
||||
; RDP Keyboard <-> X11 Keyboard layout map
|
||||
;
|
||||
; How this file works:
|
||||
; 1. load the file and scan each section to find matching "keyboard_type"
|
||||
; and "keyboard_subtype" based on the values received from the client.
|
||||
; If not found, then jump to default section.
|
||||
; 2. in the selected section, look for "rdp_layouts" and "layouts_map".
|
||||
; Based on the "keylayout" value from the client, find the right x11
|
||||
; layout value.
|
||||
; 3. model/variant are inferred based on the "keyboard_type" and
|
||||
; "keyboard_subtype", but they can be overridden.
|
||||
;
|
||||
|
||||
;
|
||||
; RDP Keyboard Type (http://msdn.microsoft.com/en-us/library/cc240563.aspx)
|
||||
;
|
||||
; 0 is not a valid value
|
||||
;
|
||||
; 1 - IBM PC/XT or compatible (83-key) keyboard
|
||||
; 2 - Olivetti "ICO" (102-key) keyboard
|
||||
; 3 - IBM PC/AT (84-key) or similar keyboard
|
||||
; 4 - IBM enhanced (101- or 102-key) keyboard
|
||||
; 5 - Nokia 1050 and similar keyboards
|
||||
; 6 - Nokia 9140 and similar keyboards
|
||||
; 7 - Japanese keyboard
|
||||
;
|
||||
; RDP Keyboard Subtype is vendor dependent. XRDP defines as follows:
|
||||
;
|
||||
; 0 is not a valid value
|
||||
;
|
||||
; 1 - Standard
|
||||
; 2 - FreeRDP JP keyboard
|
||||
; 3 - Macintosh
|
||||
; ... - < any vendor dependent subtype >
|
||||
;
|
||||
; The list can be augmented.
|
||||
;
|
||||
|
||||
|
||||
; default
|
||||
[default]
|
||||
; keyboard_type and keyboard_subtype is not read for default section. It
|
||||
; is only a placeholder to keep consistency. Default model/variant are
|
||||
; platform dependent, and could be overridden if needed.
|
||||
keyboard_type=0
|
||||
keyboard_subtype=0
|
||||
|
||||
; user could override variant and model, but generally they should be inferred
|
||||
; automatically based on keyboard type and subtype
|
||||
;variant=
|
||||
;model=
|
||||
|
||||
; A list of supported RDP keyboard layouts
|
||||
rdp_layouts=default_rdp_layouts
|
||||
; The map from RDP keyboard layout to X11 keyboard layout
|
||||
layouts_map=default_layouts_map
|
||||
|
||||
[default_rdp_layouts]
|
||||
rdp_layout_us=0x00000409
|
||||
rdp_layout_us_colemak=0x00060409
|
||||
rdp_layout_us_dvorak=0x00010409
|
||||
rdp_layout_us_dvp=0x19360409
|
||||
rdp_layout_cz=0x00000405
|
||||
rdp_layout_dk=0x00000406
|
||||
rdp_layout_de=0x00000407
|
||||
rdp_layout_es=0x0000040A
|
||||
rdp_layout_fi=0x0000040B
|
||||
rdp_layout_fr=0x0000040C
|
||||
rdp_layout_hu=0x0000040E
|
||||
rdp_layout_it=0x00000410
|
||||
rdp_layout_jp=0x00000411
|
||||
rdp_layout_jp=0xe0010411
|
||||
rdp_layout_jp=0xe0200411
|
||||
rdp_layout_jp=0xe0210411
|
||||
rdp_layout_kr=0x00000412
|
||||
rdp_layout_no=0x00000414
|
||||
rdp_layout_pl=0x00000415
|
||||
rdp_layout_br=0x00000416
|
||||
rdp_layout_ru=0x00000419
|
||||
rdp_layout_se=0x0000041D
|
||||
rdp_layout_lv=0x00000426
|
||||
rdp_layout_lv_std=0x00010426
|
||||
rdp_layout_lv_std=0x00020426
|
||||
rdp_layout_ch=0x00000807
|
||||
rdp_layout_ch_fr=0x0000100C
|
||||
rdp_layout_gb=0x00000809
|
||||
rdp_layout_latam=0x0000080A
|
||||
rdp_layout_be=0x00000813
|
||||
rdp_layout_pt=0x00000816
|
||||
|
||||
; <rdp layout name> = <X11 keyboard layout value>
|
||||
[default_layouts_map]
|
||||
rdp_layout_us=us
|
||||
rdp_layout_us_colemak=us(colemak)
|
||||
rdp_layout_us_dvorak=us(dvorak)
|
||||
rdp_layout_us_dvp=us(dvp)
|
||||
rdp_layout_cz=cz
|
||||
rdp_layout_dk=dk
|
||||
rdp_layout_de=de
|
||||
rdp_layout_es=es
|
||||
rdp_layout_fi=fi
|
||||
rdp_layout_fr=fr
|
||||
rdp_layout_hu=hu
|
||||
rdp_layout_it=it
|
||||
rdp_layout_jp=jp
|
||||
rdp_layout_kr=kr
|
||||
rdp_layout_no=no
|
||||
rdp_layout_pl=pl
|
||||
rdp_layout_br=br(abnt2)
|
||||
rdp_layout_ru=ru
|
||||
rdp_layout_se=se
|
||||
rdp_layout_lv=lv(ergonomic)
|
||||
rdp_layout_lv_std=lv
|
||||
rdp_layout_ch=ch
|
||||
rdp_layout_ch_fr=ch(fr)
|
||||
rdp_layout_gb=gb
|
||||
rdp_layout_latam=latam
|
||||
rdp_layout_be=be
|
||||
rdp_layout_pt=pt
|
||||
|
||||
; if two sections have the same keyboard_type and keyboard_subtype, then
|
||||
; the latter could override the former.
|
||||
[rdp_keyboard_mac]
|
||||
keyboard_type=4
|
||||
keyboard_subtype=3
|
||||
rdp_layouts=default_rdp_layouts
|
||||
layouts_map=rdp_layouts_map_mac
|
||||
|
||||
[rdp_keyboard_jp]
|
||||
keyboard_type=7
|
||||
keyboard_subtype=2
|
||||
model=pc105
|
||||
rdp_layouts=default_rdp_layouts
|
||||
layouts_map=default_layouts_map
|
||||
|
||||
[rdp_layouts_map_mac]
|
||||
rdp_layout_us=us
|
||||
rdp_layout_us_colemak=us(colemak)
|
||||
rdp_layout_us_dvorak=us(dvorak)
|
||||
rdp_layout_us_dvp=us(dvp)
|
||||
rdp_layout_cz=cz
|
||||
rdp_layout_dk=dk
|
||||
rdp_layout_de=de
|
||||
rdp_layout_es=es
|
||||
rdp_layout_fi=fi
|
||||
rdp_layout_fr=fr
|
||||
rdp_layout_hu=hu
|
||||
rdp_layout_it=it
|
||||
rdp_layout_jp=jp
|
||||
rdp_layout_kr=kr
|
||||
rdp_layout_pl=pl
|
||||
rdp_layout_br=br(abnt2)
|
||||
rdp_layout_ru=ru
|
||||
rdp_layout_se=se
|
||||
rdp_layout_lv=lv(ergonomic)
|
||||
rdp_layout_lv_std=lv
|
||||
rdp_layout_ch=ch
|
||||
rdp_layout_ch_fr=ch(fr)
|
||||
rdp_layout_gb=gb
|
||||
rdp_layout_latam=latam
|
||||
rdp_layout_be=be
|
||||
rdp_layout_pt=pt
|
||||
@@ -0,0 +1,173 @@
|
||||
#
|
||||
# RDP Keyboard <-> X11 Keyboard layout map (xorgxrdp support)
|
||||
#
|
||||
# How this file works
|
||||
# -------------------
|
||||
#
|
||||
# Inputs from the RDP client:-
|
||||
# - Keyboard type 'kb_type' (see below)
|
||||
# - Keyboard subtype 'kb_subtype' (see below)
|
||||
# - RDP layout identifier 'layout_id' (see [MS-LCID])
|
||||
#
|
||||
# 1. The following values are read from the [defaults] table:-
|
||||
# - layouts Required. The name of the table which translates the
|
||||
# layout_id to a layout_name, using reverse-lookup.
|
||||
# - map Required. A table mapping layout names to XKB
|
||||
# layout strings.
|
||||
# - model Optional. Value defining the XKB model name
|
||||
# - variant Optional. Value defining the XKB variant name
|
||||
# - options Optional. Value defining the XKB options string
|
||||
#
|
||||
# 2. The [overrides] sub-tables are scanned:-
|
||||
# a) The [overrides.kb_type.*] tables are scanned looking for a
|
||||
# match on kb_type, kb_subtype, or both. A successful match
|
||||
# results in overrides being applied to the values described in 1.
|
||||
#
|
||||
# Other table names directly under the [overrides] table are reserved
|
||||
# for future use.
|
||||
#
|
||||
# 3. The ['layouts'] table is reverse-looked-up to get a layout_name using
|
||||
# the 'layout_id'.
|
||||
# 4. The ['map'] table is looked-up by the layout_name to get an XKB
|
||||
# layout for the session.
|
||||
#
|
||||
# There are some subtleties:-
|
||||
# 1. (In step 3) If a layout_id > 0xffff fails to match, the lookup
|
||||
# is retried with the lower 16-bits of the layout_id.
|
||||
# 2. (In step 2). More than one layout_id can be mapped to the
|
||||
# same layout_name using an array of values.
|
||||
#
|
||||
# RDP Keyboard Type [MS-RDPBCGR] section 2.2.7.1.6
|
||||
# ------------------------------------------------
|
||||
#
|
||||
# 0 is not a valid value
|
||||
#
|
||||
# 1 - IBM PC/XT or compatible (83-key) keyboard
|
||||
# 2 - Olivetti "ICO" (102-key) keyboard
|
||||
# 3 - IBM PC/AT (84-key) or similar keyboard
|
||||
# 4 - IBM enhanced (101- or 102-key) keyboard
|
||||
# 5 - Nokia 1050 and similar keyboards
|
||||
# 6 - Nokia 9140 and similar keyboards
|
||||
# 7 - Japanese keyboard
|
||||
#
|
||||
# RDP Keyboard Subtype
|
||||
# --------------------
|
||||
# This is vendor dependent. XRDP defines as follows:
|
||||
#
|
||||
# 0 is not a valid value
|
||||
#
|
||||
# 1 - Standard
|
||||
# 2 - FreeRDP JP keyboard
|
||||
# 3 - Macintosh
|
||||
# ... - < any vendor dependent subtype >
|
||||
#
|
||||
# The list can be augmented.
|
||||
|
||||
[defaults]
|
||||
layouts = "layouts"
|
||||
map = "default_layouts_map"
|
||||
# user can set these values, but generally they should be inferred
|
||||
# automatically based on keyboard type and subtype
|
||||
#model =
|
||||
#variant =
|
||||
#options =
|
||||
|
||||
[overrides.kb_type.mac]
|
||||
# Mac - set a variant and alternate layouts map
|
||||
subtype = 3
|
||||
map = "mac_layouts_map"
|
||||
variant = "mac"
|
||||
|
||||
[overrides.kb_type.jp]
|
||||
# Japanese - set the keyboard model
|
||||
type = 7
|
||||
subtype = 2
|
||||
model = "pc105"
|
||||
|
||||
[layouts]
|
||||
rdp_layout_us = 0x00000409
|
||||
rdp_layout_us_colemak = 0x00060409
|
||||
rdp_layout_us_dvorak = 0x00010409
|
||||
rdp_layout_us_dvp = 0x19360409
|
||||
rdp_layout_cz = 0x00000405
|
||||
rdp_layout_dk = 0x00000406
|
||||
rdp_layout_de = 0x00000407
|
||||
rdp_layout_es = 0x0000040A
|
||||
rdp_layout_fi = 0x0000040B
|
||||
rdp_layout_fr = 0x0000040C
|
||||
rdp_layout_hu = 0x0000040E
|
||||
rdp_layout_it = 0x00000410
|
||||
rdp_layout_jp = [ 0x00000411, 0xe0010411, 0xe0200411, 0xe0210411 ]
|
||||
rdp_layout_kr = 0x00000412
|
||||
rdp_layout_no = 0x00000414
|
||||
rdp_layout_pl = 0x00000415
|
||||
rdp_layout_br = 0x00000416
|
||||
rdp_layout_ru = 0x00000419
|
||||
rdp_layout_se = 0x0000041D
|
||||
rdp_layout_lv = 0x00000426
|
||||
rdp_layout_lv_std = [ 0x00010426, 0x00020426 ]
|
||||
rdp_layout_ch = 0x00000807
|
||||
rdp_layout_ch_fr = 0x0000100C
|
||||
rdp_layout_gb = 0x00000809
|
||||
rdp_layout_latam = 0x0000080A
|
||||
rdp_layout_be = 0x00000813
|
||||
rdp_layout_pt = 0x00000816
|
||||
|
||||
|
||||
# <rdp layout name> = <X11 keyboard layout value>
|
||||
[default_layouts_map]
|
||||
rdp_layout_us = "us"
|
||||
rdp_layout_us_colemak = "us(colemak)"
|
||||
rdp_layout_us_dvorak = "us(dvorak)"
|
||||
rdp_layout_us_dvp = "us(dvp)"
|
||||
rdp_layout_cz = "cz"
|
||||
rdp_layout_dk = "dk"
|
||||
rdp_layout_de = "de"
|
||||
rdp_layout_es = "es"
|
||||
rdp_layout_fi = "fi"
|
||||
rdp_layout_fr = "fr"
|
||||
rdp_layout_hu = "hu"
|
||||
rdp_layout_it = "it"
|
||||
rdp_layout_jp = "jp"
|
||||
rdp_layout_kr = "kr"
|
||||
rdp_layout_no = "no"
|
||||
rdp_layout_pl = "pl"
|
||||
rdp_layout_br = "br(abnt2)"
|
||||
rdp_layout_ru = "ru"
|
||||
rdp_layout_se = "se"
|
||||
rdp_layout_lv = "lv(ergonomic)"
|
||||
rdp_layout_lv_std = "lv"
|
||||
rdp_layout_ch = "ch"
|
||||
rdp_layout_ch_fr = "ch(fr)"
|
||||
rdp_layout_gb = "gb"
|
||||
rdp_layout_latam = "latam"
|
||||
rdp_layout_be = "be"
|
||||
rdp_layout_pt = "pt"
|
||||
|
||||
[mac_layouts_map]
|
||||
rdp_layout_us = "us"
|
||||
rdp_layout_us_colemak = "us(colemak)"
|
||||
rdp_layout_us_dvorak = "us(dvorak)"
|
||||
rdp_layout_us_dvp = "us(dvp)"
|
||||
rdp_layout_cz = "cz"
|
||||
rdp_layout_dk = "dk"
|
||||
rdp_layout_de = "de"
|
||||
rdp_layout_es = "es"
|
||||
rdp_layout_fi = "fi"
|
||||
rdp_layout_fr = "fr"
|
||||
rdp_layout_hu = "hu"
|
||||
rdp_layout_it = "it"
|
||||
rdp_layout_jp = "jp"
|
||||
rdp_layout_kr = "kr"
|
||||
rdp_layout_pl = "pl"
|
||||
rdp_layout_br = "br(abnt2)"
|
||||
rdp_layout_ru = "ru"
|
||||
rdp_layout_se = "se"
|
||||
rdp_layout_lv = "lv(ergonomic)"
|
||||
rdp_layout_lv_std = "lv"
|
||||
rdp_layout_ch = "ch"
|
||||
rdp_layout_ch_fr = "ch(fr)"
|
||||
rdp_layout_gb = "gb"
|
||||
rdp_layout_latam = "latam"
|
||||
rdp_layout_be = "be"
|
||||
rdp_layout_pt = "pt"
|
||||
Reference in New Issue
Block a user