summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/trans.h5
-rw-r--r--common/xrdp_client_info.h5
-rw-r--r--common/xrdp_tls.c233
-rw-r--r--libxrdp/xrdp_sec.c205
-rw-r--r--xorg/X11R7.6/rdp/rdp.h2
-rw-r--r--xorg/X11R7.6/rdp/rdpinput.c79
-rw-r--r--xorg/X11R7.6/rdp/rdpup.c2
-rw-r--r--xrdp/Makefile.am3
-rw-r--r--xrdp/xrdp_keyboard.ini105
9 files changed, 481 insertions, 158 deletions
diff --git a/common/trans.h b/common/trans.h
index c28d420b..c5fe49e6 100644
--- a/common/trans.h
+++ b/common/trans.h
@@ -23,7 +23,6 @@
#include "arch.h"
#include "parse.h"
-#include <openssl/ssl.h>
#define TRANS_MODE_TCP 1
#define TRANS_MODE_UNIX 2
@@ -72,8 +71,8 @@ struct trans
/* xrdp_tls */
struct xrdp_tls
{
- SSL *ssl;
- SSL_CTX *ctx;
+ void *ssl; /* SSL * */
+ void *ctx; /* SSL_CTX * */
char *cert;
char *key;
struct trans *trans;
diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h
index 59915f37..7e906c92 100644
--- a/common/xrdp_client_info.h
+++ b/common/xrdp_client_info.h
@@ -128,6 +128,11 @@ struct xrdp_client_info
char certificate[1024];
char key_file[1024];
+ /* X11 keyboard layout - inferred from keyboard type/subtype */
+ char model[16];
+ char layout[16];
+ char variant[16];
+
};
#endif
diff --git a/common/xrdp_tls.c b/common/xrdp_tls.c
index 48f6b827..589bb598 100644
--- a/common/xrdp_tls.c
+++ b/common/xrdp_tls.c
@@ -18,9 +18,17 @@
* transport layer security
*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/ssl.h>
+
+#include "os_calls.h"
#include "trans.h"
#include "ssl_calls.h"
+
/*****************************************************************************/
struct xrdp_tls *
APP_CC
@@ -38,6 +46,41 @@ xrdp_tls_create(struct trans *trans, const char *key, const char *cert)
return self;
}
+
+/*****************************************************************************/
+int APP_CC
+xrdp_tls_print_error(char *func, SSL *connection, int value)
+{
+ switch (SSL_get_error(connection, value))
+ {
+ case SSL_ERROR_ZERO_RETURN:
+ g_writeln("xrdp_tls_print_error: %s: Server closed TLS connection",
+ func);
+ return 1;
+
+ case SSL_ERROR_WANT_READ:
+ g_writeln("xrdp_tls_print_error: SSL_ERROR_WANT_READ");
+ return 0;
+
+ case SSL_ERROR_WANT_WRITE:
+ g_writeln("xrdp_tls_print_error: SSL_ERROR_WANT_WRITE");
+ return 0;
+
+ case SSL_ERROR_SYSCALL:
+ g_writeln("xrdp_tls_print_error: %s: I/O error", func);
+ return 1;
+
+ case SSL_ERROR_SSL:
+ g_writeln("xrdp_tls_print_error: %s: Failure in SSL library (protocol error?)",
+ func);
+ return 1;
+
+ default:
+ g_writeln("xrdp_tls_print_error: %s: Unknown error", func);
+ return 1;
+ }
+}
+
/*****************************************************************************/
int APP_CC
xrdp_tls_accept(struct xrdp_tls *self)
@@ -53,6 +96,7 @@ xrdp_tls_accept(struct xrdp_tls *self)
*/
options |= SSL_OP_NO_SSLv2;
+#if defined(SSL_OP_NO_COMPRESSION)
/**
* SSL_OP_NO_COMPRESSION:
*
@@ -63,6 +107,7 @@ xrdp_tls_accept(struct xrdp_tls *self)
* which is why we're disabling it.
*/
options |= SSL_OP_NO_COMPRESSION;
+#endif
/**
* SSL_OP_TLS_BLOCK_PADDING_BUG:
@@ -137,40 +182,6 @@ xrdp_tls_accept(struct xrdp_tls *self)
}
/*****************************************************************************/
int APP_CC
-xrdp_tls_print_error(char *func, SSL *connection, int value)
-{
- switch (SSL_get_error(connection, value))
- {
- case SSL_ERROR_ZERO_RETURN:
- g_writeln("xrdp_tls_print_error: %s: Server closed TLS connection",
- func);
- return 1;
-
- case SSL_ERROR_WANT_READ:
- g_writeln("xrdp_tls_print_error: SSL_ERROR_WANT_READ");
- return 0;
-
- case SSL_ERROR_WANT_WRITE:
- g_writeln("xrdp_tls_print_error: SSL_ERROR_WANT_WRITE");
- return 0;
-
- case SSL_ERROR_SYSCALL:
- g_writeln("xrdp_tls_print_error: %s: I/O error", func);
- return 1;
-
- case SSL_ERROR_SSL:
- g_writeln(
- "xrdp_tls_print_error: %s: Failure in SSL library (protocol error?)",
- func);
- return 1;
-
- default:
- g_writeln("xrdp_tls_print_error: %s: Unknown error", func);
- return 1;
- }
-}
-/*****************************************************************************/
-int APP_CC
xrdp_tls_disconnect(struct xrdp_tls *self)
{
int status = SSL_shutdown(self->ssl);
@@ -205,7 +216,7 @@ xrdp_tls_delete(struct xrdp_tls *self)
}
/*****************************************************************************/
int APP_CC
-xrdp_tls_read(struct xrdp_tls *tls, unsigned char *data, int length)
+xrdp_tls_read(struct xrdp_tls *tls, char *data, int length)
{
int status;
@@ -213,25 +224,25 @@ xrdp_tls_read(struct xrdp_tls *tls, unsigned char *data, int length)
switch (SSL_get_error(tls->ssl, status))
{
- case SSL_ERROR_NONE:
- break;
-
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- status = 0;
- break;
-
- default:
- xrdp_tls_print_error("SSL_read", tls->ssl, status);
- status = -1;
- break;
+ case SSL_ERROR_NONE:
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ status = 0;
+ break;
+
+ default:
+ xrdp_tls_print_error("SSL_read", tls->ssl, status);
+ status = -1;
+ break;
}
return status;
}
/*****************************************************************************/
int APP_CC
-xrdp_tls_write(struct xrdp_tls *tls, unsigned char *data, int length)
+xrdp_tls_write(struct xrdp_tls *tls, char *data, int length)
{
int status;
@@ -239,18 +250,18 @@ xrdp_tls_write(struct xrdp_tls *tls, unsigned char *data, int length)
switch (SSL_get_error(tls->ssl, status))
{
- case SSL_ERROR_NONE:
- break;
-
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- status = 0;
- break;
-
- default:
- xrdp_tls_print_error("SSL_write", tls->ssl, status);
- status = -1;
- break;
+ case SSL_ERROR_NONE:
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ status = 0;
+ break;
+
+ default:
+ xrdp_tls_print_error("SSL_write", tls->ssl, status);
+ status = -1;
+ break;
}
return status;
@@ -319,6 +330,58 @@ xrdp_tls_force_read_s(struct trans *self, struct stream *in_s, int size)
/*****************************************************************************/
int APP_CC
+xrdp_tls_send_waiting(struct trans *self, int block)
+{
+ struct stream *temp_s;
+ int bytes;
+ int sent;
+ int timeout;
+ int cont;
+
+ timeout = block ? 100 : 0;
+ cont = 1;
+ while (cont)
+ {
+ if (self->wait_s != 0)
+ {
+ temp_s = self->wait_s;
+ if (g_tcp_can_send(self->sck, timeout))
+ {
+ bytes = (int) (temp_s->end - temp_s->p);
+ sent = xrdp_tls_write(self->tls, temp_s->p, bytes);
+ if (sent > 0)
+ {
+ temp_s->p += sent;
+ if (temp_s->p >= temp_s->end)
+ {
+ self->wait_s = (struct stream *) (temp_s->next_packet);
+ free_stream(temp_s);
+ }
+ }
+ else if (sent == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ if (!g_tcp_last_error_would_block(self->sck))
+ {
+ return 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ break;
+ }
+ cont = block;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+int APP_CC
xrdp_tls_force_write_s(struct trans *self, struct stream *out_s)
{
int size;
@@ -382,54 +445,4 @@ xrdp_tls_force_write_s(struct trans *self, struct stream *out_s)
return 0;
}
-/*****************************************************************************/
-int APP_CC
-xrdp_tls_send_waiting(struct trans *self, int block)
-{
- struct stream *temp_s;
- int bytes;
- int sent;
- int timeout;
- int cont;
- timeout = block ? 100 : 0;
- cont = 1;
- while (cont)
- {
- if (self->wait_s != 0)
- {
- temp_s = self->wait_s;
- if (g_tcp_can_send(self->sck, timeout))
- {
- bytes = (int) (temp_s->end - temp_s->p);
- sent = xrdp_tls_write(self->tls, temp_s->p, bytes);
- if (sent > 0)
- {
- temp_s->p += sent;
- if (temp_s->p >= temp_s->end)
- {
- self->wait_s = (struct stream *) (temp_s->next_packet);
- free_stream(temp_s);
- }
- }
- else if (sent == 0)
- {
- return 1;
- }
- else
- {
- if (!g_tcp_last_error_would_block(self->sck))
- {
- return 1;
- }
- }
- }
- }
- else
- {
- break;
- }
- cont = block;
- }
- return 0;
-}
diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c
index 7ac68b14..5a63afc8 100644
--- a/libxrdp/xrdp_sec.c
+++ b/libxrdp/xrdp_sec.c
@@ -221,6 +221,210 @@ hex_str_to_bin(char *in, char *out, int out_len)
}
/*****************************************************************************/
+static void APP_CC
+xrdp_load_keyboard_layout(struct xrdp_client_info *client_info)
+{
+ int fd;
+ int index = 0;
+ int bytes;
+ struct list *names = (struct list *)NULL;
+ struct list *items = (struct list *)NULL;
+ struct list *values = (struct list *)NULL;
+ char *item = (char *)NULL;
+ char *value = (char *)NULL;
+ char *q = (char *)NULL;
+ char keyboard_cfg_file[256] = { 0 };
+ char rdp_layout[256] = { 0 };
+
+ LLOGLN(0, ("xrdp_load_keyboard_layout:"));
+ /* infer model/variant */
+ /* TODO specify different X11 keyboard models/variants */
+ g_memset(client_info->model, 0, sizeof(client_info->model));
+ g_memset(client_info->variant, 0, sizeof(client_info->variant));
+ g_strncpy(client_info->layout, "us", sizeof(client_info->layout) - 1);
+ if (client_info->keyboard_subtype == 3)
+ {
+ /* macintosh keyboard */
+ bytes = sizeof(client_info->variant);
+ g_strncpy(client_info->variant, "mac", bytes - 1);
+ }
+ else if (client_info->keyboard_subtype == 0)
+ {
+ /* default - standard subtype */
+ client_info->keyboard_subtype = 1;
+ }
+
+ g_snprintf(keyboard_cfg_file, 255, "%s/xrdp_keyboard.ini", XRDP_CFG_PATH);
+ LLOGLN(10, ("keyboard_cfg_file %s", keyboard_cfg_file));
+
+ fd = g_file_open(keyboard_cfg_file);
+
+ if (fd > 0)
+ {
+ int section_found = -1;
+ char section_rdp_layouts[256] = { 0 };
+ char section_layouts_map[256] = { 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 = (char *)list_get_item(names, index);
+ if (g_strncasecmp("default", q, 8) != 0)
+ {
+ int i;
+
+ file_read_section(fd, q, items, values);
+
+ for (i = 0; i < items->count; i++)
+ {
+ item = (char *)list_get_item(items, i);
+ value = (char *)list_get_item(values, i);
+ LLOGLN(10, ("xrdp_load_keyboard_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)
+ {
+ g_strncpy(section_rdp_layouts, value, 255);
+ }
+ }
+ else if (g_strcasecmp(item, "layouts_map") == 0)
+ {
+ if (section_found != -1 && section_found == index)
+ {
+ g_strncpy(section_layouts_map, value, 255);
+ }
+ }
+ else if (g_strcasecmp(item, "model") == 0)
+ {
+ if (section_found != -1 && section_found == index)
+ {
+ bytes = sizeof(client_info->model);
+ g_memset(client_info->model, 0, bytes);
+ g_strncpy(client_info->model, value, bytes - 1);
+ }
+ }
+ else if (g_strcasecmp(item, "variant") == 0)
+ {
+ if (section_found != -1 && section_found == index)
+ {
+ bytes = sizeof(client_info->variant);
+ g_memset(client_info->variant, 0, bytes);
+ g_strncpy(client_info->variant, value, bytes - 1);
+ }
+ }
+ else
+ {
+ /*
+ * mixing items from different sections will result in
+ * skipping over current section.
+ */
+ LLOGLN(10, ("xrdp_load_keyboard_layout: skipping "
+ "configuration item - %s, continuing to next "
+ "section", item));
+ break;
+ }
+ }
+
+ list_clear(items);
+ list_clear(values);
+ }
+ }
+
+ if (section_found == -1)
+ {
+ g_memset(section_rdp_layouts, 0, sizeof(char) * 256);
+ g_memset(section_layouts_map, 0, sizeof(char) * 256);
+ // read default section
+ file_read_section(fd, "default", items, values);
+ for (index = 0; index < items->count; index++)
+ {
+ item = (char *)list_get_item(items, index);
+ value = (char *)list_get_item(values, index);
+ if (g_strcasecmp(item, "rdp_layouts") == 0)
+ {
+ g_strncpy(section_rdp_layouts, value, 255);
+ }
+ else if (g_strcasecmp(item, "layouts_map") == 0)
+ {
+ g_strncpy(section_layouts_map, value, 255);
+ }
+ }
+ list_clear(items);
+ list_clear(values);
+ }
+
+ /* load the map */
+ file_read_section(fd, section_rdp_layouts, items, values);
+ for (index = 0; index < items->count; index++)
+ {
+ int rdp_layout_id;
+ item = (char *)list_get_item(items, index);
+ value = (char *)list_get_item(values, index);
+ rdp_layout_id = g_htoi(value);
+ if (rdp_layout_id == client_info->keylayout)
+ {
+ g_strncpy(rdp_layout, item, 255);
+ break;
+ }
+ }
+ list_clear(items);
+ list_clear(values);
+ file_read_section(fd, section_layouts_map, items, values);
+ for (index = 0; index < items->count; index++)
+ {
+ item = (char *)list_get_item(items, index);
+ value = (char *)list_get_item(values, index);
+ if (g_strcasecmp(item, rdp_layout) == 0)
+ {
+ bytes = sizeof(client_info->layout);
+ g_strncpy(client_info->layout, value, bytes - 1);
+ break;
+ }
+ }
+
+ list_delete(names);
+ list_delete(items);
+ list_delete(values);
+
+ LLOGLN(0, ("xrdp_load_keyboard_layout: model [%s] variant [%s] "
+ "layout [%s]", client_info->model, client_info->variant,
+ client_info->layout));
+ g_file_close(fd);
+ }
+ else
+ {
+ LLOGLN(0, ("xrdp_load_keyboard_layout: error opening %d",
+ keyboard_cfg_file));
+ }
+}
+
+/*****************************************************************************/
struct xrdp_sec *APP_CC
xrdp_sec_create(struct xrdp_rdp *owner, struct trans *trans)
{
@@ -1853,6 +2057,7 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self)
in_uint8s(s, 79);
in_uint32_le(s, client_info->keyboard_type);
in_uint32_le(s, client_info->keyboard_subtype);
+ xrdp_load_keyboard_layout(client_info);
s->p = s->data;
return 0;
}
diff --git a/xorg/X11R7.6/rdp/rdp.h b/xorg/X11R7.6/rdp/rdp.h
index 7bc2eb6c..00725d11 100644
--- a/xorg/X11R7.6/rdp/rdp.h
+++ b/xorg/X11R7.6/rdp/rdp.h
@@ -508,7 +508,7 @@ KbdAddEvent(int down, int param1, int param2, int param3, int param4);
void
KbdSync(int param1);
int
-rdpLoadLayout(int keylayout);
+rdpLoadLayout(struct xrdp_client_info *client_info);
/* rdpup.c */
int
diff --git a/xorg/X11R7.6/rdp/rdpinput.c b/xorg/X11R7.6/rdp/rdpinput.c
index 7fb20379..ef0bb929 100644
--- a/xorg/X11R7.6/rdp/rdpinput.c
+++ b/xorg/X11R7.6/rdp/rdpinput.c
@@ -282,7 +282,7 @@ rdpChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl *ctrl)
/******************************************************************************/
int
-rdpLoadLayout(int keylayout)
+rdpLoadLayout(struct xrdp_client_info *client_info)
{
XkbRMLVOSet set;
XkbSrvInfoPtr xkbi;
@@ -292,8 +292,10 @@ rdpLoadLayout(int keylayout)
KeyCode first_key;
CARD8 num_keys;
- LLOGLN(0, ("rdpLoadLayout: keylayout 0x%8.8x display %s",
- keylayout, display));
+ int keylayout = client_info->keylayout;
+
+ LLOGLN(0, ("rdpLoadLayout: keylayout 0x%8.8x variant %s display %s",
+ keylayout, client_info->variant, display));
memset(&set, 0, sizeof(set));
if (g_use_evdev)
{
@@ -303,42 +305,26 @@ rdpLoadLayout(int keylayout)
{
set.rules = "base";
}
+
set.model = "pc104";
set.layout = "us";
- switch (keylayout)
- {
- case 0x00000407: /* German */
- set.layout = "de";
- break;
- case 0x00000409: /* US */
- set.layout = "us";
- break;
- case 0x0000040C: /* French */
- set.layout = "fr";
- break;
- case 0x00000410: /* Italian */
- set.layout = "it";
- break;
- case 0x00000416: /* Portuguese (Brazilian ABNT) */
- set.model = "abnt2";
- set.layout = "br";
- break;
- case 0x00000419: /* Russian */
- set.layout = "ru";
- break;
- case 0x0000041D: /* Swedish */
- set.layout = "se";
- break;
- case 0x00000816: /* Portuguese */
- set.layout = "pt";
- break;
- default:
- LLOGLN(0, ("rdpLoadLayout: unknown keylayout 0x%8.8x", keylayout));
- break;
- }
set.variant = "";
set.options = "";
+ if (strlen(client_info->model) > 0)
+ {
+ set.model = client_info->model;
+ }
+ if (strlen(client_info->variant) > 0)
+ {
+ set.variant = client_info->variant;
+ }
+ if (strlen(client_info->layout) > 0)
+ {
+ set.layout = client_info->layout;
+ }
+
+ retry:
/* free some stuff so we can call InitKeyboardDeviceStruct again */
xkbi = g_keyboard->key->xkbInfo;
xkb = xkbi->desc;
@@ -355,21 +341,30 @@ rdpLoadLayout(int keylayout)
rdpChangeKeyboardControl))
{
LLOGLN(0, ("rdpLoadLayout: InitKeyboardDeviceStruct failed"));
+ return 1;
}
/* notify the X11 clients eg. X_ChangeKeyboardMapping */
keySyms = XkbGetCoreMap(g_keyboard);
- first_key = keySyms->minKeyCode;
- num_keys = (keySyms->maxKeyCode - keySyms->minKeyCode) + 1;
- XkbApplyMappingChange(g_keyboard, keySyms, first_key, num_keys,
- NULL, serverClient);
- for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
+ if (keySyms)
{
- if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key)
+ first_key = keySyms->minKeyCode;
+ num_keys = (keySyms->maxKeyCode - keySyms->minKeyCode) + 1;
+ XkbApplyMappingChange(g_keyboard, keySyms, first_key, num_keys,
+ NULL, serverClient);
+ for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
{
- XkbApplyMappingChange(pDev, keySyms, first_key, num_keys,
- NULL, serverClient);
+ if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key)
+ {
+ XkbApplyMappingChange(pDev, keySyms, first_key, num_keys,
+ NULL, serverClient);
+ }
}
+ } else
+ {
+ /* sometimes, variant doesn't support all layouts */
+ set.variant = "";
+ goto retry;
}
return 0;
diff --git a/xorg/X11R7.6/rdp/rdpup.c b/xorg/X11R7.6/rdp/rdpup.c
index e7f504ec..f25b390a 100644
--- a/xorg/X11R7.6/rdp/rdpup.c
+++ b/xorg/X11R7.6/rdp/rdpup.c
@@ -1117,7 +1117,7 @@ rdpup_process_msg(struct stream *s)
g_do_multimon = 0;
}
- rdpLoadLayout(g_rdpScreen.client_info.keylayout);
+ rdpLoadLayout(&(g_rdpScreen.client_info));
}
else if (msg_type == 105)
diff --git a/xrdp/Makefile.am b/xrdp/Makefile.am
index 96ec07f3..4fd9a689 100644
--- a/xrdp/Makefile.am
+++ b/xrdp/Makefile.am
@@ -65,7 +65,8 @@ xrdp_LDFLAGS = \
xrdpsysconfdir=$(sysconfdir)/xrdp
xrdpsysconf_DATA = \
- xrdp.ini
+ xrdp.ini \
+ xrdp_keyboard.ini
xrdppkgdatadir=$(datadir)/xrdp
diff --git a/xrdp/xrdp_keyboard.ini b/xrdp/xrdp_keyboard.ini
new file mode 100644
index 00000000..bd4e4e68
--- /dev/null
+++ b/xrdp/xrdp_keyboard.ini
@@ -0,0 +1,105 @@
+#
+# 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 readed for default section. It
+# is only as a place holder 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_de=0x00000407
+rdp_layout_fr=0x0000040C
+rdp_layout_it=0x00000410
+rdp_layout_jp=0x00000411
+rdp_layout_ru=0x00000419
+rdp_layout_se=0x0000041D
+rdp_layout_pt=0x00000816
+rdp_layout_br=0x00000416
+
+# <rdp layout name> = <X11 keyboard layout value>
+[default_layouts_map]
+rdp_layout_us=us
+rdp_layout_de=de
+rdp_layout_fr=fr
+rdp_layout_it=it
+rdp_layout_jp=jp
+rdp_layout_ru=ru
+rdp_layout_se=se
+rdp_layout_pt=pt
+rdp_layout_br=br(abnt2)
+
+# 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
+rdp_layouts=default_rdp_layouts
+layouts_map=default_layouts_map
+
+[rdp_layouts_map_mac]
+rdp_layout_us=us
+rdp_layout_de=de
+rdp_layout_fr=fr
+rdp_layout_jp=jp
+rdp_layout_it=it
+rdp_layout_ru=ru
+rdp_layout_se=se
+rdp_layout_pt=pt
+rdp_layout_br=br(abnt2)