Replace xrdp_keyboard.ini with xrdp_keyboard.toml

This commit is contained in:
matt335672
2025-04-29 12:22:25 +01:00
parent 312d9b88db
commit 8c130d0b89
4 changed files with 491 additions and 381 deletions
+1 -1
View File
@@ -113,7 +113,7 @@ SUFFIXES = .in
dist_xrdpsysconf_DATA = \
gfx.toml \
xrdp_keyboard.ini
xrdp_keyboard.toml
nodist_xrdpsysconf_DATA = \
xrdp.ini
+311 -211
View File
@@ -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);
/* 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));
}
LOG(LOG_LEVEL_ERROR, "Error loading keyboard config file %s (%s)",
keyboard_cfg_file, g_get_strerror());
}
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;
}
}
char errbuf[200];
toml_table_t *tfile = toml_parse_file(fp, errbuf, sizeof(errbuf));
fclose(fp); // No longer need this open
fp = NULL;
list_clear(items);
list_clear(values);
}
}
if (section_found == -1)
if (tfile == NULL)
{
// 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++)
LOG(LOG_LEVEL_ERROR,
"Error in keyboard config file %s - %s",
keyboard_cfg_file, errbuf);
}
else
{
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);
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);
g_file_close(fd);
"layout [%s] options [%s]",
client_info->model, client_info->variant,
client_info->layout, client_info->options);
toml_free(tfile);
}
else
{
LOG(LOG_LEVEL_ERROR, "xrdp_init_xkb_layout: error opening %s",
keyboard_cfg_file);
}
// Initialise the rules and a few keycodes for xorgxrdp
-163
View File
@@ -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
+173
View File
@@ -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"