From 8c130d0b896178eb31f9ca3a9caeb789e90d8034 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:22:25 +0100 Subject: [PATCH] Replace xrdp_keyboard.ini with xrdp_keyboard.toml --- xrdp/Makefile.am | 2 +- xrdp/lang.c | 534 ++++++++++++++++++++++++---------------- xrdp/xrdp_keyboard.ini | 163 ------------ xrdp/xrdp_keyboard.toml | 173 +++++++++++++ 4 files changed, 491 insertions(+), 381 deletions(-) delete mode 100644 xrdp/xrdp_keyboard.ini create mode 100644 xrdp/xrdp_keyboard.toml diff --git a/xrdp/Makefile.am b/xrdp/Makefile.am index 4d4e53f6..996eae92 100644 --- a/xrdp/Makefile.am +++ b/xrdp/Makefile.am @@ -113,7 +113,7 @@ SUFFIXES = .in dist_xrdpsysconf_DATA = \ gfx.toml \ - xrdp_keyboard.ini + xrdp_keyboard.toml nodist_xrdpsysconf_DATA = \ xrdp.ini diff --git a/xrdp/lang.c b/xrdp/lang.c index 2dd7696f..8910e301 100644 --- a/xrdp/lang.c +++ b/xrdp/lang.c @@ -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 diff --git a/xrdp/xrdp_keyboard.ini b/xrdp/xrdp_keyboard.ini deleted file mode 100644 index e6f4003c..00000000 --- a/xrdp/xrdp_keyboard.ini +++ /dev/null @@ -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 - -; = -[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 diff --git a/xrdp/xrdp_keyboard.toml b/xrdp/xrdp_keyboard.toml new file mode 100644 index 00000000..2a2adfec --- /dev/null +++ b/xrdp/xrdp_keyboard.toml @@ -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 + + +# = +[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"