Added option to remap scancodes
authorArmin Novak <armin.novak@thincast.com>
Wed, 28 Oct 2020 11:22:48 +0000 (12:22 +0100)
committerakallabeth <akallabeth@users.noreply.github.com>
Thu, 25 Feb 2021 08:51:41 +0000 (09:51 +0100)
(cherry picked from commit d7bf6553c558db64e5e3108b08f8ee1d394d1393)

client/Wayland/wlfreerdp.c
client/X11/xf_keyboard.c
client/common/cmdline.c
client/common/cmdline.h
include/freerdp/locale/keyboard.h
include/freerdp/settings.h
libfreerdp/common/settings_getters.c
libfreerdp/common/settings_str.c
libfreerdp/core/test/settings_property_lists.h
libfreerdp/locale/keyboard.c

index 96764ee..aca7342 100644 (file)
@@ -270,7 +270,8 @@ static BOOL wl_post_connect(freerdp* instance)
        instance->update->BeginPaint = wl_begin_paint;
        instance->update->EndPaint = wl_end_paint;
        instance->update->DesktopResize = wl_resize_display;
-       freerdp_keyboard_init(instance->context->settings->KeyboardLayout);
+       freerdp_keyboard_init_ex(instance->context->settings->KeyboardLayout,
+                                instance->context->settings->KeyboardRemappingList);
 
        if (!(context->disp = wlf_disp_new(context)))
                return FALSE;
index 8717277..4c05e80 100644 (file)
@@ -115,7 +115,8 @@ BOOL xf_keyboard_init(xfContext* xfc)
 {
        xf_keyboard_clear(xfc);
        xfc->KeyboardLayout = xfc->context.settings->KeyboardLayout;
-       xfc->KeyboardLayout = freerdp_keyboard_init(xfc->KeyboardLayout);
+       xfc->KeyboardLayout =
+           freerdp_keyboard_init_ex(xfc->KeyboardLayout, xfc->context.settings->KeyboardRemappingList);
        xfc->context.settings->KeyboardLayout = xfc->KeyboardLayout;
 
        if (xfc->modifierMap)
index 3f786ec..f17ba66 100644 (file)
@@ -1992,6 +1992,11 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
 
                        settings->KeyboardLayout = (UINT32)val;
                }
+               CommandLineSwitchCase(arg, "kbd-remap")
+               {
+                       if (!copy_value(arg->Value, &settings->KeyboardRemappingList))
+                               return COMMAND_LINE_ERROR_MEMORY;
+               }
                CommandLineSwitchCase(arg, "kbd-lang")
                {
                        LONGLONG val;
index 065cfc5..8ccc4f9 100644 (file)
@@ -210,6 +210,9 @@ static const COMMAND_LINE_ARGUMENT_A args[] = {
          "List keyboard layouts" },
        { "kbd-lang-list", COMMAND_LINE_VALUE_OPTIONAL | COMMAND_LINE_PRINT, NULL, NULL, NULL, -1, NULL,
          "List keyboard languages" },
+       { "kbd-remap", COMMAND_LINE_VALUE_REQUIRED,
+         "List of <key>=<value>,... pairs to remap scancodes", NULL, NULL, -1, NULL,
+         "Keyboard scancode remapping" },
        { "kbd-subtype", COMMAND_LINE_VALUE_REQUIRED, "<id>", NULL, NULL, -1, NULL,
          "Keyboard subtype" },
        { "kbd-type", COMMAND_LINE_VALUE_REQUIRED, "<id>", NULL, NULL, -1, NULL, "Keyboard type" },
index 3f48046..ed2e6be 100644 (file)
@@ -220,6 +220,8 @@ extern "C"
 #endif
 
        FREERDP_API DWORD freerdp_keyboard_init(DWORD keyboardLayoutId);
+       FREERDP_API DWORD freerdp_keyboard_init_ex(DWORD keyboardLayoutId,
+                                                  const char* keyboardRemappingList);
        FREERDP_API RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types);
        FREERDP_API void freerdp_keyboard_layouts_free(RDP_KEYBOARD_LAYOUT* layouts);
        FREERDP_API const char* freerdp_keyboard_get_layout_name_from_id(DWORD keyboardLayoutId);
index cc89579..deddb1c 100644 (file)
@@ -800,6 +800,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
 #define FreeRDP_BitmapCacheV2CellInfo (2502)
 #define FreeRDP_ColorPointerFlag (2560)
 #define FreeRDP_PointerCacheSize (2561)
+#define FreeRDP_KeyboardRemappingList (2622)
 #define FreeRDP_KeyboardCodePage (2623)
 #define FreeRDP_KeyboardLayout (2624)
 #define FreeRDP_KeyboardType (2625)
@@ -1333,9 +1334,10 @@ struct rdp_settings
        /* Pointer Capabilities */
        ALIGN64 BOOL ColorPointerFlag;   /* 2560 */
        ALIGN64 UINT32 PointerCacheSize; /* 2561 */
-       UINT64 padding2624[2623 - 2562]; /* 2562 */
+       UINT64 padding2624[2622 - 2562]; /* 2562 */
 
        /* Input Capabilities */
+       ALIGN64 char* KeyboardRemappingList; /* 2622 */
        ALIGN64 UINT32 KeyboardCodePage;    /* 2623 */
        ALIGN64 UINT32 KeyboardLayout;      /* 2624 */
        ALIGN64 UINT32 KeyboardType;        /* 2625 */
index 2e49b89..6842ae8 100644 (file)
@@ -2247,6 +2247,9 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id)
                case FreeRDP_KerberosRealm:
                        return settings->KerberosRealm;
 
+               case FreeRDP_KeyboardRemappingList:
+                       return settings->KeyboardRemappingList;
+
                case FreeRDP_NtlmSamFile:
                        return settings->NtlmSamFile;
 
