From 6721fd9d0c857ec1891bf7382e39ee19628b232e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 19 Jul 2024 14:26:31 +0200 Subject: [PATCH] [locale,keyboard] add keyboard id from file Add the option to load keyboard layouts from a JSON file. --- libfreerdp/locale/CMakeLists.txt | 11 + libfreerdp/locale/KeyboardLayoutMap.json | 1118 ++++++++++++++++++++++ libfreerdp/locale/keyboard_layout.c | 779 +++++++++++++-- 3 files changed, 1811 insertions(+), 97 deletions(-) create mode 100644 libfreerdp/locale/KeyboardLayoutMap.json diff --git a/libfreerdp/locale/CMakeLists.txt b/libfreerdp/locale/CMakeLists.txt index c190b9f60..7b6bab326 100644 --- a/libfreerdp/locale/CMakeLists.txt +++ b/libfreerdp/locale/CMakeLists.txt @@ -42,6 +42,17 @@ set(APPLE_SRCS keyboard_apple.c keyboard_apple.h) +include(CMakeDependentOption) +cmake_dependent_option(WITH_KEYBOARD_LAYOUT_FROM_FILE "Use keyboard definitions from JSON file" OFF WITH_WINPR_JSON OFF) +if (WITH_KEYBOARD_LAYOUT_FROM_FILE) + set(FREERDP_RESOURCE_ROOT ${CMAKE_INSTALL_FULL_DATAROOTDIR}/${PRODUCT}) + freerdp_definition_add(-DFREERDP_RESOURCE_ROOT="${FREERDP_RESOURCE_ROOT}") + freerdp_definition_add(-DWITH_KEYBOARD_LAYOUT_FROM_FILE) + + install(FILES KeyboardLayoutMap.json DESTINATION ${FREERDP_RESOURCE_ROOT}) +endif() + + if(CMAKE_SYSTEM_NAME MATCHES Solaris) set(WITH_SUN true) endif() diff --git a/libfreerdp/locale/KeyboardLayoutMap.json b/libfreerdp/locale/KeyboardLayoutMap.json new file mode 100644 index 000000000..b65613ee0 --- /dev/null +++ b/libfreerdp/locale/KeyboardLayoutMap.json @@ -0,0 +1,1118 @@ +{ + "KeyboardLayouts": [ + { + "code": 1052.0, + "name": "Albanian" + }, + { + "code": 1025.0, + "name": "Arabic (101)" + }, + { + "code": 66561.0, + "name": "Arabic (102)" + }, + { + "code": 132097.0, + "name": "Arabic (102) AZERTY" + }, + { + "code": 1067.0, + "name": "Armenian Eastern" + }, + { + "code": 132139.0, + "name": "Armenian Phonetic" + }, + { + "code": 197675.0, + "name": "Armenian Typewriter" + }, + { + "code": 66603.0, + "name": "Armenian Western" + }, + { + "code": 1101.0, + "name": "Assamese - Inscript" + }, + { + "code": 66604.0, + "name": "Azerbaijani (Standard)" + }, + { + "code": 2092.0, + "name": "Azerbaijani Cyrillic" + }, + { + "code": 1068.0, + "name": "Azerbaijani Latin" + }, + { + "code": 1133.0, + "name": "Bashkir" + }, + { + "code": 1059.0, + "name": "Belarusian" + }, + { + "code": 67596.0, + "name": "Belgian (Comma)" + }, + { + "code": 2067.0, + "name": "Belgian (Period)" + }, + { + "code": 2060.0, + "name": "Belgian French" + }, + { + "code": 1093.0, + "name": "Bangla (Bangladesh)" + }, + { + "code": 132165.0, + "name": "Bangla (India)" + }, + { + "code": 66629.0, + "name": "Bangla (India - Legacy)" + }, + { + "code": 8218.0, + "name": "Bosnian (Cyrillic)" + }, + { + "code": 723968.0, + "name": "Buginese" + }, + { + "code": 197634.0, + "name": "Bulgarian" + }, + { + "code": 66562.0, + "name": "Bulgarian (Latin)" + }, + { + "code": 132098.0, + "name": "Bulgarian (phonetic layout)" + }, + { + "code": 263170.0, + "name": "Bulgarian (phonetic traditional)" + }, + { + "code": 1026.0, + "name": "Bulgarian (Typewriter)" + }, + { + "code": 4105.0, + "name": "Canadian French" + }, + { + "code": 3084.0, + "name": "Canadian French (Legacy)" + }, + { + "code": 69641.0, + "name": "Canadian Multilingual Standard" + }, + { + "code": 2143.0, + "name": "Central Atlas Tamazight" + }, + { + "code": 1065.0, + "name": "Central Kurdish" + }, + { + "code": 1116.0, + "name": "Cherokee Nation" + }, + { + "code": 66652.0, + "name": "Cherokee Nation Phonetic" + }, + { + "code": 2052.0, + "name": "Chinese (Simplified) - US Keyboard" + }, + { + "code": 1028.0, + "name": "Chinese (Traditional) - US Keyboard" + }, + { + "code": 3076.0, + "name": "Chinese (Traditional, Hong Kong S.A.R.)" + }, + { + "code": 5124.0, + "name": "Chinese (Traditional Macao S.A.R.) US Keyboard" + }, + { + "code": 4100.0, + "name": "Chinese (Simplified, Singapore) - US keyboard" + }, + { + "code": 1050.0, + "name": "Croatian" + }, + { + "code": 1029.0, + "name": "Czech" + }, + { + "code": 66565.0, + "name": "Czech (QWERTY)" + }, + { + "code": 132101.0, + "name": "Czech Programmers" + }, + { + "code": 1030.0, + "name": "Danish" + }, + { + "code": 1081.0, + "name": "Devanagari-INSCRIPT" + }, + { + "code": 1125.0, + "name": "Divehi Phonetic" + }, + { + "code": 66661.0, + "name": "Divehi Typewriter" + }, + { + "code": 1043.0, + "name": "Dutch" + }, + { + "code": 3153.0, + "name": "Dzongkha" + }, + { + "code": 1061.0, + "name": "Estonian" + }, + { + "code": 1080.0, + "name": "Faeroese" + }, + { + "code": 1035.0, + "name": "Finnish" + }, + { + "code": 67643.0, + "name": "Finnish with Sami" + }, + { + "code": 1036.0, + "name": "French" + }, + { + "code": 1182720.0, + "name": "Futhark" + }, + { + "code": 1079.0, + "name": "Georgian" + }, + { + "code": 132151.0, + "name": "Georgian (Ergonomic)" + }, + { + "code": 66615.0, + "name": "Georgian (QWERTY)" + }, + { + "code": 197687.0, + "name": "Georgian Ministry of Education and Science Schools" + }, + { + "code": 263223.0, + "name": "Georgian (Old Alphabets)" + }, + { + "code": 1031.0, + "name": "German" + }, + { + "code": 66567.0, + "name": "German (IBM)" + }, + { + "code": 789504.0, + "name": "Gothic" + }, + { + "code": 1032.0, + "name": "Greek" + }, + { + "code": 66568.0, + "name": "Greek (220)" + }, + { + "code": 197640.0, + "name": "Greek (220) Latin" + }, + { + "code": 132104.0, + "name": "Greek (319)" + }, + { + "code": 263176.0, + "name": "Greek (319) Latin" + }, + { + "code": 328712.0, + "name": "Greek Latin" + }, + { + "code": 394248.0, + "name": "Greek Polytonic" + }, + { + "code": 1135.0, + "name": "Greenlandic" + }, + { + "code": 1140.0, + "name": "Guarani" + }, + { + "code": 1095.0, + "name": "Gujarati" + }, + { + "code": 1128.0, + "name": "Hausa" + }, + { + "code": 1037.0, + "name": "Hebrew" + }, + { + "code": 66617.0, + "name": "Hindi Traditional" + }, + { + "code": 1038.0, + "name": "Hungarian" + }, + { + "code": 66574.0, + "name": "Hungarian 101-key" + }, + { + "code": 1039.0, + "name": "Icelandic" + }, + { + "code": 1136.0, + "name": "Igbo" + }, + { + "code": 16393.0, + "name": "India" + }, + { + "code": 2141.0, + "name": "Inuktitut - Latin" + }, + { + "code": 66653.0, + "name": "Inuktitut - Naqittaut" + }, + { + "code": 6153.0, + "name": "Irish" + }, + { + "code": 1040.0, + "name": "Italian" + }, + { + "code": 66576.0, + "name": "Italian (142)" + }, + { + "code": 1041.0, + "name": "Japanese" + }, + { + "code": 1117184.0, + "name": "Javanese" + }, + { + "code": 1099.0, + "name": "Kannada" + }, + { + "code": 1087.0, + "name": "Kazakh" + }, + { + "code": 1107.0, + "name": "Khmer" + }, + { + "code": 66643.0, + "name": "Khmer (NIDA)" + }, + { + "code": 1042.0, + "name": "Korean" + }, + { + "code": 1088.0, + "name": "Kyrgyz Cyrillic" + }, + { + "code": 1108.0, + "name": "Lao" + }, + { + "code": 2058.0, + "name": "Latin American" + }, + { + "code": 132134.0, + "name": "Latvian (Standard)" + }, + { + "code": 66598.0, + "name": "Latvian (Legacy)" + }, + { + "code": 461824.0, + "name": "Lisu (Basic)" + }, + { + "code": 527360.0, + "name": "Lisu (Standard)" + }, + { + "code": 66599.0, + "name": "Lithuanian" + }, + { + "code": 1063.0, + "name": "Lithuanian IBM" + }, + { + "code": 132135.0, + "name": "Lithuanian Standard" + }, + { + "code": 1134.0, + "name": "Luxembourgish" + }, + { + "code": 1071.0, + "name": "Macedonia (FYROM)" + }, + { + "code": 66607.0, + "name": "Macedonia (FYROM) - Standard" + }, + { + "code": 1100.0, + "name": "Malayalam" + }, + { + "code": 1082.0, + "name": "Maltese 47-Key" + }, + { + "code": 66618.0, + "name": "Maltese 48-key" + }, + { + "code": 1153.0, + "name": "Maori" + }, + { + "code": 1102.0, + "name": "Marathi" + }, + { + "code": 2128.0, + "name": "Mongolian (Mongolian Script - Legacy)" + }, + { + "code": 133200.0, + "name": "Mongolian (Mongolian Script - Standard)" + }, + { + "code": 1104.0, + "name": "Mongolian Cyrillic" + }, + { + "code": 68608.0, + "name": "Myanmar" + }, + { + "code": 592896.0, + "name": "N'ko" + }, + { + "code": 1121.0, + "name": "Nepali" + }, + { + "code": 134144.0, + "name": "New Tai Lue" + }, + { + "code": 1044.0, + "name": "Norwegian" + }, + { + "code": 1083.0, + "name": "Norwegian with Sami" + }, + { + "code": 1096.0, + "name": "Odia" + }, + { + "code": 855040.0, + "name": "Ol Chiki" + }, + { + "code": 986112.0, + "name": "Old Italic" + }, + { + "code": 920576.0, + "name": "Osmanya" + }, + { + "code": 1123.0, + "name": "Pashto (Afghanistan)" + }, + { + "code": 1065.0, + "name": "Persian" + }, + { + "code": 328745.0, + "name": "Persian (Standard)" + }, + { + "code": 658432.0, + "name": "Phags-pa" + }, + { + "code": 66581.0, + "name": "Polish (214)" + }, + { + "code": 1045.0, + "name": "Polish (Programmers)" + }, + { + "code": 2070.0, + "name": "Portuguese" + }, + { + "code": 1046.0, + "name": "Portuguese (Brazilian ABNT)" + }, + { + "code": 66582.0, + "name": "Portuguese (Brazilian ABNT2)" + }, + { + "code": 1094.0, + "name": "Punjabi" + }, + { + "code": 1048.0, + "name": "Romanian (Legacy)" + }, + { + "code": 132120.0, + "name": "Romanian (Programmers)" + }, + { + "code": 66584.0, + "name": "Romanian (Standard)" + }, + { + "code": 1049.0, + "name": "Russian" + }, + { + "code": 132121.0, + "name": "Russian - Mnemonic" + }, + { + "code": 66585.0, + "name": "Russian (Typewriter)" + }, + { + "code": 1157.0, + "name": "Sakha" + }, + { + "code": 133179.0, + "name": "Sami Extended Finland-Sweden" + }, + { + "code": 66619.0, + "name": "Sami Extended Norway" + }, + { + "code": 71689.0, + "name": "Scottish Gaelic" + }, + { + "code": 3098.0, + "name": "Serbian (Cyrillic)" + }, + { + "code": 2074.0, + "name": "Serbian (Latin)" + }, + { + "code": 1132.0, + "name": "Sesotho sa Leboa" + }, + { + "code": 1074.0, + "name": "Setswana" + }, + { + "code": 1115.0, + "name": "Sinhala" + }, + { + "code": 66651.0, + "name": "Sinhala - wij 9" + }, + { + "code": 1051.0, + "name": "Slovak" + }, + { + "code": 66587.0, + "name": "Slovak (QWERTY)" + }, + { + "code": 1060.0, + "name": "Slovenian" + }, + { + "code": 1051648.0, + "name": "Sora" + }, + { + "code": 66606.0, + "name": "Sorbian Extended" + }, + { + "code": 132142.0, + "name": "Sorbian Standard" + }, + { + "code": 1070.0, + "name": "Sorbian Standard (Legacy)" + }, + { + "code": 1034.0, + "name": "Spanish" + }, + { + "code": 66570.0, + "name": "Spanish Variation" + }, + { + "code": 1053.0, + "name": "Swedish" + }, + { + "code": 2107.0, + "name": "Swedish with Sami" + }, + { + "code": 4108.0, + "name": "Swiss French" + }, + { + "code": 2055.0, + "name": "Swiss German" + }, + { + "code": 1114.0, + "name": "Syriac" + }, + { + "code": 66650.0, + "name": "Syriac Phonetic" + }, + { + "code": 199680.0, + "name": "Tai Le" + }, + { + "code": 1064.0, + "name": "Tajik" + }, + { + "code": 1097.0, + "name": "Tamil" + }, + { + "code": 66628.0, + "name": "Tatar" + }, + { + "code": 1092.0, + "name": "Tatar (Legacy)" + }, + { + "code": 1098.0, + "name": "Telugu" + }, + { + "code": 1054.0, + "name": "Thai Kedmanee" + }, + { + "code": 132126.0, + "name": "Thai Kedmanee (non-ShiftLock)" + }, + { + "code": 66590.0, + "name": "Thai Pattachote" + }, + { + "code": 197662.0, + "name": "Thai Pattachote (non-ShiftLock)" + }, + { + "code": 66641.0, + "name": "Tibetan (PRC - Standard)" + }, + { + "code": 1105.0, + "name": "Tibetan (PRC - Legacy)" + }, + { + "code": 330752.0, + "name": "Tifinagh (Basic)" + }, + { + "code": 396288.0, + "name": "Tifinagh (Full)" + }, + { + "code": 66591.0, + "name": "Turkish F" + }, + { + "code": 1055.0, + "name": "Turkish Q" + }, + { + "code": 1090.0, + "name": "Turkmen" + }, + { + "code": 66568.0, + "name": "Uyghur" + }, + { + "code": 1152.0, + "name": "Uyghur (Legacy)" + }, + { + "code": 1058.0, + "name": "Ukrainian" + }, + { + "code": 132130.0, + "name": "Ukrainian (Enhanced)" + }, + { + "code": 2057.0, + "name": "United Kingdom" + }, + { + "code": 1106.0, + "name": "United Kingdom Extended" + }, + { + "code": 66569.0, + "name": "United States - Dvorak" + }, + { + "code": 132105.0, + "name": "United States - International" + }, + { + "code": 197641.0, + "name": "United States-Dvorak for left hand" + }, + { + "code": 263177.0, + "name": "United States-Dvorak for right hand" + }, + { + "code": 1033.0, + "name": "United States - English" + }, + { + "code": 1056.0, + "name": "Urdu" + }, + { + "code": 66688.0, + "name": "Uyghur" + }, + { + "code": 2115.0, + "name": "Uzbek Cyrillic" + }, + { + "code": 1066.0, + "name": "Vietnamese" + }, + { + "code": 1160.0, + "name": "Wolof" + }, + { + "code": 1157.0, + "name": "Yakut" + }, + { + "code": 1130.0, + "name": "Yoruba" + } + ], + "KeyboardVariants": [ + { + "code": 66561.0, + "id": 40.0, + "name": "Arabic (102)" + }, + { + "code": 66562.0, + "id": 4.0, + "name": "Bulgarian (Latin)" + }, + { + "code": 66565.0, + "id": 5.0, + "name": "Czech (QWERTY)" + }, + { + "code": 66567.0, + "id": 18.0, + "name": "German (IBM)" + }, + { + "code": 66568.0, + "id": 22.0, + "name": "Greek (220)" + }, + { + "code": 66569.0, + "id": 2.0, + "name": "United States-Dvorak" + }, + { + "code": 66570.0, + "id": 134.0, + "name": "Spanish Variation" + }, + { + "code": 66574.0, + "id": 6.0, + "name": "Hungarian 101-key" + }, + { + "code": 66576.0, + "id": 3.0, + "name": "Italian (142)" + }, + { + "code": 66581.0, + "id": 7.0, + "name": "Polish (214)" + }, + { + "code": 66582.0, + "id": 29.0, + "name": "Portuguese (Brazilian ABNT2)" + }, + { + "code": 66585.0, + "id": 8.0, + "name": "Russian (Typewriter)" + }, + { + "code": 66587.0, + "id": 19.0, + "name": "Slovak (QWERTY)" + }, + { + "code": 66590.0, + "id": 33.0, + "name": "Thai Pattachote" + }, + { + "code": 66591.0, + "id": 20.0, + "name": "Turkish F" + }, + { + "code": 66598.0, + "id": 21.0, + "name": "Latvian (QWERTY)" + }, + { + "code": 66599.0, + "id": 39.0, + "name": "Lithuanian" + }, + { + "code": 66603.0, + "id": 37.0, + "name": "Armenian Western" + }, + { + "code": 66617.0, + "id": 12.0, + "name": "Hindi Traditional" + }, + { + "code": 66618.0, + "id": 43.0, + "name": "Maltese 48-key" + }, + { + "code": 66619.0, + "id": 44.0, + "name": "Sami Extended Norway" + }, + { + "code": 66629.0, + "id": 42.0, + "name": "Bengali (Inscript)" + }, + { + "code": 66650.0, + "id": 14.0, + "name": "Syriac Phonetic" + }, + { + "code": 66661.0, + "id": 13.0, + "name": "Divehi Typewriter" + }, + { + "code": 67596.0, + "id": 30.0, + "name": "Belgian (Comma)" + }, + { + "code": 67643.0, + "id": 45.0, + "name": "Finnish with Sami" + }, + { + "code": 69641.0, + "id": 32.0, + "name": "Canadian Multilingual Standard" + }, + { + "code": 71689.0, + "id": 38.0, + "name": "Gaelic" + }, + { + "code": 132097.0, + "id": 41.0, + "name": "Arabic (102) AZERTY" + }, + { + "code": 132101.0, + "id": 10.0, + "name": "Czech Programmers" + }, + { + "code": 132104.0, + "id": 24.0, + "name": "Greek (319)" + }, + { + "code": 132105.0, + "id": 1.0, + "name": "United States-International" + }, + { + "code": 132126.0, + "id": 34.0, + "name": "Thai Kedmanee (non-ShiftLock)" + }, + { + "code": 133179.0, + "id": 46.0, + "name": "Sami Extended Finland-Sweden" + }, + { + "code": 197640.0, + "id": 23.0, + "name": "Greek (220) Latin" + }, + { + "code": 197641.0, + "id": 26.0, + "name": "United States-Dvorak for left hand" + }, + { + "code": 197662.0, + "id": 35.0, + "name": "Thai Pattachote (non-ShiftLock)" + }, + { + "code": 263176.0, + "id": 17.0, + "name": "Greek (319) Latin" + }, + { + "code": 263177.0, + "id": 27.0, + "name": "United States-Dvorak for right hand" + }, + { + "code": 422970377.0, + "id": 28.0, + "name": "United States-Programmer Dvorak" + }, + { + "code": 328712.0, + "id": 25.0, + "name": "Greek Latin" + }, + { + "code": 328713.0, + "id": 11.0, + "name": "US English Table for IBM Arabic 238_L" + }, + { + "code": 394248.0, + "id": 31.0, + "name": "Greek Polytonic" + }, + { + "code": 2684355596.0, + "id": 192.0, + "name": "French Bépo" + }, + { + "code": 2952791047.0, + "id": 192.0, + "name": "German Neo" + } + ], + "KeyboardIme": [ + { + "code": 3758162948.0, + "file": "phon.ime", + "name": "Chinese (Traditional) - Phonetic" + }, + { + "code": 3758162961.0, + "file": "imjp81.ime", + "name": "Japanese Input System (MS-IME2002)" + }, + { + "code": 3758162962.0, + "file": "imekr61.ime", + "name": "Korean Input System (IME 2000)" + }, + { + "code": 3758163972.0, + "file": "winpy.ime", + "name": "Chinese (Simplified) - QuanPin" + }, + { + "code": 3758228484.0, + "file": "chajei.ime", + "name": "Chinese (Traditional) - ChangJie" + }, + { + "code": 3758229508.0, + "file": "winsp.ime", + "name": "Chinese (Simplified) - ShuangPin" + }, + { + "code": 3758294020.0, + "file": "quick.ime", + "name": "Chinese (Traditional) - Quick" + }, + { + "code": 3758295044.0, + "file": "winzm.ime", + "name": "Chinese (Simplified) - ZhengMa" + }, + { + "code": 3758359556.0, + "file": "winime.ime", + "name": "Chinese (Traditional) - Big5 Code" + }, + { + "code": 3758425092.0, + "file": "winar30.ime", + "name": "Chinese (Traditional) - Array" + }, + { + "code": 3758426116.0, + "file": "wingb.ime", + "name": "Chinese (Simplified) - NeiMa" + }, + { + "code": 3758490628.0, + "file": "dayi.ime", + "name": "Chinese (Traditional) - DaYi" + }, + { + "code": 3758556164.0, + "file": "unicdime.ime", + "name": "Chinese (Traditional) - Unicode" + }, + { + "code": 3758621700.0, + "file": "TINTLGNT.IME", + "name": "Chinese (Traditional) - New Phonetic" + }, + { + "code": 3758687236.0, + "file": "CINTLGNT.IME", + "name": "Chinese (Traditional) - New ChangJie" + }, + { + "code": 3759015940.0, + "file": "pintlgnt.ime", + "name": "Chinese (Traditional) - Microsoft Pinyin IME 3.0" + }, + { + "code": 3759080452.0, + "file": "romanime.ime", + "name": "Chinese (Traditional) - Alphanumeric" + } + ] +} \ No newline at end of file diff --git a/libfreerdp/locale/keyboard_layout.c b/libfreerdp/locale/keyboard_layout.c index d94de5558..da0df533c 100644 --- a/libfreerdp/locale/keyboard_layout.c +++ b/libfreerdp/locale/keyboard_layout.c @@ -24,6 +24,8 @@ #include #include +#include +#include #include "liblocale.h" @@ -31,6 +33,11 @@ #include #include +#include +#define TAG FREERDP_TAG("locale.keyboard.layouts") + +// #define DUMP_LAYOUTS_TO_JSON + struct LanguageIdentifier { /* LanguageIdentifier = (SublangaugeIdentifier<<2) | PrimaryLanguageIdentifier @@ -48,6 +55,20 @@ struct LanguageIdentifier const char* SublanguageSymbol; }; +typedef struct +{ + DWORD code; /* Keyboard layout code */ + DWORD id; /* Keyboard variant ID */ + char* name; /* Keyboard layout variant name */ +} RDP_KEYBOARD_LAYOUT_VARIANT; + +typedef struct +{ + DWORD code; /* Keyboard layout code */ + char* file; /* IME file */ + char* name; /* Keyboard layout name */ +} RDP_KEYBOARD_IME; + static const struct LanguageIdentifier language_identifiers[] = { /* [Language identifier] [Primary language] [Prim. lang. identifier] [Prim. lang. symbol] [Sublanguage] [Sublang. identifier] [Sublang. symbol] */ @@ -500,12 +521,31 @@ static const struct LanguageIdentifier language_identifiers[] = { "SUBLANG_YORUBA_NIGERIA" }, }; +static BOOL reallocate_keyboard_layouts(RDP_KEYBOARD_LAYOUT** layouts, size_t* pcount, + size_t to_add) +{ + WINPR_ASSERT(layouts); + WINPR_ASSERT(pcount); + + RDP_KEYBOARD_LAYOUT* copy = (RDP_KEYBOARD_LAYOUT*)realloc( + *layouts, (*pcount + to_add + 1) * sizeof(RDP_KEYBOARD_LAYOUT)); + + if (!copy) + return FALSE; + + memset(©[*pcount], 0, (to_add + 1) * sizeof(RDP_KEYBOARD_LAYOUT)); + *layouts = copy; + *pcount += to_add; + return TRUE; +} + +#if !defined(WITH_KEYBOARD_LAYOUT_FROM_FILE) /* * In Windows XP, this information is available in the system registry at * HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet001/Control/Keyboard Layouts/ * https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values */ -static const RDP_KEYBOARD_LAYOUT RDP_KEYBOARD_LAYOUT_TABLE[] = { +static const RDP_KEYBOARD_LAYOUT sRDP_KEYBOARD_LAYOUT_TABLE[] = { { 0x0000041c, "Albanian" }, { 0x00000401, "Arabic (101)" }, { 0x00010401, "Arabic (102)" }, @@ -707,15 +747,9 @@ static const RDP_KEYBOARD_LAYOUT RDP_KEYBOARD_LAYOUT_TABLE[] = { { 0x00000485, "Yakut" }, { 0x0000046a, "Yoruba" }, }; +static const size_t sRDP_KEYBOARD_LAYOUT_TABLE_len = ARRAYSIZE(sRDP_KEYBOARD_LAYOUT_TABLE); -typedef struct -{ - DWORD code; /* Keyboard layout code */ - DWORD id; /* Keyboard variant ID */ - const char* name; /* Keyboard layout variant name */ -} RDP_KEYBOARD_LAYOUT_VARIANT; - -static const RDP_KEYBOARD_LAYOUT_VARIANT RDP_KEYBOARD_LAYOUT_VARIANT_TABLE[] = { +static const RDP_KEYBOARD_LAYOUT_VARIANT sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE[] = { { KBD_ARABIC_102, 0x0028, "Arabic (102)" }, { KBD_BULGARIAN_LATIN, 0x0004, "Bulgarian (Latin)" }, { KBD_CZECH_QWERTY, 0x0005, "Czech (QWERTY)" }, @@ -762,19 +796,14 @@ static const RDP_KEYBOARD_LAYOUT_VARIANT RDP_KEYBOARD_LAYOUT_VARIANT_TABLE[] = { { KBD_FRENCH_BEPO, 0x00C0, "French Bépo" }, { KBD_GERMAN_NEO, 0x00C0, "German Neo" } }; +static const size_t sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len = + ARRAYSIZE(sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE); /* Input Method Editor (IME) */ -typedef struct -{ - DWORD code; /* Keyboard layout code */ - const char* file; /* IME file */ - const char* name; /* Keyboard layout name */ -} RDP_KEYBOARD_IME; - /* Global Input Method Editors (IME) */ -static const RDP_KEYBOARD_IME RDP_KEYBOARD_IME_TABLE[] = { +static const RDP_KEYBOARD_IME sRDP_KEYBOARD_IME_TABLE[] = { { KBD_CHINESE_TRADITIONAL_PHONETIC, "phon.ime", "Chinese (Traditional) - Phonetic" }, { KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002, "imjp81.ime", "Japanese Input System (MS-IME2002)" }, { KBD_KOREAN_INPUT_SYSTEM_IME_2000, "imekr61.ime", "Korean Input System (IME 2000)" }, @@ -796,6 +825,621 @@ static const RDP_KEYBOARD_IME RDP_KEYBOARD_IME_TABLE[] = { "Chinese (Traditional) - Microsoft Pinyin IME 3.0" }, { KBD_CHINESE_TRADITIONAL_ALPHANUMERIC, "romanime.ime", "Chinese (Traditional) - Alphanumeric" } }; +static const size_t sRDP_KEYBOARD_IME_TABLE_len = ARRAYSIZE(sRDP_KEYBOARD_IME_TABLE); + +#if defined(DUMP_LAYOUTS_TO_JSON) +static BOOL append_layout(WINPR_JSON* json) +{ + WINPR_JSON* array = WINPR_JSON_AddArrayToObject(json, "KeyboardLayouts"); + if (!array) + return FALSE; + + for (size_t x = 0; x < sRDP_KEYBOARD_LAYOUT_TABLE_len; x++) + { + const RDP_KEYBOARD_LAYOUT* const ime = &sRDP_KEYBOARD_LAYOUT_TABLE[x]; + WINPR_JSON* obj = WINPR_JSON_CreateObject(); + if (!obj) + return FALSE; + WINPR_JSON_AddNumberToObject(obj, "code", ime->code); + WINPR_JSON_AddStringToObject(obj, "name", ime->name); + + if (!WINPR_JSON_AddItemToArray(array, obj)) + return FALSE; + } + + return TRUE; +} + +static BOOL append_variant(WINPR_JSON* json) +{ + WINPR_JSON* array = WINPR_JSON_AddArrayToObject(json, "KeyboardVariants"); + if (!array) + return FALSE; + + for (size_t x = 0; x < sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len; x++) + { + const RDP_KEYBOARD_LAYOUT_VARIANT* const ime = &sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE[x]; + WINPR_JSON* obj = WINPR_JSON_CreateObject(); + if (!obj) + return FALSE; + WINPR_JSON_AddNumberToObject(obj, "code", ime->code); + WINPR_JSON_AddNumberToObject(obj, "id", ime->id); + WINPR_JSON_AddStringToObject(obj, "name", ime->name); + + if (!WINPR_JSON_AddItemToArray(array, obj)) + return FALSE; + } + + return TRUE; +} + +static BOOL append_ime(WINPR_JSON* json) +{ + WINPR_JSON* array = WINPR_JSON_AddArrayToObject(json, "KeyboardIme"); + if (!array) + return FALSE; + + for (size_t x = 0; x < sRDP_KEYBOARD_IME_TABLE_len; x++) + { + const RDP_KEYBOARD_IME* const ime = &sRDP_KEYBOARD_IME_TABLE[x]; + WINPR_JSON* obj = WINPR_JSON_CreateObject(); + if (!obj) + return FALSE; + WINPR_JSON_AddNumberToObject(obj, "code", ime->code); + WINPR_JSON_AddStringToObject(obj, "file", ime->file); + WINPR_JSON_AddStringToObject(obj, "name", ime->name); + + if (!WINPR_JSON_AddItemToArray(array, obj)) + return FALSE; + } + + return TRUE; +} +#endif + +static BOOL load_layout_file(void) +{ +#if defined(DUMP_LAYOUTS_TO_JSON) + /* Dump to file in /tmp */ + char* str = NULL; + WINPR_JSON* json = WINPR_JSON_CreateObject(); + if (!json) + goto end; + + if (!append_layout(json)) + goto end; + if (!append_variant(json)) + goto end; + if (!append_ime(json)) + goto end; + + str = WINPR_JSON_Print(json); + if (!str) + goto end; + { + FILE* fp = winpr_fopen("/tmp/kbd.json", "w"); + if (!fp) + goto end; + fprintf(fp, "%s", str); + fclose(fp); + } +end: + free(str); + WINPR_JSON_Delete(json); +#endif + return TRUE; +} +#else +static RDP_KEYBOARD_LAYOUT* sRDP_KEYBOARD_LAYOUT_TABLE = NULL; +static size_t sRDP_KEYBOARD_LAYOUT_TABLE_len = 0; + +static RDP_KEYBOARD_LAYOUT_VARIANT* sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE = NULL; +static size_t sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len = 0; + +static RDP_KEYBOARD_IME* sRDP_KEYBOARD_IME_TABLE = NULL; +static size_t sRDP_KEYBOARD_IME_TABLE_len = 0; + +static void clear_keyboard_layout(RDP_KEYBOARD_LAYOUT* layout) +{ + if (!layout) + return; + + free(layout->name); + const RDP_KEYBOARD_LAYOUT empty = { 0 }; + *layout = empty; +} + +static void clear_keyboard_variant(RDP_KEYBOARD_LAYOUT_VARIANT* layout) +{ + if (!layout) + return; + + free(layout->name); + const RDP_KEYBOARD_LAYOUT_VARIANT empty = { 0 }; + *layout = empty; +} + +static void clear_keyboard_ime(RDP_KEYBOARD_IME* layout) +{ + if (!layout) + return; + + free(layout->file); + free(layout->name); + const RDP_KEYBOARD_IME empty = { 0 }; + *layout = empty; +} + +static void clear_layout_tables(void) +{ + for (size_t x = 0; x < sRDP_KEYBOARD_LAYOUT_TABLE_len; x++) + { + RDP_KEYBOARD_LAYOUT* layout = &sRDP_KEYBOARD_LAYOUT_TABLE[x]; + clear_keyboard_layout(layout); + } + + free(sRDP_KEYBOARD_LAYOUT_TABLE); + sRDP_KEYBOARD_LAYOUT_TABLE = NULL; + sRDP_KEYBOARD_LAYOUT_TABLE_len = 0; + + for (size_t x = 0; x < sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len; x++) + { + RDP_KEYBOARD_LAYOUT_VARIANT* variant = &sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE[x]; + clear_keyboard_variant(variant); + } + free(sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE); + sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE = NULL; + sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len = 0; + + for (size_t x = 0; x < sRDP_KEYBOARD_IME_TABLE_len; x++) + { + RDP_KEYBOARD_IME* ime = &sRDP_KEYBOARD_IME_TABLE[x]; + clear_keyboard_ime(ime); + } + free(sRDP_KEYBOARD_IME_TABLE); + sRDP_KEYBOARD_IME_TABLE = NULL; + sRDP_KEYBOARD_IME_TABLE_len = 0; +} + +static WINPR_JSON* load_layouts_from_file(const char* filename) +{ + INT64 jstrlen = 0; + char* jstr = NULL; + WINPR_JSON* json = NULL; + FILE* fp = winpr_fopen(filename, "r"); + if (!fp) + { + WLog_WARN(TAG, "resource file '%s' does not exist or is not readable", filename); + return NULL; + } + + if (_fseeki64(fp, 0, SEEK_END) < 0) + { + WLog_WARN(TAG, "resource file '%s' seek failed", filename); + goto end; + } + jstrlen = _ftelli64(fp); + if (jstrlen < 0) + { + WLog_WARN(TAG, "resource file '%s' invalid length %" PRId64, filename, jstrlen); + goto end; + } + if (_fseeki64(fp, 0, SEEK_SET) < 0) + { + WLog_WARN(TAG, "resource file '%s' seek failed", filename); + goto end; + } + + jstr = calloc(jstrlen + 1, sizeof(char)); + if (!jstr) + { + WLog_WARN(TAG, "resource file '%s' failed to allocate buffer of size %" PRId64, filename, + jstrlen); + goto end; + } + + if (fread(jstr, jstrlen, sizeof(char), fp) != 1) + { + WLog_WARN(TAG, "resource file '%s' failed to read buffer of size %" PRId64, filename, + jstrlen); + goto end; + } + + json = WINPR_JSON_ParseWithLength(jstr, jstrlen); + if (!json) + WLog_WARN(TAG, "resource file '%s' is not a valid JSON file", filename); +end: + fclose(fp); + free(jstr); + return json; +} + +static char* get_object_str(WINPR_JSON* json, size_t pos, const char* name) +{ + WINPR_ASSERT(json); + if (!WINPR_JSON_IsObject(json) || !WINPR_JSON_HasObjectItem(json, name)) + { + WLog_WARN(TAG, "Invalid JSON entry at entry %" PRIuz ", missing an Object named '%s'", pos, + name); + return NULL; + } + WINPR_JSON* obj = WINPR_JSON_GetObjectItem(json, name); + WINPR_ASSERT(obj); + if (!WINPR_JSON_IsString(obj)) + { + WLog_WARN(TAG, + "Invalid JSON entry at entry %" PRIuz ", Object named '%s': Not of type string", + pos, name); + return NULL; + } + + const char* str = WINPR_JSON_GetStringValue(obj); + if (!str) + { + WLog_WARN(TAG, "Invalid JSON entry at entry %" PRIuz ", Object named '%s': NULL string", + pos, name); + return NULL; + } + + return _strdup(str); +} + +static UINT32 get_object_integer(WINPR_JSON* json, size_t pos, const char* name) +{ + WINPR_ASSERT(json); + if (!WINPR_JSON_IsObject(json) || !WINPR_JSON_HasObjectItem(json, name)) + { + WLog_WARN(TAG, "Invalid JSON entry at entry %" PRIuz ", missing an Object named '%s'", pos, + name); + return 0; + } + WINPR_JSON* obj = WINPR_JSON_GetObjectItem(json, name); + WINPR_ASSERT(obj); + if (!WINPR_JSON_IsNumber(obj)) + { + WLog_WARN(TAG, + "Invalid JSON entry at entry %" PRIuz ", Object named '%s': Not of type string", + pos, name); + return 0; + } + + return WINPR_JSON_GetNumberValue(obj); +} + +static BOOL parse_json_layout_entry(WINPR_JSON* json, size_t pos, RDP_KEYBOARD_LAYOUT* entry) +{ + WINPR_ASSERT(entry); + if (!json || !WINPR_JSON_IsObject(json)) + { + WLog_WARN(TAG, "Invalid JSON entry at entry %" PRIuz ", expected an array", pos); + return FALSE; + } + + entry->code = get_object_integer(json, pos, "code"); + entry->name = get_object_str(json, pos, "name"); + if (!entry->name) + { + clear_keyboard_layout(entry); + return FALSE; + } + return TRUE; +} + +static BOOL parse_layout_entries(WINPR_JSON* json, const char* filename) +{ + if (!WINPR_JSON_IsArray(json)) + { + WLog_WARN(TAG, "Invalid top level JSON type in file %s, expected an array", filename); + return FALSE; + } + return TRUE; +} + +static BOOL parse_json_variant_entry(WINPR_JSON* json, size_t pos, + RDP_KEYBOARD_LAYOUT_VARIANT* entry) +{ + WINPR_ASSERT(entry); + if (!json || !WINPR_JSON_IsObject(json)) + { + WLog_WARN(TAG, "Invalid JSON entry at entry %" PRIuz ", expected an array", pos); + return FALSE; + } + + entry->code = get_object_integer(json, pos, "code"); + entry->id = get_object_integer(json, pos, "id"); + entry->name = get_object_str(json, pos, "name"); + if (!entry->name) + { + clear_keyboard_variant(entry); + return FALSE; + } + return TRUE; +} + +static BOOL parse_variant_entries(WINPR_JSON* json, const char* filename) +{ + if (!WINPR_JSON_IsArray(json)) + { + WLog_WARN(TAG, "Invalid top level JSON type in file %s, expected an array", filename); + return FALSE; + } + WINPR_ASSERT(!sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE); + WINPR_ASSERT(sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len == 0); + + const size_t count = WINPR_JSON_GetArraySize(json); + sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE = calloc(count, sizeof(RDP_KEYBOARD_LAYOUT_VARIANT)); + if (!sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE) + return FALSE; + sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len = count; + + for (size_t x = 0; x < count; x++) + { + WINPR_JSON* entry = WINPR_JSON_GetArrayItem(json, x); + if (!parse_json_variant_entry(entry, x, &sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE[x])) + return FALSE; + } + return TRUE; +} + +static BOOL parse_json_ime_entry(WINPR_JSON* json, size_t pos, RDP_KEYBOARD_IME* entry) +{ + WINPR_ASSERT(entry); + if (!json || !WINPR_JSON_IsObject(json)) + { + WLog_WARN(TAG, "Invalid JSON entry at entry %" PRIuz ", expected an array", pos); + return FALSE; + } + + entry->code = get_object_integer(json, pos, "code"); + entry->file = get_object_str(json, pos, "file"); + entry->name = get_object_str(json, pos, "name"); + if (!entry->file || !entry->name) + { + clear_keyboard_ime(entry); + return FALSE; + } + return TRUE; +} + +static BOOL parse_ime_entries(WINPR_JSON* json, const char* filename) +{ + if (!WINPR_JSON_IsArray(json)) + { + WLog_WARN(TAG, "Invalid top level JSON type in file %s, expected an array", filename); + return FALSE; + } + WINPR_ASSERT(!sRDP_KEYBOARD_IME_TABLE); + WINPR_ASSERT(sRDP_KEYBOARD_IME_TABLE_len == 0); + + const size_t count = WINPR_JSON_GetArraySize(json); + sRDP_KEYBOARD_IME_TABLE = calloc(count, sizeof(RDP_KEYBOARD_IME)); + if (!sRDP_KEYBOARD_IME_TABLE) + return FALSE; + sRDP_KEYBOARD_IME_TABLE_len = count; + + for (size_t x = 0; x < count; x++) + { + WINPR_JSON* entry = WINPR_JSON_GetArrayItem(json, x); + if (!parse_json_ime_entry(entry, x, &sRDP_KEYBOARD_IME_TABLE[x])) + return FALSE; + } + return TRUE; +} + +static BOOL CALLBACK load_layouts(PINIT_ONCE once, PVOID param, PVOID* context) +{ + WINPR_UNUSED(once); + WINPR_UNUSED(param); + WINPR_UNUSED(context); + + WINPR_JSON* json = NULL; + char* filename = GetCombinedPath(FREERDP_RESOURCE_ROOT, "KeyboardLayoutMap.json"); + if (!filename) + { + WLog_WARN(TAG, "Could not create WinPR timezone resource filename"); + goto end; + } + + json = load_layouts_from_file(filename); + if (!json) + goto end; + if (!WINPR_JSON_IsObject(json)) + { + WLog_WARN(TAG, "Invalid top level JSON type in file %s, expected an array", filename); + goto end; + } + + { + WINPR_JSON* obj = WINPR_JSON_GetObjectItem(json, "KeyboardLayouts"); + if (!parse_layout_entries(obj, filename)) + goto end; + } + { + WINPR_JSON* obj = WINPR_JSON_GetObjectItem(json, "KeyboardVariants"); + if (!parse_variant_entries(obj, filename)) + goto end; + } + { + WINPR_JSON* obj = WINPR_JSON_GetObjectItem(json, "KeyboardIme"); + if (!parse_ime_entries(obj, filename)) + goto end; + } + +end: + free(filename); + WINPR_JSON_Delete(json); + (void)atexit(clear_layout_tables); + return TRUE; +} + +static BOOL load_layout_file(void) +{ + static INIT_ONCE once = INIT_ONCE_STATIC_INIT; + InitOnceExecuteOnce(&once, load_layouts, NULL, NULL); + return TRUE; +} + +#endif + +static UINT32 rdp_keyboard_layout_by_name(const char* name) +{ + WINPR_ASSERT(name); + load_layout_file(); + + for (size_t i = 0; i < sRDP_KEYBOARD_LAYOUT_TABLE_len; i++) + { + const RDP_KEYBOARD_LAYOUT* const layout = &sRDP_KEYBOARD_LAYOUT_TABLE[i]; + if (strcmp(layout->name, name) == 0) + return layout->code; + } + return 0; +} + +static UINT32 rdp_keyboard_variant_by_name(const char* name) +{ + WINPR_ASSERT(name); + load_layout_file(); + + for (size_t i = 0; i < sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len; i++) + { + const RDP_KEYBOARD_LAYOUT_VARIANT* const variant = &sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE[i]; + if (strcmp(variant->name, name) == 0) + return variant->code; + } + return 0; +} + +static UINT32 rdp_keyboard_ime_by_name(const char* name) +{ + WINPR_ASSERT(name); + load_layout_file(); + + for (size_t i = 0; i < sRDP_KEYBOARD_IME_TABLE_len; i++) + { + const RDP_KEYBOARD_IME* const ime = &sRDP_KEYBOARD_IME_TABLE[i]; + if (strcmp(ime->name, name) == 0) + return ime->code; + } + return 0; +} + +static const char* rdp_keyboard_layout_by_id(UINT32 id) +{ + load_layout_file(); + + for (size_t i = 0; i < sRDP_KEYBOARD_LAYOUT_TABLE_len; i++) + { + const RDP_KEYBOARD_LAYOUT* const layout = &sRDP_KEYBOARD_LAYOUT_TABLE[i]; + if (layout->code == id) + return layout->name; + } + + return 0; +} + +static const char* rdp_keyboard_variant_by_id(UINT32 id) +{ + load_layout_file(); + + for (size_t i = 0; i < sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len; i++) + { + const RDP_KEYBOARD_LAYOUT_VARIANT* const variant = &sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE[i]; + if (variant->code == id) + return variant->name; + } + return 0; +} + +static const char* rdp_keyboard_ime_by_id(UINT32 id) +{ + load_layout_file(); + + for (size_t i = 0; i < sRDP_KEYBOARD_IME_TABLE_len; i++) + { + const RDP_KEYBOARD_IME* const ime = &sRDP_KEYBOARD_IME_TABLE[i]; + if (ime->code == id) + return ime->name; + } + return NULL; +} + +static BOOL rdp_keyboard_layout_clone_append(RDP_KEYBOARD_LAYOUT** layouts, size_t* pcount) +{ + WINPR_ASSERT(layouts); + WINPR_ASSERT(pcount); + + load_layout_file(); + + const size_t length = sRDP_KEYBOARD_LAYOUT_TABLE_len; + const size_t offset = *pcount; + if (!reallocate_keyboard_layouts(layouts, pcount, length)) + return FALSE; + + for (size_t i = 0; i < length; i++) + { + const RDP_KEYBOARD_LAYOUT* const ime = &sRDP_KEYBOARD_LAYOUT_TABLE[i]; + RDP_KEYBOARD_LAYOUT* layout = &(*layouts)[i + offset]; + layout->code = ime->code; + if (ime->name) + layout->name = _strdup(ime->name); + + if (!layout->name) + return FALSE; + } + return TRUE; +} + +static BOOL rdp_keyboard_variant_clone_append(RDP_KEYBOARD_LAYOUT** layouts, size_t* pcount) +{ + WINPR_ASSERT(layouts); + WINPR_ASSERT(pcount); + + load_layout_file(); + + const size_t length = sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE_len; + const size_t offset = *pcount; + if (!reallocate_keyboard_layouts(layouts, pcount, length)) + return FALSE; + + for (size_t i = 0; i < length; i++) + { + const RDP_KEYBOARD_LAYOUT_VARIANT* const ime = &sRDP_KEYBOARD_LAYOUT_VARIANT_TABLE[i]; + RDP_KEYBOARD_LAYOUT* layout = &(*layouts)[i + offset]; + layout->code = ime->code; + if (ime->name) + layout->name = _strdup(ime->name); + + if (!layout->name) + return FALSE; + } + return TRUE; +} + +static BOOL rdp_keyboard_ime_clone_append(RDP_KEYBOARD_LAYOUT** layouts, size_t* pcount) +{ + WINPR_ASSERT(layouts); + WINPR_ASSERT(pcount); + + load_layout_file(); + + const size_t length = sRDP_KEYBOARD_IME_TABLE_len; + const size_t offset = *pcount; + if (!reallocate_keyboard_layouts(layouts, pcount, length)) + return FALSE; + + for (size_t i = 0; i < length; i++) + { + const RDP_KEYBOARD_IME* const ime = &sRDP_KEYBOARD_IME_TABLE[i]; + RDP_KEYBOARD_LAYOUT* layout = &(*layouts)[i + offset]; + layout->code = ime->code; + if (ime->name) + layout->name = _strdup(ime->name); + + if (!layout->name) + return FALSE; + } + return TRUE; +} void freerdp_keyboard_layouts_free(RDP_KEYBOARD_LAYOUT* layouts, size_t count) { @@ -817,6 +1461,8 @@ RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types, size_t* count) size_t num = 0; RDP_KEYBOARD_LAYOUT* layouts = NULL; + load_layout_file(); + num = 0; WINPR_ASSERT(count); @@ -824,65 +1470,20 @@ RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types, size_t* count) if ((types & RDP_KEYBOARD_LAYOUT_TYPE_STANDARD) != 0) { - const size_t length = ARRAYSIZE(RDP_KEYBOARD_LAYOUT_TABLE); - RDP_KEYBOARD_LAYOUT* new = (RDP_KEYBOARD_LAYOUT*)realloc( - layouts, (num + length + 1) * sizeof(RDP_KEYBOARD_LAYOUT)); - - if (!new) + if (!rdp_keyboard_layout_clone_append(&layouts, &num)) goto fail; - - layouts = new; - - for (size_t i = 0; i < length; i++, num++) - { - layouts[num].code = RDP_KEYBOARD_LAYOUT_TABLE[i].code; - layouts[num].name = _strdup(RDP_KEYBOARD_LAYOUT_TABLE[i].name); - - if (!layouts[num].name) - goto fail; - } } if ((types & RDP_KEYBOARD_LAYOUT_TYPE_VARIANT) != 0) { - const size_t length = ARRAYSIZE(RDP_KEYBOARD_LAYOUT_VARIANT_TABLE); - RDP_KEYBOARD_LAYOUT* new = (RDP_KEYBOARD_LAYOUT*)realloc( - layouts, (num + length + 1) * sizeof(RDP_KEYBOARD_LAYOUT)); - - if (!new) + if (!rdp_keyboard_variant_clone_append(&layouts, &num)) goto fail; - - layouts = new; - - for (size_t i = 0; i < length; i++, num++) - { - layouts[num].code = RDP_KEYBOARD_LAYOUT_VARIANT_TABLE[i].code; - layouts[num].name = _strdup(RDP_KEYBOARD_LAYOUT_VARIANT_TABLE[i].name); - - if (!layouts[num].name) - goto fail; - } } if ((types & RDP_KEYBOARD_LAYOUT_TYPE_IME) != 0) { - const size_t length = ARRAYSIZE(RDP_KEYBOARD_IME_TABLE); - RDP_KEYBOARD_LAYOUT* new = (RDP_KEYBOARD_LAYOUT*)realloc( - layouts, (num + length + 1) * sizeof(RDP_KEYBOARD_LAYOUT)); - - if (!new) + if (!rdp_keyboard_ime_clone_append(&layouts, &num)) goto fail; - - layouts = new; - - for (size_t i = 0; i < length; i++, num++) - { - layouts[num].code = RDP_KEYBOARD_IME_TABLE[i].code; - layouts[num].name = _strdup(RDP_KEYBOARD_IME_TABLE[i].name); - - if (!layouts[num].name) - goto fail; - } } *count = num; @@ -894,48 +1495,32 @@ fail: const char* freerdp_keyboard_get_layout_name_from_id(DWORD keyboardLayoutID) { - for (size_t i = 0; i < ARRAYSIZE(RDP_KEYBOARD_LAYOUT_TABLE); i++) - { - if (RDP_KEYBOARD_LAYOUT_TABLE[i].code == keyboardLayoutID) - return RDP_KEYBOARD_LAYOUT_TABLE[i].name; - } + const char* name = rdp_keyboard_layout_by_id(keyboardLayoutID); + if (name) + return name; - for (size_t i = 0; i < ARRAYSIZE(RDP_KEYBOARD_LAYOUT_VARIANT_TABLE); i++) - { - if (RDP_KEYBOARD_LAYOUT_VARIANT_TABLE[i].code == keyboardLayoutID) - return RDP_KEYBOARD_LAYOUT_VARIANT_TABLE[i].name; - } + name = rdp_keyboard_variant_by_id(keyboardLayoutID); + if (name) + return name; - for (size_t i = 0; i < ARRAYSIZE(RDP_KEYBOARD_IME_TABLE); i++) - { - if (RDP_KEYBOARD_IME_TABLE[i].code == keyboardLayoutID) - return RDP_KEYBOARD_IME_TABLE[i].name; - } + name = rdp_keyboard_ime_by_id(keyboardLayoutID); + if (name) + return name; return "unknown"; } DWORD freerdp_keyboard_get_layout_id_from_name(const char* name) { - for (size_t i = 0; i < ARRAYSIZE(RDP_KEYBOARD_LAYOUT_TABLE); i++) - { - if (strcmp(RDP_KEYBOARD_LAYOUT_TABLE[i].name, name) == 0) - return RDP_KEYBOARD_LAYOUT_TABLE[i].code; - } + DWORD rc = rdp_keyboard_layout_by_name(name); + if (rc != 0) + return rc; - for (size_t i = 0; i < ARRAYSIZE(RDP_KEYBOARD_LAYOUT_VARIANT_TABLE); i++) - { - if (strcmp(RDP_KEYBOARD_LAYOUT_VARIANT_TABLE[i].name, name) == 0) - return RDP_KEYBOARD_LAYOUT_VARIANT_TABLE[i].code; - } + rc = rdp_keyboard_variant_by_name(name); + if (rc != 0) + return rc; - for (size_t i = 0; i < ARRAYSIZE(RDP_KEYBOARD_IME_TABLE); i++) - { - if (strcmp(RDP_KEYBOARD_IME_TABLE[i].name, name) == 0) - return RDP_KEYBOARD_IME_TABLE[i].code; - } - - return 0; + return rdp_keyboard_ime_by_name(name); } static void copy(const struct LanguageIdentifier* id, RDP_CODEPAGE* cp)