Merge pull request #3512 from matt335672/xrdp_keyboard_ini_to_toml

Xrdp keyboard ini to toml
This commit is contained in:
matt335672
2025-05-21 11:47:38 +01:00
committed by GitHub
12 changed files with 586 additions and 454 deletions
+4 -2
View File
@@ -1,12 +1,14 @@
# tomlc99
> **Note: there is a newer version of this library available at [tomlc17](https://github.com/cktan/tomlc17).**
TOML in c99; v1.0 compliant.
If you are looking for a C++ library, you might try this wrapper: [https://github.com/cktan/tomlcpp](https://github.com/cktan/tomlcpp).
* Compatible with [TOML v1.0.0](https://toml.io/en/v1.0.0).
* Tested with multiple test suites, including
[BurntSushi/toml-test](https://github.com/BurntSushi/toml-test) and
[toml-lang/toml-test](https://github.com/toml-lang/toml-test) and
[iarna/toml-spec-tests](https://github.com/iarna/toml-spec-tests).
* Provides very simple and intuitive interface.
@@ -174,7 +176,7 @@ Alternatively, specify `make install prefix=/a/file/path` to install into
## Testing
To test against the standard test set provided by BurntSushi/toml-test:
To test against the standard test set provided by toml-lang/toml-test:
```sh
% make
Vendored Regular → Executable
+3 -6
View File
@@ -1,9 +1,6 @@
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
mkdir -p $DIR/goworkspace
export GOPATH=$DIR/goworkspace
go get github.com/BurntSushi/toml-test@latest # install test suite
go install github.com/BurntSushi/toml/cmd/toml-test-decoder@latest # e.g., install my parser
cp $GOPATH/bin/* .
export GOBIN=$DIR
go install github.com/toml-lang/toml-test/cmd/toml-test@latest # install test suite
Vendored Regular → Executable
+3 -3
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
rm -f tests
ln -s ./goworkspace/pkg/mod/github.com/\!burnt\!sushi/toml-test@v0.1.0/tests
./toml-test ../toml_json
$DIR/toml-test $DIR/../toml_json
Vendored Regular → Executable
+2 -1
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -e
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
[ -d toml-spec-tests ] || git clone https://github.com/cktan/toml-spec-tests.git
Vendored Regular → Executable
+7 -5
View File
@@ -1,4 +1,6 @@
if ! (which jq >& /dev/null); then
#!/usr/bin/env bash
if ! (which jq >& /dev/null); then
echo "ERROR: please install the 'jq' utility"
exit 1
fi
@@ -12,11 +14,11 @@ for i in toml-spec-tests/values/*.toml; do
fname="${fname%.*}"
echo -n $fname ' '
res='[OK]'
if (../toml_json $fname.toml >& $fname.json.out); then
if (../toml_json $fname.toml >& $fname.json.out); then
jq -S . $fname.json.out > t.json
mv t.json $fname.json.out
if [ -f $fname.json ]; then
if ! (diff $fname.json $fname.json.out >& /dev/null); then
if ! (diff $fname.json $fname.json.out >& /dev/null); then
res='[FAILED]'
else
rm -f $fname.json.out
@@ -32,10 +34,10 @@ done
#
# NEGATIVE tests
#
for i in toml-spec-tests/errors/*.toml; do
for i in toml-spec-tests/errors/*.toml; do
echo -n $i ' '
res='[OK]'
if (../toml_json $i >& $i.json.out); then
if (../toml_json $i >& $i.json.out); then
res='[FAILED]'
fi
echo ... $res
+45 -33
View File
@@ -221,8 +221,8 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) {
110xxxxx 10xxxxxx
*/
if (code <= 0x000007FF) {
buf[0] = (unsigned char) (0xc0 | (code >> 6));
buf[1] = (unsigned char) (0x80 | (code & 0x3f));
buf[0] = (unsigned char)(0xc0 | (code >> 6));
buf[1] = (unsigned char)(0x80 | (code & 0x3f));
return 2;
}
@@ -230,9 +230,9 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) {
1110xxxx 10xxxxxx 10xxxxxx
*/
if (code <= 0x0000FFFF) {
buf[0] = (unsigned char) (0xe0 | (code >> 12));
buf[1] = (unsigned char) (0x80 | ((code >> 6) & 0x3f));
buf[2] = (unsigned char) (0x80 | (code & 0x3f));
buf[0] = (unsigned char)(0xe0 | (code >> 12));
buf[1] = (unsigned char)(0x80 | ((code >> 6) & 0x3f));
buf[2] = (unsigned char)(0x80 | (code & 0x3f));
return 3;
}
@@ -240,10 +240,10 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) {
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
if (code <= 0x001FFFFF) {
buf[0] = (unsigned char) (0xf0 | (code >> 18));
buf[1] = (unsigned char) (0x80 | ((code >> 12) & 0x3f));
buf[2] = (unsigned char) (0x80 | ((code >> 6) & 0x3f));
buf[3] = (unsigned char) (0x80 | (code & 0x3f));
buf[0] = (unsigned char)(0xf0 | (code >> 18));
buf[1] = (unsigned char)(0x80 | ((code >> 12) & 0x3f));
buf[2] = (unsigned char)(0x80 | ((code >> 6) & 0x3f));
buf[3] = (unsigned char)(0x80 | (code & 0x3f));
return 4;
}
@@ -251,11 +251,11 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) {
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
if (code <= 0x03FFFFFF) {
buf[0] = (unsigned char) (0xf8 | (code >> 24));
buf[1] = (unsigned char) (0x80 | ((code >> 18) & 0x3f));
buf[2] = (unsigned char) (0x80 | ((code >> 12) & 0x3f));
buf[3] = (unsigned char) (0x80 | ((code >> 6) & 0x3f));
buf[4] = (unsigned char) (0x80 | (code & 0x3f));
buf[0] = (unsigned char)(0xf8 | (code >> 24));
buf[1] = (unsigned char)(0x80 | ((code >> 18) & 0x3f));
buf[2] = (unsigned char)(0x80 | ((code >> 12) & 0x3f));
buf[3] = (unsigned char)(0x80 | ((code >> 6) & 0x3f));
buf[4] = (unsigned char)(0x80 | (code & 0x3f));
return 5;
}
@@ -263,12 +263,12 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) {
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
if (code <= 0x7FFFFFFF) {
buf[0] = (unsigned char) (0xfc | (code >> 30));
buf[1] = (unsigned char) (0x80 | ((code >> 24) & 0x3f));
buf[2] = (unsigned char) (0x80 | ((code >> 18) & 0x3f));
buf[3] = (unsigned char) (0x80 | ((code >> 12) & 0x3f));
buf[4] = (unsigned char) (0x80 | ((code >> 6) & 0x3f));
buf[5] = (unsigned char) (0x80 | (code & 0x3f));
buf[0] = (unsigned char)(0xfc | (code >> 30));
buf[1] = (unsigned char)(0x80 | ((code >> 24) & 0x3f));
buf[2] = (unsigned char)(0x80 | ((code >> 18) & 0x3f));
buf[3] = (unsigned char)(0x80 | ((code >> 12) & 0x3f));
buf[4] = (unsigned char)(0x80 | ((code >> 6) & 0x3f));
buf[5] = (unsigned char)(0x80 | (code & 0x3f));
return 6;
}
@@ -412,8 +412,10 @@ static void *expand(void *p, int sz, int newsz) {
if (!s)
return 0;
memcpy(s, p, sz);
FREE(p);
if (p) {
memcpy(s, p, sz);
FREE(p);
}
return s;
}
@@ -423,8 +425,10 @@ static void **expand_ptrarr(void **p, int n) {
return 0;
s[n] = 0;
memcpy(s, p, n * sizeof(void *));
FREE(p);
if (p) {
memcpy(s, p, n * sizeof(void *));
FREE(p);
}
return s;
}
@@ -2212,6 +2216,7 @@ int toml_rtos(toml_raw_t src, char **ret) {
if (!src)
return -1;
// for strings, first char must be a s-quote or d-quote
int qchar = src[0];
int srclen = strlen(src);
if (!(qchar == '\'' || qchar == '"')) {
@@ -2220,12 +2225,14 @@ int toml_rtos(toml_raw_t src, char **ret) {
// triple quotes?
if (qchar == src[1] && qchar == src[2]) {
multiline = 1;
sp = src + 3;
sq = src + srclen - 3;
/* last 3 chars in src must be qchar */
if (!(sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar))
multiline = 1; // triple-quote implies multiline
sp = src + 3; // first char after quote
sq = src + srclen - 3; // first char of ending quote
if (!(sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) {
// last 3 chars in src must be qchar
return -1;
}
/* skip new line immediate after qchar */
if (sp[0] == '\n')
@@ -2234,13 +2241,18 @@ int toml_rtos(toml_raw_t src, char **ret) {
sp += 2;
} else {
sp = src + 1;
sq = src + srclen - 1;
/* last char in src must be qchar */
if (!(sp <= sq && *sq == qchar))
sp = src + 1; // first char after quote
sq = src + srclen - 1; // ending quote
if (!(sp <= sq && *sq == qchar)) {
/* last char in src must be qchar */
return -1;
}
}
// at this point:
// sp points to first valid char after quote.
// sq points to one char beyond last valid char.
// string len is (sq - sp).
if (qchar == '\'') {
*ret = norm_lit_str(sp, sq - sp, multiline, 0, 0);
} else {
+1 -1
View File
@@ -26,7 +26,7 @@
#define TOML_H
#ifdef _MSC_VER
#pragma warning(disable: 4996)
#pragma warning(disable : 4996)
#endif
#include <stdint.h>
+30 -22
View File
@@ -91,15 +91,16 @@ static void print_raw(const char *s) {
else
millisec[0] = 0;
if (ts.year && ts.hour) {
printf("{\"type\":\"datetime\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%"
printf("{\"type\":\"%s\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%"
"s%s\"}",
(ts.z ? "datetime" : "datetime-local"),
*ts.year, *ts.month, *ts.day, *ts.hour, *ts.minute, *ts.second,
millisec, (ts.z ? ts.z : ""));
} else if (ts.year) {
printf("{\"type\":\"date\",\"value\":\"%04d-%02d-%02d\"}", *ts.year,
printf("{\"type\":\"date-local\",\"value\":\"%04d-%02d-%02d\"}", *ts.year,
*ts.month, *ts.day);
} else if (ts.hour) {
printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d%s\"}", *ts.hour,
printf("{\"type\":\"time-local\",\"value\":\"%02d:%02d:%02d%s\"}", *ts.hour,
*ts.minute, *ts.second, millisec);
}
} else {
@@ -149,36 +150,43 @@ static void print_table_array(toml_array_t *curarr) {
}
static void print_array(toml_array_t *curarr) {
toml_array_t *arr;
const char *raw;
int i;
if (toml_array_kind(curarr) == 't') {
print_table_array(curarr);
return;
}
printf("{\"type\":\"array\",\"value\":[");
switch (toml_array_kind(curarr)) {
printf("[");
case 'v':
for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) {
printf("%s", i > 0 ? "," : "");
print_raw(raw);
}
break;
const char *raw;
toml_array_t *arr;
toml_table_t *tab;
case 'a':
for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) {
printf("%s", i > 0 ? "," : "");
const int n = toml_array_nelem(curarr);
for (int i = 0; i < n; i++) {
printf("%s", i > 0 ? "," : "");
if (0 != (arr = toml_array_at(curarr, i))) {
print_array(arr);
continue;
}
break;
default:
break;
if (0 != (tab = toml_table_at(curarr, i))) {
print_table(tab);
continue;
}
raw = toml_raw_at(curarr, i);
if (raw) {
print_raw(raw);
continue;
}
fflush(stdout);
fprintf(stderr, "ERROR: unable to decode value in array\n");
exit(1);
}
printf("]}");
printf("]");
}
static void cat(FILE *fp) {
+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
+317 -217
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);
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
-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"