@@ -2551,6 +2554,12 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char*
                        settings->KerberosRealm = (val ? _strdup(val) : NULL);
                        return (!val || settings->KerberosRealm != NULL);
 
+               case FreeRDP_KeyboardRemappingList:
+                       if (cleanup)
+                               free(settings->KeyboardRemappingList);
+                       settings->KeyboardRemappingList = (val ? _strdup(val) : NULL);
+                       return (!val || settings->KeyboardRemappingList != NULL);
+
                case FreeRDP_NtlmSamFile:
                        if (cleanup)
                                free(settings->NtlmSamFile);
index 699c94b..caa2b50 100644 (file)
@@ -324,6 +324,7 @@ static const struct settings_str_entry settings_map[] = {
        { FreeRDP_ImeFileName, 7, "FreeRDP_ImeFileName" },
        { FreeRDP_KerberosKdc, 7, "FreeRDP_KerberosKdc" },
        { FreeRDP_KerberosRealm, 7, "FreeRDP_KerberosRealm" },
+       { FreeRDP_KeyboardRemappingList, 7, "FreeRDP_KeyboardRemappingList" },
        { FreeRDP_NtlmSamFile, 7, "FreeRDP_NtlmSamFile" },
        { FreeRDP_Password, 7, "FreeRDP_Password" },
        { FreeRDP_PasswordHash, 7, "FreeRDP_PasswordHash" },
index c44018e..77ba237 100644 (file)
@@ -333,6 +333,7 @@ static const size_t string_list_indices[] = {
        FreeRDP_ImeFileName,
        FreeRDP_KerberosKdc,
        FreeRDP_KerberosRealm,
+       FreeRDP_KeyboardRemappingList,
        FreeRDP_NtlmSamFile,
        FreeRDP_Password,
        FreeRDP_PasswordHash,
index 4ee955d..eca0d63 100644 (file)
@@ -42,8 +42,9 @@
 
 #endif
 
-DWORD VIRTUAL_SCANCODE_TO_X11_KEYCODE[256][2];
-DWORD X11_KEYCODE_TO_VIRTUAL_SCANCODE[256];
+static DWORD VIRTUAL_SCANCODE_TO_X11_KEYCODE[256][2] = { 0 };
+static DWORD X11_KEYCODE_TO_VIRTUAL_SCANCODE[256] = { 0 };
+static DWORD REMAPPING_TABLE[0x10000] = { 0 };
 
 int freerdp_detect_keyboard(DWORD* keyboardLayoutId)
 {
@@ -154,13 +155,60 @@ DWORD freerdp_keyboard_init(DWORD keyboardLayoutId)
        return keyboardLayoutId;
 }
 
+DWORD freerdp_keyboard_init_ex(DWORD keyboardLayoutId, const char* keyboardRemappingList)
+{
+       DWORD rc = freerdp_keyboard_init(keyboardLayoutId);
+
+       memset(REMAPPING_TABLE, 0, sizeof(REMAPPING_TABLE));
+       if (keyboardRemappingList)
+       {
+               char* copy = _strdup(keyboardRemappingList);
+               char* context = NULL;
+               char* token;
+               if (!copy)
+                       goto fail;
+               token = strtok_s(copy, ",", &context);
+               while (token)
+               {
+                       DWORD key, value;
+                       int rc = sscanf(token, "%" PRIu32 "=%" PRIu32, &key, &value);
+                       if (rc != 2)
+                               rc = sscanf(token, "%" PRIx32 "=%" PRIx32 "", &key, &value);
+                       if (rc != 2)
+                               rc = sscanf(token, "%" PRIu32 "=%" PRIx32, &key, &value);
+                       if (rc != 2)
+                               rc = sscanf(token, "%" PRIx32 "=%" PRIu32, &key, &value);
+                       if (rc != 2)
+                               goto fail;
+                       if (key >= ARRAYSIZE(REMAPPING_TABLE))
+                               goto fail;
+                       REMAPPING_TABLE[key] = value;
+                       token = strtok_s(NULL, ",", &context);
+               }
+       fail:
+               free(copy);
+       }
+       return rc;
+}
+
 DWORD freerdp_keyboard_get_rdp_scancode_from_x11_keycode(DWORD keycode)
 {
-       DEBUG_KBD("x11 keycode: %02" PRIX32 " -> rdp code: %02" PRIX8 "%s", keycode,
-                 RDP_SCANCODE_CODE(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode]),
-                 RDP_SCANCODE_EXTENDED(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode]) ? " extended" : "");
+       const DWORD scancode = X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode];
+       const DWORD remapped = REMAPPING_TABLE[scancode];
+       DEBUG_KBD("x11 keycode: %02" PRIX32 " -> rdp code: [%04" PRIx16 "] %02" PRIX8 "%s", keycode,
+                 scancode, RDP_SCANCODE_CODE(scancode),
+                 RDP_SCANCODE_EXTENDED(scancode) ? " extended" : "");
 
-       return X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode];
+       if (remapped != 0)
+       {
+               DEBUG_KBD("remapped scancode: [%04" PRIx16 "] %02" PRIX8 "[%s] -> [%04" PRIx16 "] %02" PRIX8
+                         "[%s]",
+                         scancode, RDP_SCANCODE_CODE(scancode),
+                         RDP_SCANCODE_EXTENDED(scancode) ? " extended" : "", remapped,
+                         RDP_SCANCODE_CODE(remapped), RDP_SCANCODE_EXTENDED(remapped) ? " extended" : "");
+               return remapped;
+       }
+       return scancode;
 }
 
 DWORD freerdp_keyboard_get_x11_keycode_from_rdp_scancode(DWORD scancode, BOOL extended)