From ce1dcbb552756ddf994f172971d99c3f121588f1 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Mon, 4 Sep 2023 15:39:22 +0300 Subject: [PATCH] kdeui: new KKeyboardLayout class KKeyboardLayout along with Solid::Input are to be used not only in a reimplementation of the keyboard plasma applet but also potentially for a software input panel (QEvent::RequestSoftwareInputPanel and QEvent::CloseSoftwareInputPanel handler) Signed-off-by: Ivailo Monev --- includes/CMakeLists.txt | 1 + includes/KKeyboardLayout | 1 + kdeui/CMakeLists.txt | 7 + kdeui/util/kkeyboardlayout.cpp | 1339 ++++++++++++++++++++++++++++++++ kdeui/util/kkeyboardlayout.h | 79 ++ kdeui/util/scoop-rules.py | 93 +++ solid/solid/ifaces/input.cpp | 2 +- 7 files changed, 1521 insertions(+), 1 deletion(-) create mode 100644 includes/KKeyboardLayout create mode 100644 kdeui/util/kkeyboardlayout.cpp create mode 100644 kdeui/util/kkeyboardlayout.h create mode 100755 kdeui/util/scoop-rules.py diff --git a/includes/CMakeLists.txt b/includes/CMakeLists.txt index 030425ba..99241767 100644 --- a/includes/CMakeLists.txt +++ b/includes/CMakeLists.txt @@ -158,6 +158,7 @@ install( KJobTrackerInterface KJobUiDelegate KKeySequenceWidget + KKeyboardLayout KLed KLineEdit KLinkItemSelectionModel diff --git a/includes/KKeyboardLayout b/includes/KKeyboardLayout new file mode 100644 index 00000000..7e096a4b --- /dev/null +++ b/includes/KKeyboardLayout @@ -0,0 +1 @@ +#include "../kkeyboardlayout.h" diff --git a/kdeui/CMakeLists.txt b/kdeui/CMakeLists.txt index 83d4f20b..c3c94dc5 100644 --- a/kdeui/CMakeLists.txt +++ b/kdeui/CMakeLists.txt @@ -197,6 +197,7 @@ set(kdeui_LIB_SRCS util/kpixmapsequencewidget.cpp util/kimageio.cpp util/kkeyserver_x11.cpp + util/kkeyboardlayout.cpp widgets/kactionselector.cpp widgets/kdialogbuttonbox.cpp widgets/kbuttongroup.cpp @@ -272,6 +273,11 @@ if (X11_Xkb_FOUND AND X11_Xkbfile_FOUND) ${X11_Xkb_INCLUDE_PATH} ${X11_Xlib_INCLUDE_PATH} ) + set(KDEUI_EXTRA_LIBS + ${KDEUI_EXTRA_LIBS} + ${X11_LIBRARIES} + ${X11_Xkbfile_LIB} + ) endif() qt4_add_dbus_interfaces(kdeui_LIB_SRCS jobs/org.kde.JobViewServer.xml ) @@ -482,6 +488,7 @@ install( util/kcursor.h util/kguiitem.h util/kkeyserver.h + util/kkeyboardlayout.h util/kselectionowner.h util/knumvalidator.h util/kpassivepopup.h diff --git a/kdeui/util/kkeyboardlayout.cpp b/kdeui/util/kkeyboardlayout.cpp new file mode 100644 index 00000000..08294fc3 --- /dev/null +++ b/kdeui/util/kkeyboardlayout.cpp @@ -0,0 +1,1339 @@ +/* This file is part of the KDE libraries + Copyright (C) 2023 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config-kkeyserver.h" +#include "kkeyboardlayout.h" +#include "kstandarddirs.h" +#include "klocale.h" +#include "kdebug.h" + +#include +#include +#include +#include + +#if defined(HAVE_XKB) +# include +# include +# include +# include +#endif + +static const int s_layouttimeout = 500; +static const char s_xkbseparator = ','; + +// NOTE: scooped via scoop-rules.py script, make sure to pipe it to `sort -u` +static const struct modelDescriptionData { + const char* name; + const char* description; +} modelDescriptionTbl[] = { + { "a4_rfkb23", I18N_NOOP("A4Tech Wireless Desktop RFKB-23") }, + { "a4techKB21", I18N_NOOP("A4Tech KB-21") }, + { "a4techKBS8", I18N_NOOP("A4Tech KBS-8") }, + { "acer_c300", I18N_NOOP("Acer C300") }, + { "acer_ferrari4k", I18N_NOOP("Acer Ferrari 4000") }, + { "acer_laptop", I18N_NOOP("Acer laptop") }, + { "airkey", I18N_NOOP("Acer AirKey V") }, + { "apex300", I18N_NOOP("SteelSeries Apex 300 (Apex RAW)") }, + { "apple", I18N_NOOP("Apple") }, + { "apple_laptop", I18N_NOOP("Apple laptop") }, + { "applealu_ansi", I18N_NOOP("Apple Aluminium (ANSI)") }, + { "applealu_iso", I18N_NOOP("Apple Aluminium (ISO)") }, + { "applealu_jis", I18N_NOOP("Apple Aluminium (JIS)") }, + { "armada", I18N_NOOP("Compaq Armada laptop") }, + { "asus_laptop", I18N_NOOP("Asus laptop") }, + { "azonaRF2300", I18N_NOOP("Azona RF2300 Wireless Internet") }, + { "benqx", I18N_NOOP("BenQ X-Touch") }, + { "benqx730", I18N_NOOP("BenQ X-Touch 730") }, + { "benqx800", I18N_NOOP("BenQ X-Touch 800") }, + { "brother", I18N_NOOP("Brother Internet") }, + { "btc5090", I18N_NOOP("BTC 5090") }, + { "btc5113rf", I18N_NOOP("BTC 5113RF Multimedia") }, + { "btc5126t", I18N_NOOP("BTC 5126T") }, + { "btc6301urf", I18N_NOOP("BTC 6301URF") }, + { "btc9000", I18N_NOOP("BTC 9000") }, + { "btc9000a", I18N_NOOP("BTC 9000A") }, + { "btc9001ah", I18N_NOOP("BTC 9001AH") }, + { "btc9019u", I18N_NOOP("BTC 9019U") }, + { "btc9116u", I18N_NOOP("BTC 9116U Mini Wireless Internet and Gaming") }, + { "cherryblue", I18N_NOOP("Cherry Blue Line CyBo@rd") }, + { "cherrybluea", I18N_NOOP("Cherry Blue Line CyBo@rd (alt.)") }, + { "cherryblueb", I18N_NOOP("Cherry CyMotion Master XPress") }, + { "cherrybunlim", I18N_NOOP("Cherry B.UNLIMITED") }, + { "cherrycmexpert", I18N_NOOP("Cherry CyMotion Expert") }, + { "cherrycyboard", I18N_NOOP("Cherry CyBo@rd USB-Hub") }, + { "chicony", I18N_NOOP("Chicony Internet") }, + { "chicony0108", I18N_NOOP("Chicony KU-0108") }, + { "chicony0420", I18N_NOOP("Chicony KU-0420") }, + { "chicony9885", I18N_NOOP("Chicony KB-9885") }, + { "chromebook", I18N_NOOP("Chromebook") }, + { "classmate", I18N_NOOP("Classmate PC") }, + { "compalfl90", I18N_NOOP("FL90") }, + { "compaqeak8", I18N_NOOP("Compaq Easy Access") }, + { "compaqik13", I18N_NOOP("Compaq Internet (13 keys)") }, + { "compaqik18", I18N_NOOP("Compaq Internet (18 keys)") }, + { "compaqik7", I18N_NOOP("Compaq Internet (7 keys)") }, + { "creativedw7000", I18N_NOOP("Creative Desktop Wireless 7000") }, + { "cymotionlinux", I18N_NOOP("Cherry CyMotion Master Linux") }, + { "dell", I18N_NOOP("Dell") }, + { "dell101", I18N_NOOP("Dell 101-key PC") }, + { "dellm65", I18N_NOOP("Dell Precision M65 laptop") }, + { "dellsk8125", I18N_NOOP("Dell SK-8125") }, + { "dellsk8135", I18N_NOOP("Dell SK-8135") }, + { "dellusbmm", I18N_NOOP("Dell USB Multimedia") }, + { "dexxa", I18N_NOOP("Dexxa Wireless Desktop") }, + { "diamond", I18N_NOOP("Diamond 9801/9802") }, + { "dtk2000", I18N_NOOP("DTK2000") }, + { "emachines", I18N_NOOP("eMachines m6800 laptop") }, + { "ennyah_dkb1008", I18N_NOOP("Ennyah DKB-1008") }, + { "everex", I18N_NOOP("Everex STEPnote") }, + { "flexpro", I18N_NOOP("Keytronic FlexPro") }, + { "fscaa1667g", I18N_NOOP("Fujitsu-Siemens Amilo laptop") }, + { "genius", I18N_NOOP("Genius Comfy KB-16M/Multimedia KWD-910") }, + { "geniuscomfy", I18N_NOOP("Genius Comfy KB-12e") }, + { "geniuscomfy2", I18N_NOOP("Genius Comfy KB-21e-Scroll") }, + { "geniuskb19e", I18N_NOOP("Genius KB-19e NB") }, + { "geniuskkb2050hs", I18N_NOOP("Genius KKB-2050HS") }, + { "gyration", I18N_NOOP("Gyration") }, + { "hhk", I18N_NOOP("Happy Hacking") }, + { "honeywell_euroboard", I18N_NOOP("Honeywell Euroboard") }, + { "hp250x", I18N_NOOP("Hewlett-Packard NEC SK-2500 Multimedia") }, + { "hp500fa", I18N_NOOP("Hewlett-Packard Omnibook 500 FA") }, + { "hp5xx", I18N_NOOP("Hewlett-Packard Omnibook 500") }, + { "hp6000", I18N_NOOP("Hewlett-Packard Omnibook 6000/6100") }, + { "hpdv5", I18N_NOOP("Hewlett-Packard Pavilion dv5") }, + { "hpi6", I18N_NOOP("Hewlett-Packard Internet") }, + { "hpmini110", I18N_NOOP("Hewlett-Packard Mini 110 laptop") }, + { "hpnx9020", I18N_NOOP("Hewlett-Packard nx9020") }, + { "hpxe3gc", I18N_NOOP("Hewlett-Packard Omnibook XE3 GC") }, + { "hpxe3gf", I18N_NOOP("Hewlett-Packard Omnibook XE3 GF") }, + { "hpxt1000", I18N_NOOP("Hewlett-Packard Omnibook XT1000") }, + { "hpzt11xx", I18N_NOOP("Hewlett-Packard Pavilion ZT1100") }, + { "ibm_spacesaver", I18N_NOOP("IBM Space Saver") }, + { "inspiron", I18N_NOOP("Dell Inspiron 6000/8000 laptop") }, + { "ipaq", I18N_NOOP("Compaq iPaq") }, + { "itouch", I18N_NOOP("Logitech iTouch") }, + { "kinesis", I18N_NOOP("Kinesis") }, + { "latitude", I18N_NOOP("Dell Latitude laptop") }, + { "logiaccess", I18N_NOOP("Logitech Access") }, + { "logicd", I18N_NOOP("Logitech Cordless Desktop") }, + { "logicd_it", I18N_NOOP("Logitech Cordless Desktop iTouch") }, + { "logicd_nav", I18N_NOOP("Logitech Cordless Desktop Navigator") }, + { "logicd_opt", I18N_NOOP("Logitech Cordless Desktop Optical") }, + { "logicda", I18N_NOOP("Logitech Cordless Desktop (alt.)") }, + { "logicdn", I18N_NOOP("Logitech Cordless Desktop Navigator") }, + { "logicdpa2", I18N_NOOP("Logitech Cordless Desktop Pro (2nd alt.)") }, + { "logicfn", I18N_NOOP("Logitech Cordless Freedom/Desktop Navigator") }, + { "logicink", I18N_NOOP("Logitech Internet Navigator") }, + { "logiclx300", I18N_NOOP("Logitech Cordless Desktop LX-300") }, + { "logidinovo", I18N_NOOP("Logitech diNovo") }, + { "logidinovoedge", I18N_NOOP("Logitech diNovo Edge") }, + { "logiex110", I18N_NOOP("Logitech Cordless Desktop EX110") }, + { "logii350", I18N_NOOP("Logitech Internet 350") }, + { "logiik", I18N_NOOP("Logitech Internet") }, + { "logiinkse", I18N_NOOP("Logitech iTouch Internet Navigator SE") }, + { "logiinkseusb", I18N_NOOP("Logitech iTouch Internet Navigator SE USB") }, + { "logiitc", I18N_NOOP("Logitech iTouch Cordless Y-RB6") }, + { "logimel", I18N_NOOP("Logitech Internet 350") }, + { "logitech_base", I18N_NOOP("Logitech") }, + { "logitech_g15", I18N_NOOP("Logitech G15 extra keys via G15daemon") }, + { "logiultrax", I18N_NOOP("Logitech Ultra-X") }, + { "logiultraxc", I18N_NOOP("Logitech Ultra-X Cordless Media Desktop") }, + { "macbook78", I18N_NOOP("MacBook/MacBook Pro") }, + { "macbook79", I18N_NOOP("MacBook/MacBook Pro (intl.)") }, + { "macintosh", I18N_NOOP("Macintosh") }, + { "macintosh_hhk", I18N_NOOP("Happy Hacking for Mac") }, + { "macintosh_old", I18N_NOOP("Macintosh Old") }, + { "microsoft", I18N_NOOP("Microsoft Natural") }, + { "microsoft4000", I18N_NOOP("Microsoft Natural Ergonomic 4000") }, + { "microsoft7000", I18N_NOOP("Microsoft Natural Wireless Ergonomic 7000") }, + { "microsoftccurve2k", I18N_NOOP("Microsoft Comfort Curve 2000") }, + { "microsoftelite", I18N_NOOP("Microsoft Natural Elite") }, + { "microsoftinet", I18N_NOOP("Microsoft Internet") }, + { "microsoftmult", I18N_NOOP("Microsoft Wireless Multimedia 1.0A") }, + { "microsoftoffice", I18N_NOOP("Microsoft Office Keyboard") }, + { "microsoftpro", I18N_NOOP("Microsoft Natural Pro/Internet Pro") }, + { "microsoftprooem", I18N_NOOP("Microsoft Natural Pro OEM") }, + { "microsoftprose", I18N_NOOP("Microsoft Internet Pro (Swedish)") }, + { "microsoftprousb", I18N_NOOP("Microsoft Natural Pro USB/Internet Pro") }, + { "microsoftsurface", I18N_NOOP("Microsoft Surface") }, + { "mx1998", I18N_NOOP("Memorex MX1998") }, + { "mx2500", I18N_NOOP("Memorex MX2500 EZ-Access") }, + { "mx2750", I18N_NOOP("Memorex MX2750") }, + { "olpc", I18N_NOOP("OLPC") }, + { "omnikey101", I18N_NOOP("Northgate OmniKey 101") }, + { "oretec", I18N_NOOP("Ortek Multimedia/Internet MCK-800") }, + { "pc101", I18N_NOOP("Generic 101-key PC") }, + { "pc102", I18N_NOOP("Generic 102-key PC") }, + { "pc104", I18N_NOOP("Generic 104-key PC") }, + { "pc104alt", I18N_NOOP("Generic 104-key PC with L-shaped Enter key") }, + { "pc105", I18N_NOOP("Generic 105-key PC") }, + { "pc86", I18N_NOOP("Generic 86-key PC") }, + { "pc98", I18N_NOOP("PC-98") }, + { "precision_m", I18N_NOOP("Dell Precision M laptop") }, + { "presario", I18N_NOOP("Compaq Presario laptop") }, + { "propeller", I18N_NOOP("Propeller Voyager KTEZ-1000") }, + { "qtronix", I18N_NOOP("QTronix Scorpius 98N+") }, + { "rapidaccess", I18N_NOOP("IBM Rapid Access") }, + { "rapidaccess2", I18N_NOOP("IBM Rapid Access II") }, + { "samsung4500", I18N_NOOP("Samsung SDM 4500P") }, + { "samsung4510", I18N_NOOP("Samsung SDM 4510P") }, + { "sanwaskbkg3", I18N_NOOP("Sanwa Supply SKB-KG3") }, + { "scorpius", I18N_NOOP("Advance Scorpius KI") }, + { "silvercrest", I18N_NOOP("Silvercrest Multimedia Wireless") }, + { "sk1300", I18N_NOOP("NEC SK-1300") }, + { "sk2500", I18N_NOOP("NEC SK-2500") }, + { "sk6200", I18N_NOOP("NEC SK-6200") }, + { "sk7100", I18N_NOOP("NEC SK-7100") }, + { "sp_inet", I18N_NOOP("Super Power Multimedia") }, + { "sun_type6_euro_usb", I18N_NOOP("Sun Type 6/7 USB (European)") }, + { "sun_type6_jp", I18N_NOOP("Sun Type 6 (Japanese)") }, + { "sun_type6_jp_usb", I18N_NOOP("Sun Type 6 USB (Japanese)") }, + { "sun_type6_unix_usb", I18N_NOOP("Sun Type 6 USB (Unix)") }, + { "sun_type6_usb", I18N_NOOP("Sun Type 6/7 USB") }, + { "sun_type7_euro_usb", I18N_NOOP("Sun Type 7 USB (European)") }, + { "sun_type7_jp_usb", I18N_NOOP("Sun Type 7 USB (Japanese)/Japanese 106-key") }, + { "sun_type7_unix_usb", I18N_NOOP("Sun Type 7 USB (Unix)") }, + { "sun_type7_usb", I18N_NOOP("Sun Type 7 USB") }, + { "sven", I18N_NOOP("SVEN Ergonomic 2500") }, + { "sven303", I18N_NOOP("SVEN Slim 303") }, + { "symplon", I18N_NOOP("Symplon PaceBook tablet") }, + { "targa_v811", I18N_NOOP("Targa Visionary 811") }, + { "teck227", I18N_NOOP("Truly Ergonomic 227") }, + { "teck229", I18N_NOOP("Truly Ergonomic 229") }, + { "thinkpad", I18N_NOOP("IBM ThinkPad 560Z/600/600E/A22E") }, + { "thinkpad60", I18N_NOOP("IBM ThinkPad R60/T60/R61/T61") }, + { "thinkpadz60", I18N_NOOP("IBM ThinkPad Z60m/Z60t/Z61m/Z61t") }, + { "tm2020", I18N_NOOP("TypeMatrix EZ-Reach 2020") }, + { "tm2030PS2", I18N_NOOP("TypeMatrix EZ-Reach 2030 PS2") }, + { "tm2030USB", I18N_NOOP("TypeMatrix EZ-Reach 2030 USB") }, + { "tm2030USB-102", I18N_NOOP("TypeMatrix EZ-Reach 2030 USB (102/105:EU mode)") }, + { "tm2030USB-106", I18N_NOOP("TypeMatrix EZ-Reach 2030 USB (106:JP mode)") }, + { "toshiba_s3000", I18N_NOOP("Toshiba Satellite S3000") }, + { "trust", I18N_NOOP("Trust Wireless Classic") }, + { "trust_slimline", I18N_NOOP("Trust Slimline") }, + { "trustda", I18N_NOOP("Trust Direct Access") }, + { "unitekkb1925", I18N_NOOP("Unitek KB-1925") }, + { "vsonku306", I18N_NOOP("ViewSonic KU-306 Internet") }, + { "winbook", I18N_NOOP("Winbook Model XP5") }, + { "yahoo", I18N_NOOP("Yahoo! Internet") } +}; +static const qint16 modelDescriptionTblSize = sizeof(modelDescriptionTbl) / sizeof(modelDescriptionData); + +static const struct layoutDescriptionData { + const char* name; + const char* description; +} layoutDescriptionTbl[] = { + { "af", I18N_NOOP("Dari") }, + { "al", I18N_NOOP("Albanian") }, + { "am", I18N_NOOP("Armenian") }, + { "ara", I18N_NOOP("Arabic") }, + { "at", I18N_NOOP("German (Austria)") }, + { "au", I18N_NOOP("English (Australian)") }, + { "az", I18N_NOOP("Azerbaijani") }, + { "ba", I18N_NOOP("Bosnian") }, + { "bd", I18N_NOOP("Bangla") }, + { "be", I18N_NOOP("Belgian") }, + { "bg", I18N_NOOP("Bulgarian") }, + { "br", I18N_NOOP("Portuguese (Brazil)") }, + { "brai", I18N_NOOP("Braille") }, + { "bt", I18N_NOOP("Dzongkha") }, + { "bw", I18N_NOOP("Tswana") }, + { "by", I18N_NOOP("Belarusian") }, + { "ca", I18N_NOOP("French (Canada)") }, + { "cd", I18N_NOOP("French (Democratic Republic of the Congo)") }, + { "ch", I18N_NOOP("German (Switzerland)") }, + { "cm", I18N_NOOP("English (Cameroon)") }, + { "cn", I18N_NOOP("Chinese") }, + { "custom", I18N_NOOP("A user-defined custom Layout") }, + { "cz", I18N_NOOP("Czech") }, + { "de", I18N_NOOP("German") }, + { "dk", I18N_NOOP("Danish") }, + { "dz", I18N_NOOP("Berber (Algeria, Latin)") }, + { "ee", I18N_NOOP("Estonian") }, + { "epo", I18N_NOOP("Esperanto") }, + { "es", I18N_NOOP("Spanish") }, + { "et", I18N_NOOP("Amharic") }, + { "fi", I18N_NOOP("Finnish") }, + { "fo", I18N_NOOP("Faroese") }, + { "fr", I18N_NOOP("French") }, + { "gb", I18N_NOOP("English (UK)") }, + { "ge", I18N_NOOP("Georgian") }, + { "gh", I18N_NOOP("English (Ghana)") }, + { "gn", I18N_NOOP("N'Ko (AZERTY)") }, + { "gr", I18N_NOOP("Greek") }, + { "hr", I18N_NOOP("Croatian") }, + { "hu", I18N_NOOP("Hungarian") }, + { "id", I18N_NOOP("Indonesian (Latin)") }, + { "ie", I18N_NOOP("Irish") }, + { "il", I18N_NOOP("Hebrew") }, + { "in", I18N_NOOP("Indian") }, + { "iq", I18N_NOOP("Iraqi") }, + { "ir", I18N_NOOP("Persian") }, + { "is", I18N_NOOP("Icelandic") }, + { "it", I18N_NOOP("Italian") }, + { "jp", I18N_NOOP("Japanese") }, + { "jv", I18N_NOOP("Indonesian (Javanese)") }, + { "ke", I18N_NOOP("Swahili (Kenya)") }, + { "kg", I18N_NOOP("Kyrgyz") }, + { "kh", I18N_NOOP("Khmer (Cambodia)") }, + { "kr", I18N_NOOP("Korean") }, + { "kz", I18N_NOOP("Kazakh") }, + { "la", I18N_NOOP("Lao") }, + { "latam", I18N_NOOP("Spanish (Latin American)") }, + { "lk", I18N_NOOP("Sinhala (phonetic)") }, + { "lt", I18N_NOOP("Lithuanian") }, + { "lv", I18N_NOOP("Latvian") }, + { "ma", I18N_NOOP("Arabic (Morocco)") }, + { "mao", I18N_NOOP("Maori") }, + { "md", I18N_NOOP("Moldavian") }, + { "me", I18N_NOOP("Montenegrin") }, + { "mk", I18N_NOOP("Macedonian") }, + { "ml", I18N_NOOP("Bambara") }, + { "mm", I18N_NOOP("Burmese") }, + { "mn", I18N_NOOP("Mongolian") }, + { "mt", I18N_NOOP("Maltese") }, + { "mv", I18N_NOOP("Dhivehi") }, + { "my", I18N_NOOP("Malay (Jawi, Arabic Keyboard)") }, + { "ng", I18N_NOOP("English (Nigeria)") }, + { "nl", I18N_NOOP("Dutch") }, + { "no", I18N_NOOP("Norwegian") }, + { "np", I18N_NOOP("Nepali") }, + { "ph", I18N_NOOP("Filipino") }, + { "pk", I18N_NOOP("Urdu (Pakistan)") }, + { "pl", I18N_NOOP("Polish") }, + { "pt", I18N_NOOP("Portuguese") }, + { "ro", I18N_NOOP("Romanian") }, + { "rs", I18N_NOOP("Serbian") }, + { "ru", I18N_NOOP("Russian") }, + { "se", I18N_NOOP("Swedish") }, + { "si", I18N_NOOP("Slovenian") }, + { "sk", I18N_NOOP("Slovak") }, + { "sn", I18N_NOOP("Wolof") }, + { "sy", I18N_NOOP("Arabic (Syria)") }, + { "tg", I18N_NOOP("French (Togo)") }, + { "th", I18N_NOOP("Thai") }, + { "tj", I18N_NOOP("Tajik") }, + { "tm", I18N_NOOP("Turkmen") }, + { "tr", I18N_NOOP("Turkish") }, + { "tw", I18N_NOOP("Taiwanese") }, + { "tz", I18N_NOOP("Swahili (Tanzania)") }, + { "ua", I18N_NOOP("Ukrainian") }, + { "us", I18N_NOOP("English (US)") }, + { "uz", I18N_NOOP("Uzbek") }, + { "vn", I18N_NOOP("Vietnamese") }, + { "za", I18N_NOOP("English (South Africa)") } +}; +static const qint16 layoutDescriptionTblSize = sizeof(layoutDescriptionTbl) / sizeof(layoutDescriptionData); + +static const struct variantDescriptionData { + const char* name; + const char* name2; + const char* description; +} variantDescriptionTbl[] = { + { "af", "fa-olpc", I18N_NOOP("Dari (Afghanistan, OLPC)") }, + { "af", "ps", I18N_NOOP("Pashto") }, + { "af", "ps-olpc", I18N_NOOP("Pashto (Afghanistan, OLPC)") }, + { "af", "uz", I18N_NOOP("Uzbek (Afghanistan)") }, + { "af", "uz-olpc", I18N_NOOP("Uzbek (Afghanistan, OLPC)") }, + { "al", "plisi", I18N_NOOP("Albanian (Plisi)") }, + { "al", "veqilharxhi", I18N_NOOP("Albanian (Veqilharxhi)") }, + { "am", "eastern", I18N_NOOP("Armenian (eastern)") }, + { "am", "eastern-alt", I18N_NOOP("Armenian (alt. eastern)") }, + { "am", "phonetic", I18N_NOOP("Armenian (phonetic)") }, + { "am", "phonetic-alt", I18N_NOOP("Armenian (alt. phonetic)") }, + { "am", "western", I18N_NOOP("Armenian (western)") }, + { "ara", "azerty", I18N_NOOP("Arabic (AZERTY)") }, + { "ara", "azerty_digits", I18N_NOOP("Arabic (AZERTY, Eastern Arabic numerals)") }, + { "ara", "buckwalter", I18N_NOOP("Arabic (Buckwalter)") }, + { "ara", "digits", I18N_NOOP("Arabic (Eastern Arabic numerals)") }, + { "ara", "mac", I18N_NOOP("Arabic (Macintosh)") }, + { "ara", "olpc", I18N_NOOP("Arabic (OLPC)") }, + { "ara", "qwerty", I18N_NOOP("Arabic (QWERTY)") }, + { "ara", "qwerty_digits", I18N_NOOP("Arabic (QWERTY, Eastern Arabic numerals)") }, + { "at", "mac", I18N_NOOP("German (Austria, Macintosh)") }, + { "at", "nodeadkeys", I18N_NOOP("German (Austria, no dead keys)") }, + { "az", "cyrillic", I18N_NOOP("Azerbaijani (Cyrillic)") }, + { "ba", "alternatequotes", I18N_NOOP("Bosnian (with guillemets)") }, + { "ba", "unicode", I18N_NOOP("Bosnian (with Bosnian digraphs)") }, + { "ba", "unicodeus", I18N_NOOP("Bosnian (US, with Bosnian digraphs)") }, + { "ba", "us", I18N_NOOP("Bosnian (US)") }, + { "bd", "probhat", I18N_NOOP("Bangla (Probhat)") }, + { "be", "iso-alternate", I18N_NOOP("Belgian (ISO, alt.)") }, + { "be", "nodeadkeys", I18N_NOOP("Belgian (no dead keys)") }, + { "be", "oss", I18N_NOOP("Belgian (alt.)") }, + { "be", "oss_latin9", I18N_NOOP("Belgian (Latin-9 only, alt.)") }, + { "be", "wang", I18N_NOOP("Belgian (Wang 724 AZERTY)") }, + { "bg", "bas_phonetic", I18N_NOOP("Bulgarian (new phonetic)") }, + { "bg", "bekl", I18N_NOOP("Bulgarian (enhanced)") }, + { "bg", "phonetic", I18N_NOOP("Bulgarian (traditional phonetic)") }, + { "br", "dvorak", I18N_NOOP("Portuguese (Brazil, Dvorak)") }, + { "br", "nativo", I18N_NOOP("Portuguese (Brazil, Nativo)") }, + { "br", "nativo-epo", I18N_NOOP("Esperanto (Brazil, Nativo)") }, + { "br", "nativo-us", I18N_NOOP("Portuguese (Brazil, Nativo for US keyboards)") }, + { "br", "nodeadkeys", I18N_NOOP("Portuguese (Brazil, no dead keys)") }, + { "br", "thinkpad", I18N_NOOP("Portuguese (Brazil, IBM/Lenovo ThinkPad)") }, + { "brai", "left_hand", I18N_NOOP("Braille (left-handed)") }, + { "brai", "left_hand_invert", I18N_NOOP("Braille (left-handed inverted thumb)") }, + { "brai", "right_hand", I18N_NOOP("Braille (right-handed)") }, + { "brai", "right_hand_invert", I18N_NOOP("Braille (right-handed inverted thumb)") }, + { "by", "intl", I18N_NOOP("Belarusian (intl.)") }, + { "by", "latin", I18N_NOOP("Belarusian (Latin)") }, + { "by", "legacy", I18N_NOOP("Belarusian (legacy)") }, + { "by", "ru", I18N_NOOP("Russian (Belarus)") }, + { "ca", "eng", I18N_NOOP("English (Canada)") }, + { "ca", "fr-dvorak", I18N_NOOP("French (Canada, Dvorak)") }, + { "ca", "fr-legacy", I18N_NOOP("French (Canada, legacy)") }, + { "ca", "ike", I18N_NOOP("Inuktitut") }, + { "ca", "multi", I18N_NOOP("Canadian (intl., 1st part)") }, + { "ca", "multi-2gr", I18N_NOOP("Canadian (intl., 2nd part)") }, + { "ca", "multix", I18N_NOOP("Canadian (intl.)") }, + { "ch", "de_mac", I18N_NOOP("German (Switzerland, Macintosh)") }, + { "ch", "de_nodeadkeys", I18N_NOOP("German (Switzerland, no dead keys)") }, + { "ch", "fr", I18N_NOOP("French (Switzerland)") }, + { "ch", "fr_mac", I18N_NOOP("French (Switzerland, Macintosh)") }, + { "ch", "fr_nodeadkeys", I18N_NOOP("French (Switzerland, no dead keys)") }, + { "ch", "legacy", I18N_NOOP("German (Switzerland, legacy)") }, + { "cm", "azerty", I18N_NOOP("Cameroon (AZERTY, intl.)") }, + { "cm", "dvorak", I18N_NOOP("Cameroon (Dvorak, intl.)") }, + { "cm", "french", I18N_NOOP("French (Cameroon)") }, + { "cm", "mmuock", I18N_NOOP("Mmuock") }, + { "cm", "qwerty", I18N_NOOP("Cameroon Multilingual (QWERTY, intl.)") }, + { "cn", "altgr-pinyin", I18N_NOOP("Hanyu Pinyin Letters (with AltGr dead keys)") }, + { "cn", "mon_manchu_galik", I18N_NOOP("Mongolian (Manchu Galik)") }, + { "cn", "mon_todo_galik", I18N_NOOP("Mongolian (Todo Galik)") }, + { "cn", "mon_trad", I18N_NOOP("Mongolian (Bichig)") }, + { "cn", "mon_trad_galik", I18N_NOOP("Mongolian (Galik)") }, + { "cn", "mon_trad_manchu", I18N_NOOP("Mongolian (Manchu)") }, + { "cn", "mon_trad_todo", I18N_NOOP("Mongolian (Todo)") }, + { "cn", "mon_trad_xibe", I18N_NOOP("Mongolian (Xibe)") }, + { "cn", "tib", I18N_NOOP("Tibetan") }, + { "cn", "tib_asciinum", I18N_NOOP("Tibetan (with ASCII numerals)") }, + { "cn", "ug", I18N_NOOP("Uyghur") }, + { "cz", "bksl", I18N_NOOP("Czech (with <\\|> key)") }, + { "cz", "dvorak-ucw", I18N_NOOP("Czech (US, Dvorak, UCW support)") }, + { "cz", "qwerty", I18N_NOOP("Czech (QWERTY)") }, + { "cz", "qwerty-mac", I18N_NOOP("Czech (QWERTY, Macintosh)") }, + { "cz", "qwerty_bksl", I18N_NOOP("Czech (QWERTY, extended backslash)") }, + { "cz", "rus", I18N_NOOP("Russian (Czech, phonetic)") }, + { "cz", "ucw", I18N_NOOP("Czech (UCW, only accented letters)") }, + { "de", "T3", I18N_NOOP("German (T3)") }, + { "de", "deadacute", I18N_NOOP("German (dead acute)") }, + { "de", "deadgraveacute", I18N_NOOP("German (dead grave acute)") }, + { "de", "deadtilde", I18N_NOOP("German (dead tilde)") }, + { "de", "dsb", I18N_NOOP("Lower Sorbian") }, + { "de", "dsb_qwertz", I18N_NOOP("Lower Sorbian (QWERTZ)") }, + { "de", "dvorak", I18N_NOOP("German (Dvorak)") }, + { "de", "e1", I18N_NOOP("German (E1)") }, + { "de", "e2", I18N_NOOP("German (E2)") }, + { "de", "mac", I18N_NOOP("German (Macintosh)") }, + { "de", "mac_nodeadkeys", I18N_NOOP("German (Macintosh, no dead keys)") }, + { "de", "neo", I18N_NOOP("German (Neo 2)") }, + { "de", "nodeadkeys", I18N_NOOP("German (no dead keys)") }, + { "de", "qwerty", I18N_NOOP("German (QWERTY)") }, + { "de", "ro", I18N_NOOP("Romanian (Germany)") }, + { "de", "ro_nodeadkeys", I18N_NOOP("Romanian (Germany, no dead keys)") }, + { "de", "ru", I18N_NOOP("Russian (Germany, phonetic)") }, + { "de", "tr", I18N_NOOP("Turkish (Germany)") }, + { "de", "us", I18N_NOOP("German (US)") }, + { "dk", "dvorak", I18N_NOOP("Danish (Dvorak)") }, + { "dk", "mac", I18N_NOOP("Danish (Macintosh)") }, + { "dk", "mac_nodeadkeys", I18N_NOOP("Danish (Macintosh, no dead keys)") }, + { "dk", "nodeadkeys", I18N_NOOP("Danish (no dead keys)") }, + { "dk", "winkeys", I18N_NOOP("Danish (Windows)") }, + { "dz", "ar", I18N_NOOP("Arabic (Algeria)") }, + { "dz", "azerty-deadkeys", I18N_NOOP("Kabyle (AZERTY, with dead keys)") }, + { "dz", "ber", I18N_NOOP("Berber (Algeria, Tifinagh)") }, + { "dz", "qwerty-gb-deadkeys", I18N_NOOP("Kabyle (QWERTY, UK, with dead keys)") }, + { "dz", "qwerty-us-deadkeys", I18N_NOOP("Kabyle (QWERTY, US, with dead keys)") }, + { "ee", "dvorak", I18N_NOOP("Estonian (Dvorak)") }, + { "ee", "nodeadkeys", I18N_NOOP("Estonian (no dead keys)") }, + { "ee", "us", I18N_NOOP("Estonian (US)") }, + { "epo", "legacy", I18N_NOOP("Esperanto (legacy)") }, + { "es", "ast", I18N_NOOP("Asturian (Spain, with bottom-dot H and L)") }, + { "es", "cat", I18N_NOOP("Catalan (Spain, with middle-dot L)") }, + { "es", "deadtilde", I18N_NOOP("Spanish (dead tilde)") }, + { "es", "dvorak", I18N_NOOP("Spanish (Dvorak)") }, + { "es", "mac", I18N_NOOP("Spanish (Macintosh)") }, + { "es", "nodeadkeys", I18N_NOOP("Spanish (no dead keys)") }, + { "es", "winkeys", I18N_NOOP("Spanish (Windows)") }, + { "fi", "classic", I18N_NOOP("Finnish (classic)") }, + { "fi", "mac", I18N_NOOP("Finnish (Macintosh)") }, + { "fi", "nodeadkeys", I18N_NOOP("Finnish (classic, no dead keys)") }, + { "fi", "smi", I18N_NOOP("Northern Saami (Finland)") }, + { "fi", "winkeys", I18N_NOOP("Finnish (Windows)") }, + { "fo", "nodeadkeys", I18N_NOOP("Faroese (no dead keys)") }, + { "fr", "afnor", I18N_NOOP("French (AZERTY, AFNOR)") }, + { "fr", "azerty", I18N_NOOP("French (AZERTY)") }, + { "fr", "bepo", I18N_NOOP("French (BEPO)") }, + { "fr", "bepo_afnor", I18N_NOOP("French (BEPO, AFNOR)") }, + { "fr", "bepo_latin9", I18N_NOOP("French (BEPO, Latin-9 only)") }, + { "fr", "bre", I18N_NOOP("French (Breton)") }, + { "fr", "dvorak", I18N_NOOP("French (Dvorak)") }, + { "fr", "geo", I18N_NOOP("Georgian (France, AZERTY Tskapo)") }, + { "fr", "latin9", I18N_NOOP("French (legacy, alt.)") }, + { "fr", "latin9_nodeadkeys", I18N_NOOP("French (legacy, alt., no dead keys)") }, + { "fr", "mac", I18N_NOOP("French (Macintosh)") }, + { "fr", "nodeadkeys", I18N_NOOP("French (no dead keys)") }, + { "fr", "oci", I18N_NOOP("Occitan") }, + { "fr", "oss", I18N_NOOP("French (alt.)") }, + { "fr", "oss_latin9", I18N_NOOP("French (alt., Latin-9 only)") }, + { "fr", "oss_nodeadkeys", I18N_NOOP("French (alt., no dead keys)") }, + { "fr", "us", I18N_NOOP("French (US)") }, + { "gb", "colemak", I18N_NOOP("English (UK, Colemak)") }, + { "gb", "colemak_dh", I18N_NOOP("English (UK, Colemak-DH)") }, + { "gb", "dvorak", I18N_NOOP("English (UK, Dvorak)") }, + { "gb", "dvorakukp", I18N_NOOP("English (UK, Dvorak, with UK punctuation)") }, + { "gb", "extd", I18N_NOOP("English (UK, extended, Windows)") }, + { "gb", "gla", I18N_NOOP("Scottish Gaelic") }, + { "gb", "intl", I18N_NOOP("English (UK, intl., with dead keys)") }, + { "gb", "mac", I18N_NOOP("English (UK, Macintosh)") }, + { "gb", "mac_intl", I18N_NOOP("English (UK, Macintosh, intl.)") }, + { "gb", "pl", I18N_NOOP("Polish (British keyboard)") }, + { "ge", "ergonomic", I18N_NOOP("Georgian (ergonomic)") }, + { "ge", "mess", I18N_NOOP("Georgian (MESS)") }, + { "ge", "os", I18N_NOOP("Ossetian (Georgia)") }, + { "ge", "ru", I18N_NOOP("Russian (Georgia)") }, + { "gh", "akan", I18N_NOOP("Akan") }, + { "gh", "avn", I18N_NOOP("Avatime") }, + { "gh", "ewe", I18N_NOOP("Ewe") }, + { "gh", "fula", I18N_NOOP("Fula") }, + { "gh", "ga", I18N_NOOP("Ga") }, + { "gh", "generic", I18N_NOOP("English (Ghana, multilingual)") }, + { "gh", "gillbt", I18N_NOOP("English (Ghana, GILLBT)") }, + { "gh", "hausa", I18N_NOOP("Hausa (Ghana)") }, + { "gr", "extended", I18N_NOOP("Greek (extended)") }, + { "gr", "nodeadkeys", I18N_NOOP("Greek (no dead keys)") }, + { "gr", "polytonic", I18N_NOOP("Greek (polytonic)") }, + { "gr", "simple", I18N_NOOP("Greek (simple)") }, + { "hr", "alternatequotes", I18N_NOOP("Croatian (with guillemets)") }, + { "hr", "unicode", I18N_NOOP("Croatian (with Croatian digraphs)") }, + { "hr", "unicodeus", I18N_NOOP("Croatian (US, with Croatian digraphs)") }, + { "hr", "us", I18N_NOOP("Croatian (US)") }, + { "hu", "101_qwerty_comma_dead", I18N_NOOP("Hungarian (QWERTY, 101-key, comma, dead keys)") }, + { "hu", "101_qwerty_comma_nodead", I18N_NOOP("Hungarian (QWERTY, 101-key, comma, no dead keys)") }, + { "hu", "101_qwerty_dot_dead", I18N_NOOP("Hungarian (QWERTY, 101-key, dot, dead keys)") }, + { "hu", "101_qwerty_dot_nodead", I18N_NOOP("Hungarian (QWERTY, 101-key, dot, no dead keys)") }, + { "hu", "101_qwertz_comma_dead", I18N_NOOP("Hungarian (QWERTZ, 101-key, comma, dead keys)") }, + { "hu", "101_qwertz_comma_nodead", I18N_NOOP("Hungarian (QWERTZ, 101-key, comma, no dead keys)") }, + { "hu", "101_qwertz_dot_dead", I18N_NOOP("Hungarian (QWERTZ, 101-key, dot, dead keys)") }, + { "hu", "101_qwertz_dot_nodead", I18N_NOOP("Hungarian (QWERTZ, 101-key, dot, no dead keys)") }, + { "hu", "102_qwerty_comma_dead", I18N_NOOP("Hungarian (QWERTY, 102-key, comma, dead keys)") }, + { "hu", "102_qwerty_comma_nodead", I18N_NOOP("Hungarian (QWERTY, 102-key, comma, no dead keys)") }, + { "hu", "102_qwerty_dot_dead", I18N_NOOP("Hungarian (QWERTY, 102-key, dot, dead keys)") }, + { "hu", "102_qwerty_dot_nodead", I18N_NOOP("Hungarian (QWERTY, 102-key, dot, no dead keys)") }, + { "hu", "102_qwertz_comma_dead", I18N_NOOP("Hungarian (QWERTZ, 102-key, comma, dead keys)") }, + { "hu", "102_qwertz_comma_nodead", I18N_NOOP("Hungarian (QWERTZ, 102-key, comma, no dead keys)") }, + { "hu", "102_qwertz_dot_dead", I18N_NOOP("Hungarian (QWERTZ, 102-key, dot, dead keys)") }, + { "hu", "102_qwertz_dot_nodead", I18N_NOOP("Hungarian (QWERTZ, 102-key, dot, no dead keys)") }, + { "hu", "nodeadkeys", I18N_NOOP("Hungarian (no dead keys)") }, + { "hu", "qwerty", I18N_NOOP("Hungarian (QWERTY)") }, + { "hu", "standard", I18N_NOOP("Hungarian (standard)") }, + { "id", "phonetic", I18N_NOOP("Indonesian (Arab Pegon, phonetic)") }, + { "id", "phoneticx", I18N_NOOP("Indonesian (Arab Pegon, extended phonetic)") }, + { "ie", "CloGaelach", I18N_NOOP("CloGaelach") }, + { "ie", "UnicodeExpert", I18N_NOOP("Irish (UnicodeExpert)") }, + { "ie", "ogam", I18N_NOOP("Ogham") }, + { "ie", "ogam_is434", I18N_NOOP("Ogham (IS434)") }, + { "il", "biblical", I18N_NOOP("Hebrew (Biblical, Tiro)") }, + { "il", "lyx", I18N_NOOP("Hebrew (lyx)") }, + { "il", "phonetic", I18N_NOOP("Hebrew (phonetic)") }, + { "in", "ben", I18N_NOOP("Bangla (India)") }, + { "in", "ben_baishakhi", I18N_NOOP("Bangla (India, Baishakhi)") }, + { "in", "ben_bornona", I18N_NOOP("Bangla (India, Bornona)") }, + { "in", "ben_gitanjali", I18N_NOOP("Bangla (India, Gitanjali)") }, + { "in", "ben_inscript", I18N_NOOP("Bangla (India, Baishakhi InScript)") }, + { "in", "ben_probhat", I18N_NOOP("Bangla (India, Probhat)") }, + { "in", "bolnagri", I18N_NOOP("Hindi (Bolnagri)") }, + { "in", "eeyek", I18N_NOOP("Manipuri (Eeyek)") }, + { "in", "eng", I18N_NOOP("English (India, with rupee)") }, + { "in", "guj", I18N_NOOP("Gujarati") }, + { "in", "guru", I18N_NOOP("Punjabi (Gurmukhi)") }, + { "in", "hin-kagapa", I18N_NOOP("Hindi (KaGaPa, phonetic)") }, + { "in", "hin-wx", I18N_NOOP("Hindi (Wx)") }, + { "in", "iipa", I18N_NOOP("Indic IPA") }, + { "in", "jhelum", I18N_NOOP("Punjabi (Gurmukhi Jhelum)") }, + { "in", "kan", I18N_NOOP("Kannada") }, + { "in", "kan-kagapa", I18N_NOOP("Kannada (KaGaPa, phonetic)") }, + { "in", "mal", I18N_NOOP("Malayalam") }, + { "in", "mal_enhanced", I18N_NOOP("Malayalam (enhanced InScript, with rupee)") }, + { "in", "mal_lalitha", I18N_NOOP("Malayalam (Lalitha)") }, + { "in", "mar-kagapa", I18N_NOOP("Marathi (KaGaPa, phonetic)") }, + { "in", "marathi", I18N_NOOP("Marathi (enhanced InScript)") }, + { "in", "olck", I18N_NOOP("Ol Chiki") }, + { "in", "ori", I18N_NOOP("Oriya") }, + { "in", "ori-bolnagri", I18N_NOOP("Oriya (Bolnagri)") }, + { "in", "ori-wx", I18N_NOOP("Oriya (Wx)") }, + { "in", "san-kagapa", I18N_NOOP("Sanskrit (KaGaPa, phonetic)") }, + { "in", "tam", I18N_NOOP("Tamil (InScript)") }, + { "in", "tam_tamilnet", I18N_NOOP("Tamil (TamilNet '99)") }, + { "in", "tam_tamilnet_TAB", I18N_NOOP("Tamil (TamilNet '99, TAB encoding)") }, + { "in", "tam_tamilnet_TSCII", I18N_NOOP("Tamil (TamilNet '99, TSCII encoding)") }, + { "in", "tam_tamilnet_with_tam_nums", I18N_NOOP("Tamil (TamilNet '99 with Tamil numerals)") }, + { "in", "tel", I18N_NOOP("Telugu") }, + { "in", "tel-kagapa", I18N_NOOP("Telugu (KaGaPa, phonetic)") }, + { "in", "tel-sarala", I18N_NOOP("Telugu (Sarala)") }, + { "in", "urd-phonetic", I18N_NOOP("Urdu (phonetic)") }, + { "in", "urd-phonetic3", I18N_NOOP("Urdu (alt. phonetic)") }, + { "in", "urd-winkeys", I18N_NOOP("Urdu (Windows)") }, + { "iq", "ku", I18N_NOOP("Kurdish (Iraq, Latin Q)") }, + { "iq", "ku_alt", I18N_NOOP("Kurdish (Iraq, Latin Alt-Q)") }, + { "iq", "ku_ara", I18N_NOOP("Kurdish (Iraq, Arabic-Latin)") }, + { "iq", "ku_f", I18N_NOOP("Kurdish (Iraq, F)") }, + { "ir", "ku", I18N_NOOP("Kurdish (Iran, Latin Q)") }, + { "ir", "ku_alt", I18N_NOOP("Kurdish (Iran, Latin Alt-Q)") }, + { "ir", "ku_ara", I18N_NOOP("Kurdish (Iran, Arabic-Latin)") }, + { "ir", "ku_f", I18N_NOOP("Kurdish (Iran, F)") }, + { "ir", "pes_keypad", I18N_NOOP("Persian (with Persian keypad)") }, + { "is", "dvorak", I18N_NOOP("Icelandic (Dvorak)") }, + { "is", "mac", I18N_NOOP("Icelandic (Macintosh)") }, + { "is", "mac_legacy", I18N_NOOP("Icelandic (Macintosh, legacy)") }, + { "it", "fur", I18N_NOOP("Friulian (Italy)") }, + { "it", "geo", I18N_NOOP("Georgian (Italy)") }, + { "it", "ibm", I18N_NOOP("Italian (IBM 142)") }, + { "it", "intl", I18N_NOOP("Italian (intl., with dead keys)") }, + { "it", "mac", I18N_NOOP("Italian (Macintosh)") }, + { "it", "nodeadkeys", I18N_NOOP("Italian (no dead keys)") }, + { "it", "scn", I18N_NOOP("Sicilian") }, + { "it", "us", I18N_NOOP("Italian (US)") }, + { "it", "winkeys", I18N_NOOP("Italian (Windows)") }, + { "jp", "OADG109A", I18N_NOOP("Japanese (OADG 109A)") }, + { "jp", "dvorak", I18N_NOOP("Japanese (Dvorak)") }, + { "jp", "kana", I18N_NOOP("Japanese (Kana)") }, + { "jp", "kana86", I18N_NOOP("Japanese (Kana 86)") }, + { "jp", "mac", I18N_NOOP("Japanese (Macintosh)") }, + { "ke", "kik", I18N_NOOP("Kikuyu") }, + { "kg", "phonetic", I18N_NOOP("Kyrgyz (phonetic)") }, + { "kr", "kr104", I18N_NOOP("Korean (101/104-key compatible)") }, + { "kz", "ext", I18N_NOOP("Kazakh (extended)") }, + { "kz", "kazrus", I18N_NOOP("Kazakh (with Russian)") }, + { "kz", "latin", I18N_NOOP("Kazakh (Latin)") }, + { "kz", "ruskaz", I18N_NOOP("Russian (Kazakhstan, with Kazakh)") }, + { "la", "stea", I18N_NOOP("Lao (STEA)") }, + { "latam", "colemak", I18N_NOOP("Spanish (Latin American, Colemak)") }, + { "latam", "colemak-gaming", I18N_NOOP("Spanish (Latin American, Colemak for gaming)") }, + { "latam", "deadtilde", I18N_NOOP("Spanish (Latin American, dead tilde)") }, + { "latam", "dvorak", I18N_NOOP("Spanish (Latin American, Dvorak)") }, + { "latam", "nodeadkeys", I18N_NOOP("Spanish (Latin American, no dead keys)") }, + { "lk", "tam_TAB", I18N_NOOP("Tamil (Sri Lanka, TamilNet '99, TAB encoding)") }, + { "lk", "tam_unicode", I18N_NOOP("Tamil (Sri Lanka, TamilNet '99)") }, + { "lk", "us", I18N_NOOP("Sinhala (US)") }, + { "lt", "ibm", I18N_NOOP("Lithuanian (IBM LST 1205-92)") }, + { "lt", "lekp", I18N_NOOP("Lithuanian (LEKP)") }, + { "lt", "lekpa", I18N_NOOP("Lithuanian (LEKPa)") }, + { "lt", "ratise", I18N_NOOP("Lithuanian (Ratise)") }, + { "lt", "sgs", I18N_NOOP("Samogitian") }, + { "lt", "std", I18N_NOOP("Lithuanian (standard)") }, + { "lt", "us", I18N_NOOP("Lithuanian (US)") }, + { "lv", "adapted", I18N_NOOP("Latvian (adapted)") }, + { "lv", "apostrophe", I18N_NOOP("Latvian (apostrophe)") }, + { "lv", "ergonomic", I18N_NOOP("Latvian (ergonomic, ŪGJRMV)") }, + { "lv", "fkey", I18N_NOOP("Latvian (F)") }, + { "lv", "modern", I18N_NOOP("Latvian (modern)") }, + { "lv", "tilde", I18N_NOOP("Latvian (tilde)") }, + { "ma", "french", I18N_NOOP("French (Morocco)") }, + { "ma", "rif", I18N_NOOP("Tarifit") }, + { "ma", "tifinagh", I18N_NOOP("Berber (Morocco, Tifinagh)") }, + { "ma", "tifinagh-alt", I18N_NOOP("Berber (Morocco, Tifinagh alt.)") }, + { "ma", "tifinagh-alt-phonetic", I18N_NOOP("Berber (Morocco, Tifinagh phonetic, alt.)") }, + { "ma", "tifinagh-extended", I18N_NOOP("Berber (Morocco, Tifinagh extended)") }, + { "ma", "tifinagh-extended-phonetic", I18N_NOOP("Berber (Morocco, Tifinagh extended phonetic)") }, + { "ma", "tifinagh-phonetic", I18N_NOOP("Berber (Morocco, Tifinagh phonetic)") }, + { "md", "gag", I18N_NOOP("Moldavian (Gagauz)") }, + { "me", "cyrillic", I18N_NOOP("Montenegrin (Cyrillic)") }, + { "me", "cyrillicalternatequotes", I18N_NOOP("Montenegrin (Cyrillic, with guillemets)") }, + { "me", "cyrillicyz", I18N_NOOP("Montenegrin (Cyrillic, ZE and ZHE swapped)") }, + { "me", "latinalternatequotes", I18N_NOOP("Montenegrin (Latin, with guillemets)") }, + { "me", "latinunicode", I18N_NOOP("Montenegrin (Latin, Unicode)") }, + { "me", "latinunicodeyz", I18N_NOOP("Montenegrin (Latin, Unicode, QWERTY)") }, + { "me", "latinyz", I18N_NOOP("Montenegrin (Latin, QWERTY)") }, + { "mk", "nodeadkeys", I18N_NOOP("Macedonian (no dead keys)") }, + { "ml", "fr-oss", I18N_NOOP("French (Mali, alt.)") }, + { "ml", "us-intl", I18N_NOOP("English (Mali, US, intl.)") }, + { "ml", "us-mac", I18N_NOOP("English (Mali, US, Macintosh)") }, + { "mm", "mnw", I18N_NOOP("Mon") }, + { "mm", "mnw-a1", I18N_NOOP("Mon (A1)") }, + { "mm", "shn", I18N_NOOP("Shan") }, + { "mm", "zawgyi", I18N_NOOP("Burmese Zawgyi") }, + { "mm", "zgt", I18N_NOOP("Shan (Zawgyi Tai)") }, + { "mt", "alt-gb", I18N_NOOP("Maltese (UK, with AltGr overrides)") }, + { "mt", "alt-us", I18N_NOOP("Maltese (US, with AltGr overrides)") }, + { "mt", "us", I18N_NOOP("Maltese (US)") }, + { "my", "phonetic", I18N_NOOP("Malay (Jawi, phonetic)") }, + { "ng", "hausa", I18N_NOOP("Hausa (Nigeria)") }, + { "ng", "igbo", I18N_NOOP("Igbo") }, + { "ng", "yoruba", I18N_NOOP("Yoruba") }, + { "nl", "mac", I18N_NOOP("Dutch (Macintosh)") }, + { "nl", "std", I18N_NOOP("Dutch (standard)") }, + { "nl", "us", I18N_NOOP("Dutch (US)") }, + { "no", "colemak", I18N_NOOP("Norwegian (Colemak)") }, + { "no", "dvorak", I18N_NOOP("Norwegian (Dvorak)") }, + { "no", "mac", I18N_NOOP("Norwegian (Macintosh)") }, + { "no", "mac_nodeadkeys", I18N_NOOP("Norwegian (Macintosh, no dead keys)") }, + { "no", "nodeadkeys", I18N_NOOP("Norwegian (no dead keys)") }, + { "no", "smi", I18N_NOOP("Northern Saami (Norway)") }, + { "no", "smi_nodeadkeys", I18N_NOOP("Northern Saami (Norway, no dead keys)") }, + { "no", "winkeys", I18N_NOOP("Norwegian (Windows)") }, + { "ph", "capewell-dvorak", I18N_NOOP("Filipino (Capewell-Dvorak, Latin)") }, + { "ph", "capewell-dvorak-bay", I18N_NOOP("Filipino (Capewell-Dvorak, Baybayin)") }, + { "ph", "capewell-qwerf2k6", I18N_NOOP("Filipino (Capewell-QWERF 2006, Latin)") }, + { "ph", "capewell-qwerf2k6-bay", I18N_NOOP("Filipino (Capewell-QWERF 2006, Baybayin)") }, + { "ph", "colemak", I18N_NOOP("Filipino (Colemak, Latin)") }, + { "ph", "colemak-bay", I18N_NOOP("Filipino (Colemak, Baybayin)") }, + { "ph", "dvorak", I18N_NOOP("Filipino (Dvorak, Latin)") }, + { "ph", "dvorak-bay", I18N_NOOP("Filipino (Dvorak, Baybayin)") }, + { "ph", "qwerty-bay", I18N_NOOP("Filipino (QWERTY, Baybayin)") }, + { "pk", "ara", I18N_NOOP("Arabic (Pakistan)") }, + { "pk", "snd", I18N_NOOP("Sindhi") }, + { "pk", "urd-crulp", I18N_NOOP("Urdu (Pakistan, CRULP)") }, + { "pk", "urd-nla", I18N_NOOP("Urdu (Pakistan, NLA)") }, + { "pl", "csb", I18N_NOOP("Kashubian") }, + { "pl", "dvorak", I18N_NOOP("Polish (Dvorak)") }, + { "pl", "dvorak_altquotes", I18N_NOOP("Polish (Dvorak, with Polish quotes on key 1)") }, + { "pl", "dvorak_quotes", I18N_NOOP("Polish (Dvorak, with Polish quotes on quotemark key)") }, + { "pl", "dvp", I18N_NOOP("Polish (programmer Dvorak)") }, + { "pl", "legacy", I18N_NOOP("Polish (legacy)") }, + { "pl", "qwertz", I18N_NOOP("Polish (QWERTZ)") }, + { "pl", "ru_phonetic_dvorak", I18N_NOOP("Russian (Poland, phonetic Dvorak)") }, + { "pl", "szl", I18N_NOOP("Silesian") }, + { "pt", "mac", I18N_NOOP("Portuguese (Macintosh)") }, + { "pt", "mac_nodeadkeys", I18N_NOOP("Portuguese (Macintosh, no dead keys)") }, + { "pt", "nativo", I18N_NOOP("Portuguese (Nativo)") }, + { "pt", "nativo-epo", I18N_NOOP("Esperanto (Portugal, Nativo)") }, + { "pt", "nativo-us", I18N_NOOP("Portuguese (Nativo for US keyboards)") }, + { "pt", "nodeadkeys", I18N_NOOP("Portuguese (no dead keys)") }, + { "ro", "std", I18N_NOOP("Romanian (standard)") }, + { "ro", "winkeys", I18N_NOOP("Romanian (Windows)") }, + { "rs", "alternatequotes", I18N_NOOP("Serbian (Cyrillic, with guillemets)") }, + { "rs", "latin", I18N_NOOP("Serbian (Latin)") }, + { "rs", "latinalternatequotes", I18N_NOOP("Serbian (Latin, with guillemets)") }, + { "rs", "latinunicode", I18N_NOOP("Serbian (Latin, Unicode)") }, + { "rs", "latinunicodeyz", I18N_NOOP("Serbian (Latin, Unicode, QWERTY)") }, + { "rs", "latinyz", I18N_NOOP("Serbian (Latin, QWERTY)") }, + { "rs", "rue", I18N_NOOP("Pannonian Rusyn") }, + { "rs", "yz", I18N_NOOP("Serbian (Cyrillic, ZE and ZHE swapped)") }, + { "ru", "bak", I18N_NOOP("Bashkirian") }, + { "ru", "chm", I18N_NOOP("Mari") }, + { "ru", "cv", I18N_NOOP("Chuvash") }, + { "ru", "cv_latin", I18N_NOOP("Chuvash (Latin)") }, + { "ru", "dos", I18N_NOOP("Russian (DOS)") }, + { "ru", "kom", I18N_NOOP("Komi") }, + { "ru", "legacy", I18N_NOOP("Russian (legacy)") }, + { "ru", "mac", I18N_NOOP("Russian (Macintosh)") }, + { "ru", "os_legacy", I18N_NOOP("Ossetian (legacy)") }, + { "ru", "os_winkeys", I18N_NOOP("Ossetian (Windows)") }, + { "ru", "phonetic", I18N_NOOP("Russian (phonetic)") }, + { "ru", "phonetic_YAZHERTY", I18N_NOOP("Russian (phonetic, YAZHERTY)") }, + { "ru", "phonetic_azerty", I18N_NOOP("Russian (phonetic, AZERTY)") }, + { "ru", "phonetic_dvorak", I18N_NOOP("Russian (phonetic, Dvorak)") }, + { "ru", "phonetic_fr", I18N_NOOP("Russian (phonetic, French)") }, + { "ru", "phonetic_winkeys", I18N_NOOP("Russian (phonetic, Windows)") }, + { "ru", "sah", I18N_NOOP("Yakut") }, + { "ru", "srp", I18N_NOOP("Serbian (Russia)") }, + { "ru", "tt", I18N_NOOP("Tatar") }, + { "ru", "typewriter", I18N_NOOP("Russian (typewriter)") }, + { "ru", "typewriter-legacy", I18N_NOOP("Russian (typewriter, legacy)") }, + { "ru", "udm", I18N_NOOP("Udmurt") }, + { "ru", "xal", I18N_NOOP("Kalmyk") }, + { "se", "dvorak", I18N_NOOP("Swedish (Dvorak)") }, + { "se", "mac", I18N_NOOP("Swedish (Macintosh)") }, + { "se", "nodeadkeys", I18N_NOOP("Swedish (no dead keys)") }, + { "se", "rus", I18N_NOOP("Russian (Sweden, phonetic)") }, + { "se", "rus_nodeadkeys", I18N_NOOP("Russian (Sweden, phonetic, no dead keys)") }, + { "se", "smi", I18N_NOOP("Northern Saami (Sweden)") }, + { "se", "svdvorak", I18N_NOOP("Swedish (Svdvorak)") }, + { "se", "swl", I18N_NOOP("Swedish Sign Language") }, + { "se", "us", I18N_NOOP("Swedish (US)") }, + { "se", "us_dvorak", I18N_NOOP("Swedish (Dvorak, intl.)") }, + { "si", "alternatequotes", I18N_NOOP("Slovenian (with guillemets)") }, + { "si", "us", I18N_NOOP("Slovenian (US)") }, + { "sk", "bksl", I18N_NOOP("Slovak (extended backslash)") }, + { "sk", "qwerty", I18N_NOOP("Slovak (QWERTY)") }, + { "sk", "qwerty_bksl", I18N_NOOP("Slovak (QWERTY, extended backslash)") }, + { "sy", "ku", I18N_NOOP("Kurdish (Syria, Latin Q)") }, + { "sy", "ku_alt", I18N_NOOP("Kurdish (Syria, Latin Alt-Q)") }, + { "sy", "ku_f", I18N_NOOP("Kurdish (Syria, F)") }, + { "sy", "syc", I18N_NOOP("Syriac") }, + { "sy", "syc_phonetic", I18N_NOOP("Syriac (phonetic)") }, + { "th", "pat", I18N_NOOP("Thai (Pattachote)") }, + { "th", "tis", I18N_NOOP("Thai (TIS-820.2538)") }, + { "tj", "legacy", I18N_NOOP("Tajik (legacy)") }, + { "tm", "alt", I18N_NOOP("Turkmen (Alt-Q)") }, + { "tr", "alt", I18N_NOOP("Turkish (Alt-Q)") }, + { "tr", "f", I18N_NOOP("Turkish (F)") }, + { "tr", "intl", I18N_NOOP("Turkish (intl., with dead keys)") }, + { "tr", "ku", I18N_NOOP("Kurdish (Turkey, Latin Q)") }, + { "tr", "ku_alt", I18N_NOOP("Kurdish (Turkey, Latin Alt-Q)") }, + { "tr", "ku_f", I18N_NOOP("Kurdish (Turkey, F)") }, + { "tr", "ot", I18N_NOOP("Ottoman (Q)") }, + { "tr", "otf", I18N_NOOP("Ottoman (F)") }, + { "tr", "otk", I18N_NOOP("Old Turkic") }, + { "tr", "otkf", I18N_NOOP("Old Turkic (F)") }, + { "tw", "indigenous", I18N_NOOP("Taiwanese (indigenous)") }, + { "tw", "saisiyat", I18N_NOOP("Saisiyat (Taiwan)") }, + { "ua", "crh", I18N_NOOP("Crimean Tatar (Turkish Q)") }, + { "ua", "crh_alt", I18N_NOOP("Crimean Tatar (Turkish Alt-Q)") }, + { "ua", "crh_f", I18N_NOOP("Crimean Tatar (Turkish F)") }, + { "ua", "homophonic", I18N_NOOP("Ukrainian (homophonic)") }, + { "ua", "legacy", I18N_NOOP("Ukrainian (legacy)") }, + { "ua", "macOS", I18N_NOOP("Ukrainian (macOS)") }, + { "ua", "phonetic", I18N_NOOP("Ukrainian (phonetic)") }, + { "ua", "rstu", I18N_NOOP("Ukrainian (standard RSTU)") }, + { "ua", "rstu_ru", I18N_NOOP("Russian (Ukraine, standard RSTU)") }, + { "ua", "typewriter", I18N_NOOP("Ukrainian (typewriter)") }, + { "ua", "winkeys", I18N_NOOP("Ukrainian (Windows)") }, + { "us", "alt-intl", I18N_NOOP("English (US, alt. intl.)") }, + { "us", "altgr-intl", I18N_NOOP("English (intl., with AltGr dead keys)") }, + { "us", "chr", I18N_NOOP("Cherokee") }, + { "us", "colemak", I18N_NOOP("English (Colemak)") }, + { "us", "colemak_dh", I18N_NOOP("English (Colemak-DH)") }, + { "us", "colemak_dh_iso", I18N_NOOP("English (Colemak-DH ISO)") }, + { "us", "dvorak", I18N_NOOP("English (Dvorak)") }, + { "us", "dvorak-alt-intl", I18N_NOOP("English (Dvorak, alt. intl.)") }, + { "us", "dvorak-classic", I18N_NOOP("English (classic Dvorak)") }, + { "us", "dvorak-intl", I18N_NOOP("English (Dvorak, intl., with dead keys)") }, + { "us", "dvorak-l", I18N_NOOP("English (Dvorak, left-handed)") }, + { "us", "dvorak-mac", I18N_NOOP("English (Dvorak, Macintosh)") }, + { "us", "dvorak-r", I18N_NOOP("English (Dvorak, right-handed)") }, + { "us", "dvp", I18N_NOOP("English (programmer Dvorak)") }, + { "us", "euro", I18N_NOOP("English (US, euro on 5)") }, + { "us", "haw", I18N_NOOP("Hawaiian") }, + { "us", "hbs", I18N_NOOP("Serbo-Croatian (US)") }, + { "us", "intl", I18N_NOOP("English (US, intl., with dead keys)") }, + { "us", "mac", I18N_NOOP("English (Macintosh)") }, + { "us", "norman", I18N_NOOP("English (Norman)") }, + { "us", "olpc2", I18N_NOOP("English (the divide/multiply toggle the layout)") }, + { "us", "rus", I18N_NOOP("Russian (US, phonetic)") }, + { "us", "symbolic", I18N_NOOP("English (US, Symbolic)") }, + { "us", "workman", I18N_NOOP("English (Workman)") }, + { "us", "workman-intl", I18N_NOOP("English (Workman, intl., with dead keys)") }, + { "uz", "latin", I18N_NOOP("Uzbek (Latin)") }, + { "vn", "fr", I18N_NOOP("Vietnamese (French)") }, + { "vn", "us", I18N_NOOP("Vietnamese (US)") } +}; +static const qint16 variantDescriptionTblSize = sizeof(variantDescriptionTbl) / sizeof(variantDescriptionData); + +static const struct optionDescriptionData { + const char* name; + const char* description; +} optionDescriptionTbl[] = { + { "altwin", I18N_NOOP("Alt and Win behavior") }, + { "altwin:alt_super_win", I18N_NOOP("Alt is mapped to Right Win, Super to Menu") }, + { "altwin:alt_win", I18N_NOOP("Alt is mapped to Win and the usual Alt") }, + { "altwin:ctrl_alt_win", I18N_NOOP("Ctrl is mapped to Alt, Alt to Win") }, + { "altwin:ctrl_rwin", I18N_NOOP("Ctrl is mapped to Right Win and the usual Ctrl") }, + { "altwin:ctrl_win", I18N_NOOP("Ctrl is mapped to Win and the usual Ctrl") }, + { "altwin:hyper_win", I18N_NOOP("Hyper is mapped to Win") }, + { "altwin:left_meta_win", I18N_NOOP("Meta is mapped to Left Win") }, + { "altwin:menu", I18N_NOOP("Add the standard behavior to Menu key") }, + { "altwin:menu_win", I18N_NOOP("Menu is mapped to Win") }, + { "altwin:meta_alt", I18N_NOOP("Alt and Meta are on Alt") }, + { "altwin:meta_win", I18N_NOOP("Meta is mapped to Win") }, + { "altwin:prtsc_rwin", I18N_NOOP("Win is mapped to PrtSc and the usual Win") }, + { "altwin:swap_alt_win", I18N_NOOP("Alt is swapped with Win") }, + { "altwin:swap_lalt_lwin", I18N_NOOP("Left Alt is swapped with Left Win") }, + { "apple:alupckeys", I18N_NOOP("Apple Aluminium emulates Pause, PrtSc, Scroll Lock") }, + { "caps", I18N_NOOP("Caps Lock behavior") }, + { "caps:backspace", I18N_NOOP("Make Caps Lock an additional Backspace") }, + { "caps:capslock", I18N_NOOP("Caps Lock toggles normal capitalization of alphabetic characters") }, + { "caps:ctrl_modifier", I18N_NOOP("Make Caps Lock an additional Ctrl") }, + { "caps:escape", I18N_NOOP("Make Caps Lock an additional Esc") }, + { "caps:escape_shifted_capslock", I18N_NOOP("Make Caps Lock an additional Esc, but Shift + Caps Lock is the regular Caps Lock") }, + { "caps:hyper", I18N_NOOP("Make Caps Lock an additional Hyper") }, + { "caps:internal", I18N_NOOP("Caps Lock uses internal capitalization; Shift \"pauses\" Caps Lock") }, + { "caps:internal_nocancel", I18N_NOOP("Caps Lock uses internal capitalization; Shift does not affect Caps Lock") }, + { "caps:menu", I18N_NOOP("Make Caps Lock an additional Menu key") }, + { "caps:none", I18N_NOOP("Caps Lock is disabled") }, + { "caps:numlock", I18N_NOOP("Make Caps Lock an additional Num Lock") }, + { "caps:shift", I18N_NOOP("Caps Lock acts as Shift with locking; Shift \"pauses\" Caps Lock") }, + { "caps:shift_nocancel", I18N_NOOP("Caps Lock acts as Shift with locking; Shift does not affect Caps Lock") }, + { "caps:shiftlock", I18N_NOOP("Caps Lock toggles Shift Lock (affects all keys)") }, + { "caps:super", I18N_NOOP("Make Caps Lock an additional Super") }, + { "caps:swapescape", I18N_NOOP("Swap Esc and Caps Lock") }, + { "compat", I18N_NOOP("Compatibility options") }, + { "compose:102", I18N_NOOP("The \"< >\" key") }, + { "compose:102-altgr", I18N_NOOP("3rd level of the \"< >\" key") }, + { "compose:caps", I18N_NOOP("Caps Lock") }, + { "compose:caps-altgr", I18N_NOOP("3rd level of Caps Lock") }, + { "compose:lctrl", I18N_NOOP("Left Ctrl") }, + { "compose:lctrl-altgr", I18N_NOOP("3rd level of Left Ctrl") }, + { "compose:lwin", I18N_NOOP("Left Win") }, + { "compose:lwin-altgr", I18N_NOOP("3rd level of Left Win") }, + { "compose:menu", I18N_NOOP("Menu") }, + { "compose:menu-altgr", I18N_NOOP("3rd level of Menu") }, + { "compose:paus", I18N_NOOP("Pause") }, + { "compose:prsc", I18N_NOOP("PrtSc") }, + { "compose:ralt", I18N_NOOP("Right Alt") }, + { "compose:rctrl", I18N_NOOP("Right Ctrl") }, + { "compose:rctrl-altgr", I18N_NOOP("3rd level of Right Ctrl") }, + { "compose:rwin", I18N_NOOP("Right Win") }, + { "compose:rwin-altgr", I18N_NOOP("3rd level of Right Win") }, + { "compose:sclk", I18N_NOOP("Scroll Lock") }, + { "ctrl", I18N_NOOP("Ctrl position") }, + { "ctrl:aa_ctrl", I18N_NOOP("At the bottom left") }, + { "ctrl:ac_ctrl", I18N_NOOP("To the left of \"A\"") }, + { "ctrl:lctrl_meta", I18N_NOOP("Left Ctrl as Meta") }, + { "ctrl:menu_rctrl", I18N_NOOP("Menu as Right Ctrl") }, + { "ctrl:nocaps", I18N_NOOP("Caps Lock as Ctrl") }, + { "ctrl:rctrl_ralt", I18N_NOOP("Right Ctrl as Right Alt") }, + { "ctrl:swap_lalt_lctl", I18N_NOOP("Swap Left Alt with Left Ctrl") }, + { "ctrl:swap_lalt_lctl_lwin", I18N_NOOP("Left Alt as Ctrl, Left Ctrl as Win, Left Win as Left Alt") }, + { "ctrl:swap_lwin_lctl", I18N_NOOP("Swap Left Win with Left Ctrl") }, + { "ctrl:swap_rwin_rctl", I18N_NOOP("Swap Right Win with Right Ctrl") }, + { "ctrl:swapcaps", I18N_NOOP("Swap Ctrl and Caps Lock") }, + { "ctrl:swapcaps_hyper", I18N_NOOP("Caps Lock as Ctrl, Ctrl as Hyper") }, + { "currencysign", I18N_NOOP("Currency signs") }, + { "esperanto", I18N_NOOP("Esperanto letters with superscripts") }, + { "esperanto:colemak", I18N_NOOP("At the corresponding key in a Colemak layout") }, + { "esperanto:dvorak", I18N_NOOP("At the corresponding key in a Dvorak layout") }, + { "esperanto:qwerty", I18N_NOOP("At the corresponding key in a QWERTY layout") }, + { "eurosign:2", I18N_NOOP("Euro on 2") }, + { "eurosign:4", I18N_NOOP("Euro on 4") }, + { "eurosign:5", I18N_NOOP("Euro on 5") }, + { "eurosign:e", I18N_NOOP("Euro on E") }, + { "grab:break_actions", I18N_NOOP("Allow breaking grabs with keyboard actions (warning: security risk)") }, + { "grab:debug", I18N_NOOP("Allow grab and window tree logging") }, + { "grp", I18N_NOOP("Switching to another layout") }, + { "grp:alt_caps_toggle", I18N_NOOP("Alt+Caps Lock") }, + { "grp:alt_shift_toggle", I18N_NOOP("Alt+Shift") }, + { "grp:alt_space_toggle", I18N_NOOP("Alt+Space") }, + { "grp:alts_toggle", I18N_NOOP("Both Alt together") }, + { "grp:caps_switch", I18N_NOOP("Caps Lock (while pressed), Alt+Caps Lock for the original Caps Lock action") }, + { "grp:caps_toggle", I18N_NOOP("Caps Lock") }, + { "grp:ctrl_alt_toggle", I18N_NOOP("Alt+Ctrl") }, + { "grp:ctrl_shift_toggle", I18N_NOOP("Ctrl+Shift") }, + { "grp:ctrls_toggle", I18N_NOOP("Both Ctrl together") }, + { "grp:lalt_lshift_toggle", I18N_NOOP("Left Alt+Left Shift") }, + { "grp:lalt_toggle", I18N_NOOP("Left Alt") }, + { "grp:lctrl_lshift_toggle", I18N_NOOP("Left Ctrl+Left Shift") }, + { "grp:lctrl_lwin_rctrl_menu", I18N_NOOP("Left Ctrl+Left Win to first layout; Right Ctrl+Menu to second layout") }, + { "grp:lctrl_lwin_toggle", I18N_NOOP("Left Ctrl+Left Win") }, + { "grp:lctrl_rctrl_switch", I18N_NOOP("Left Ctrl to first layout; Right Ctrl to last layout") }, + { "grp:lctrl_toggle", I18N_NOOP("Left Ctrl") }, + { "grp:lshift_toggle", I18N_NOOP("Left Shift") }, + { "grp:lswitch", I18N_NOOP("Left Alt (while pressed)") }, + { "grp:lwin_switch", I18N_NOOP("Left Win (while pressed)") }, + { "grp:lwin_toggle", I18N_NOOP("Left Win") }, + { "grp:menu_switch", I18N_NOOP("Menu (while pressed), Shift+Menu for Menu") }, + { "grp:menu_toggle", I18N_NOOP("Menu") }, + { "grp:rctrl_rshift_toggle", I18N_NOOP("Right Ctrl+Right Shift") }, + { "grp:rctrl_switch", I18N_NOOP("Right Ctrl (while pressed)") }, + { "grp:rctrl_toggle", I18N_NOOP("Right Ctrl") }, + { "grp:rshift_toggle", I18N_NOOP("Right Shift") }, + { "grp:rwin_switch", I18N_NOOP("Right Win (while pressed)") }, + { "grp:rwin_toggle", I18N_NOOP("Right Win") }, + { "grp:sclk_toggle", I18N_NOOP("Scroll Lock") }, + { "grp:shift_caps_switch", I18N_NOOP("Caps Lock to first layout; Shift+Caps Lock to last layout") }, + { "grp:shift_caps_toggle", I18N_NOOP("Shift+Caps Lock") }, + { "grp:shifts_toggle", I18N_NOOP("Both Shift together") }, + { "grp:switch", I18N_NOOP("Right Alt (while pressed)") }, + { "grp:toggle", I18N_NOOP("Right Alt") }, + { "grp:win_menu_switch", I18N_NOOP("Left Win to first layout; Right Win/Menu to last layout") }, + { "grp:win_space_toggle", I18N_NOOP("Win+Space") }, + { "grp:win_switch", I18N_NOOP("Any Win (while pressed)") }, + { "grp_led", I18N_NOOP("Use keyboard LED to show alternative layout") }, + { "grp_led:caps", I18N_NOOP("Caps Lock") }, + { "grp_led:num", I18N_NOOP("Num Lock") }, + { "grp_led:scroll", I18N_NOOP("Scroll Lock") }, + { "japan", I18N_NOOP("Japanese keyboard options") }, + { "japan:hztg_escape", I18N_NOOP("Make Zenkaku Hankaku an additional Esc") }, + { "japan:kana_lock", I18N_NOOP("Kana Lock key is locking") }, + { "japan:nicola_f_bs", I18N_NOOP("NICOLA-F style Backspace") }, + { "keypad", I18N_NOOP("Layout of numeric keypad") }, + { "keypad:atm", I18N_NOOP("Phone and ATM style") }, + { "keypad:future", I18N_NOOP("Unicode arrows and math operators on default level") }, + { "keypad:future_wang", I18N_NOOP("Wang 724 keypad with Unicode arrows and math operators on default level") }, + { "keypad:hex", I18N_NOOP("Hexadecimal") }, + { "keypad:legacy", I18N_NOOP("Legacy") }, + { "keypad:legacy_wang", I18N_NOOP("Legacy Wang 724") }, + { "keypad:oss", I18N_NOOP("Unicode arrows and math operators") }, + { "keypad:oss_wang", I18N_NOOP("Wang 724 keypad with Unicode arrows and math operators") }, + { "keypad:pointerkeys", I18N_NOOP("Shift + Num Lock enables PointerKeys") }, + { "korean", I18N_NOOP("Korean Hangul/Hanja keys") }, + { "korean:ralt_hangul", I18N_NOOP("Make right Alt a Hangul key") }, + { "korean:ralt_hanja", I18N_NOOP("Make right Alt a Hanja key") }, + { "korean:rctrl_hangul", I18N_NOOP("Make right Ctrl a Hangul key") }, + { "korean:rctrl_hanja", I18N_NOOP("Make right Ctrl a Hanja key") }, + { "kpdl", I18N_NOOP("Numeric keypad Delete behavior") }, + { "kpdl:comma", I18N_NOOP("Legacy key with comma") }, + { "kpdl:commaoss", I18N_NOOP("Four-level key with comma") }, + { "kpdl:dot", I18N_NOOP("Legacy key with dot") }, + { "kpdl:dotoss", I18N_NOOP("Four-level key with dot") }, + { "kpdl:dotoss_latin9", I18N_NOOP("Four-level key with dot, Latin-9 only") }, + { "kpdl:kposs", I18N_NOOP("Four-level key with abstract separators") }, + { "kpdl:momayyezoss", I18N_NOOP("Four-level key with momayyez") }, + { "kpdl:semi", I18N_NOOP("Semicolon on third level") }, + { "lv2", I18N_NOOP("Key to choose the 2nd level") }, + { "lv2:lsgt_switch", I18N_NOOP("The \"< >\" key") }, + { "lv3", I18N_NOOP("Key to choose the 3rd level") }, + { "lv3:alt_switch", I18N_NOOP("Any Alt") }, + { "lv3:bksl_switch", I18N_NOOP("Backslash") }, + { "lv3:bksl_switch_latch", I18N_NOOP("Backslash; acts as onetime lock when pressed together with another 3rd level chooser") }, + { "lv3:caps_switch", I18N_NOOP("Caps Lock") }, + { "lv3:caps_switch_latch", I18N_NOOP("Caps Lock; acts as onetime lock when pressed together with another 3rd-level chooser") }, + { "lv3:enter_switch", I18N_NOOP("Enter on keypad") }, + { "lv3:lalt_switch", I18N_NOOP("Left Alt") }, + { "lv3:lsgt_switch", I18N_NOOP("The \"< >\" key") }, + { "lv3:lsgt_switch_latch", I18N_NOOP("The \"< >\" key; acts as onetime lock when pressed together with another 3rd level chooser") }, + { "lv3:lwin_switch", I18N_NOOP("Left Win") }, + { "lv3:menu_switch", I18N_NOOP("Menu") }, + { "lv3:ralt_alt", I18N_NOOP("Right Alt never chooses 3rd level") }, + { "lv3:ralt_switch", I18N_NOOP("Right Alt") }, + { "lv3:ralt_switch_multikey", I18N_NOOP("Right Alt; Shift+Right Alt as Compose") }, + { "lv3:rwin_switch", I18N_NOOP("Right Win") }, + { "lv3:switch", I18N_NOOP("Right Ctrl") }, + { "lv3:win_switch", I18N_NOOP("Any Win") }, + { "lv5", I18N_NOOP("Key to choose 5th level") }, + { "lv5:lsgt_switch", I18N_NOOP("The \"< >\" key chooses 5th level") }, + { "lv5:lsgt_switch_lock", I18N_NOOP("The \"< >\" key chooses 5th level and acts as a one-time lock if pressed with another 5th level chooser") }, + { "lv5:lsgt_switch_lock_cancel", I18N_NOOP("The \"< >\" key chooses 5th level and acts as a one-time lock if pressed with another 5th level chooser") }, + { "lv5:lwin_switch_lock", I18N_NOOP("Left Win chooses 5th level and acts as a one-time lock if pressed with another 5th level chooser") }, + { "lv5:menu_switch", I18N_NOOP("Menu chooses 5th level") }, + { "lv5:ralt_switch", I18N_NOOP("Right Alt chooses 5th level") }, + { "lv5:ralt_switch_lock", I18N_NOOP("Right Alt chooses 5th level and acts as a one-time lock if pressed with another 5th level chooser") }, + { "lv5:rwin_switch_lock", I18N_NOOP("Right Win chooses 5th level and acts as a one-time lock if pressed with another 5th level chooser") }, + { "misc:apl", I18N_NOOP("Enable APL overlay characters") }, + { "misc:typo", I18N_NOOP("Enable extra typographic characters") }, + { "mod_led", I18N_NOOP("Use keyboard LED to indicate modifiers") }, + { "mod_led:compose", I18N_NOOP("Compose") }, + { "nbsp", I18N_NOOP("Non-breaking space input") }, + { "nbsp:level2", I18N_NOOP("Non-breaking space at the 2nd level") }, + { "nbsp:level3", I18N_NOOP("Non-breaking space at the 3rd level") }, + { "nbsp:level3n", I18N_NOOP("Non-breaking space at the 3rd level, thin non-breaking space at the 4th level") }, + { "nbsp:level3s", I18N_NOOP("Non-breaking space at the 3rd level, nothing at the 4th level") }, + { "nbsp:level4", I18N_NOOP("Non-breaking space at the 4th level") }, + { "nbsp:level4n", I18N_NOOP("Non-breaking space at the 4th level, thin non-breaking space at the 6th level") }, + { "nbsp:level4nl", I18N_NOOP("Non-breaking space at the 4th level, thin non-breaking space at the 6th level (via Ctrl+Shift)") }, + { "nbsp:none", I18N_NOOP("Usual space at any level") }, + { "nbsp:zwnj2", I18N_NOOP("Zero-width non-joiner at the 2nd level") }, + { "nbsp:zwnj2nb3", I18N_NOOP("Zero-width non-joiner at the 2nd level, non-breaking space at the 3rd level") }, + { "nbsp:zwnj2nb3nnb4", I18N_NOOP("Zero-width non-joiner at the 2nd level, non-breaking space at the 3rd level, thin non-breaking space at the 4th level") }, + { "nbsp:zwnj2nb3s", I18N_NOOP("Zero-width non-joiner at the 2nd level, non-breaking space at the 3rd level, nothing at the 4th level") }, + { "nbsp:zwnj2nb3zwj4", I18N_NOOP("Zero-width non-joiner at the 2nd level, non-breaking space at the 3rd level, zero-width joiner at the 4th level") }, + { "nbsp:zwnj2zwj3", I18N_NOOP("Zero-width non-joiner at the 2nd level, zero-width joiner at the 3rd level") }, + { "nbsp:zwnj2zwj3nb4", I18N_NOOP("Zero-width non-joiner at the 2nd level, zero-width joiner at the 3rd level, non-breaking space at the 4th level") }, + { "nbsp:zwnj3zwj4", I18N_NOOP("Zero-width non-joiner at the 3rd level, zero-width joiner at the 4th level") }, + { "numpad:mac", I18N_NOOP("Numeric keypad always enters digits (as in macOS)") }, + { "numpad:microsoft", I18N_NOOP("Num Lock on: digits; Shift for arrows. Num Lock off: arrows (as in Windows)") }, + { "numpad:pc", I18N_NOOP("Default numeric keypad keys") }, + { "numpad:shift3", I18N_NOOP("Shift does not cancel Num Lock, chooses 3rd level instead") }, + { "rupeesign:4", I18N_NOOP("Rupee on 4") }, + { "shift:both_capslock", I18N_NOOP("Both Shift together enable Caps Lock") }, + { "shift:both_capslock_cancel", I18N_NOOP("Both Shift together enable Caps Lock; one Shift key disables it") }, + { "shift:both_shiftlock", I18N_NOOP("Both Shift together enable Shift Lock") }, + { "shift:breaks_caps", I18N_NOOP("Shift cancels Caps Lock") }, + { "solaris", I18N_NOOP("Old Solaris keycodes compatibility") }, + { "solaris:sun_compat", I18N_NOOP("Sun key compatibility") }, + { "srvrkeys:none", I18N_NOOP("Special keys (Ctrl+Alt+<key>) handled in a server") }, + { "terminate", I18N_NOOP("Key sequence to kill the X server") }, + { "terminate:ctrl_alt_bksp", I18N_NOOP("Ctrl+Alt+Backspace") } +}; +static const qint16 optionDescriptionTblSize = sizeof(optionDescriptionTbl) / sizeof(optionDescriptionData); + + +bool KKeyboardType::operator==(const KKeyboardType &other) const +{ + return (rule == other.rule + && model == other.model + && layout == other.layout + && variant == other.variant + && option == other.option + ); +} + +class KKeyboardLayoutPrivate +{ +public: + KKeyboardLayoutPrivate(KKeyboardLayout *parent); + ~KKeyboardLayoutPrivate(); + + void _k_checkLayouts(); + + QList currentlayouts; + QString setxkbmapexe; + +private: + KKeyboardLayout* m_parent; + QTimer* m_timer; +}; + +KKeyboardLayoutPrivate::KKeyboardLayoutPrivate(KKeyboardLayout *parent) + : m_parent(parent), + m_timer(new QTimer(parent)) +{ + m_timer->setInterval(s_layouttimeout); + QObject::connect( + m_timer, SIGNAL(timeout()), + m_parent, SLOT(_k_checkLayouts()) + ); + m_timer->start(); +} + +KKeyboardLayoutPrivate::~KKeyboardLayoutPrivate() +{ + m_timer->stop(); +} + +void KKeyboardLayoutPrivate::_k_checkLayouts() +{ + const QList layouts = m_parent->layouts(); + if (layouts != currentlayouts) { + currentlayouts = layouts; + kDebug() << "XKB layouts changed"; + emit m_parent->layoutChanged(); + } +} + +KKeyboardLayout::KKeyboardLayout(QObject *parent) + : QObject(parent), + d(new KKeyboardLayoutPrivate(this)) +{ +} + +KKeyboardLayout::~KKeyboardLayout() +{ + delete d; +} + +QList KKeyboardLayout::layouts() const +{ + QList result; +#if defined(HAVE_XKB) + XkbRF_VarDefsRec xkbvardefs; + const Bool xkbresult = XkbRF_GetNamesProp(QX11Info::display(), NULL, &xkbvardefs); + if (xkbresult != True) { + kWarning() << "Could not get XKB layouts"; + } else { + const QByteArray xkbmodel = QByteArray::fromRawData(xkbvardefs.model, qstrlen(xkbvardefs.model)); + const QByteArray xkblayout = QByteArray::fromRawData(xkbvardefs.layout, qstrlen(xkbvardefs.layout)); + const QByteArray xkbvariants = QByteArray::fromRawData(xkbvardefs.variant, qstrlen(xkbvardefs.variant)); + const QByteArray xkboptions = QByteArray::fromRawData(xkbvardefs.options, qstrlen(xkbvardefs.options)); + const QList splitlayouts = xkblayout.split(s_xkbseparator); + const QList splitvariants = xkbvariants.split(s_xkbseparator); + for (int i = 0; i < splitlayouts.size(); i++) { + KKeyboardType kkeyboardtype; + kkeyboardtype.model = xkbmodel; + kkeyboardtype.layout = splitlayouts.at(i); + if (i < splitvariants.size()) { + kkeyboardtype.variant = splitvariants.at(i); + } + kkeyboardtype.option = xkboptions; + result.append(kkeyboardtype); + } + } +#endif + if (result.size() == 0) { + result.append(KKeyboardLayout::defaultLayout()); + } + return result; +} + +bool KKeyboardLayout::setLayouts(const QList &layouts) +{ + if (layouts.size() == 0) { + kWarning() << "Empty keyboard layouts"; + return false; + } + + QByteArray xkbrule; + QByteArray xkbmodel; + QByteArray xkblayouts; + QList xkbvariants; + QList xkboptions; + foreach (const KKeyboardType &layout, layouts) { + if (layout.layout.isEmpty()) { + kWarning() << "Invalid keyboard layout"; + return false; + } + + // NOTE: -rules and -model can be speicifed only once + if (!xkbrule.isEmpty() && xkbrule != layout.rule) { + kWarning() << "Conflicting keyboard layout rules"; + return false; + } + xkbrule = layout.rule; + if (!xkbmodel.isEmpty() && xkbmodel != layout.model) { + kWarning() << "Conflicting keyboard layout models"; + return false; + } + xkbmodel = layout.model; + + // NOTE: layouts and variants have to be joined, variant can be empty + if (!xkblayouts.isEmpty()) { + xkblayouts.append(s_xkbseparator); + } + xkblayouts.append(layout.layout); + xkbvariants.append(layout.variant); + // NOTE: options can be empty, also -option argument must be used per-option + if (!layout.option.isEmpty()) { + xkboptions.append(layout.option); + } + } + + kDebug() << "Changing XKB layouts to" << xkbrule << xkbmodel << xkblayouts << xkbvariants << xkboptions; + // setting the properly is simply not enough, X11 server has to load rules and whatnot + if (d->setxkbmapexe.isEmpty()) { + d->setxkbmapexe = KStandardDirs::findExe("setxkbmap"); + } + if (d->setxkbmapexe.isEmpty()) { + kWarning() << "Could not find setxkbmap"; + return false; + } + + // NOTE: options have to be reset first + static const QStringList setxkbmapresetargs = QStringList() + << QString::fromLatin1("-option"); + int setxkbmapstatus = QProcess::execute(d->setxkbmapexe, setxkbmapresetargs); + if (setxkbmapstatus != 0) { + kWarning() << "Could not reset XKB map" << setxkbmapstatus; + return false; + } + + QStringList setxkbmapargs = QStringList() + << QString::fromLatin1("-layout") + << QString::fromLatin1(xkblayouts.constData(), xkblayouts.size()); + if (!xkbrule.isEmpty()) { + setxkbmapargs << QString::fromLatin1("-rules"); + setxkbmapargs << QString::fromLatin1(xkbrule.constData(), xkbrule.size()); + } + if (!xkbmodel.isEmpty()) { + setxkbmapargs << QString::fromLatin1("-model"); + setxkbmapargs << QString::fromLatin1(xkbmodel.constData(), xkbmodel.size()); + } + if (!xkbvariants.isEmpty()) { + QByteArray xkbvariantsdata; + foreach (const QByteArray &xkbvariant, xkbvariants) { + xkbvariantsdata.append(xkbvariant); + xkbvariantsdata.append(s_xkbseparator); + } + xkbvariantsdata.chop(1); + setxkbmapargs << QString::fromLatin1("-variant"); + setxkbmapargs << QString::fromLatin1(xkbvariantsdata.constData(), xkbvariantsdata.size()); + } + foreach (const QByteArray &option, xkboptions) { + setxkbmapargs << QString::fromLatin1("-option"); + setxkbmapargs << QString::fromLatin1(option.constData(), option.size()); + } + setxkbmapstatus = QProcess::execute(d->setxkbmapexe, setxkbmapargs); + if (setxkbmapstatus != 0) { + kWarning() << "Could not set XKB map" << setxkbmapstatus << setxkbmapargs; + return false; + } + return true; +} + +KKeyboardType KKeyboardLayout::defaultLayout() +{ + // should all else fail this is a default that will work for most cases (assuming the XKB data + // is installed that is) + KKeyboardType defaultlayout; + defaultlayout.rule = "base"; + defaultlayout.model = "pc105"; + defaultlayout.layout = "us"; + return defaultlayout; +} + +QList KKeyboardLayout::modelNames() +{ + QList result; + result.reserve(modelDescriptionTblSize); + for (int i = 0; i < modelDescriptionTblSize; i++) { + result.append(modelDescriptionTbl[i].name); + } + return result; +} + +QList KKeyboardLayout::layoutNames() +{ + QList result; + result.reserve(layoutDescriptionTblSize); + for (int i = 0; i < layoutDescriptionTblSize; i++) { + result.append(layoutDescriptionTbl[i].name); + } + return result; +} + +QList KKeyboardLayout::variantNames(const QByteArray &layout) +{ + QList result; + for (int i = 0; i < variantDescriptionTblSize; i++) { + if (qstrcmp(layout.constData(), variantDescriptionTbl[i].name) == 0) { + result.append(variantDescriptionTbl[i].name2); + } + } + return result; +} + +QList KKeyboardLayout::optionNames() +{ + QList result; + result.reserve(optionDescriptionTblSize); + for (int i = 0; i < optionDescriptionTblSize; i++) { + result.append(optionDescriptionTbl[i].name); + } + return result; +} + +QString KKeyboardLayout::modelDescription(const QByteArray &model) +{ + for (int i = 0; i < modelDescriptionTblSize; i++) { + if (qstrcmp(model.constData(), modelDescriptionTbl[i].name) == 0) { + return ki18nc("Keyboard model description", modelDescriptionTbl[i].description).toString(); + } + } + return QString::fromLatin1(model.constData(), model.size()); +} + +QString KKeyboardLayout::layoutDescription(const QByteArray &layout) +{ + for (int i = 0; i < layoutDescriptionTblSize; i++) { + if (qstrcmp(layout.constData(), layoutDescriptionTbl[i].name) == 0) { + return ki18nc("Keyboard layout description", layoutDescriptionTbl[i].description).toString(); + } + } + return QString::fromLatin1(layout.constData(), layout.size()); +} + +QString KKeyboardLayout::variantDescription(const QByteArray &layout, const QByteArray &variant) +{ + if (variant.isEmpty()) { + return i18nc("Keyboard variant description", "None"); + } + for (int i = 0; i < variantDescriptionTblSize; i++) { + if (qstrcmp(layout.constData(), variantDescriptionTbl[i].name) == 0 + && qstrcmp(variant.constData(), variantDescriptionTbl[i].name2) == 0) { + return ki18nc("Keyboard variant description", variantDescriptionTbl[i].description).toString(); + } + } + return QString::fromLatin1(variant.constData(), variant.size()); +} + +QString KKeyboardLayout::optionDescription(const QByteArray &option) +{ + if (option.isEmpty()) { + return i18nc("Keyboard option description", "None"); + } + for (int i = 0; i < optionDescriptionTblSize; i++) { + if (qstrcmp(option.constData(), optionDescriptionTbl[i].name) == 0) { + return ki18nc("Keyboard option description", optionDescriptionTbl[i].description).toString(); + } + } + return QString::fromLatin1(option.constData(), option.size()); +} + +#include "moc_kkeyboardlayout.cpp" diff --git a/kdeui/util/kkeyboardlayout.h b/kdeui/util/kkeyboardlayout.h new file mode 100644 index 00000000..69fbbc69 --- /dev/null +++ b/kdeui/util/kkeyboardlayout.h @@ -0,0 +1,79 @@ +/* This file is part of the KDE libraries + Copyright (C) 2023 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KKEYBOARDLAYOUT_H +#define KKEYBOARDLAYOUT_H + +#include + +#include +#include +#include + +class KKeyboardLayoutPrivate; + +struct KKeyboardType +{ + QByteArray rule; + QByteArray model; + QByteArray layout; + QByteArray variant; + QByteArray option; + + bool operator==(const KKeyboardType &other) const; +}; + +/*! + Class to query and change the keyboard layout. + + @since 4.24 + @warning the API is subject to change +*/ +class KDEUI_EXPORT KKeyboardLayout : public QObject +{ + Q_OBJECT +public: + KKeyboardLayout(QObject *parent = nullptr); + ~KKeyboardLayout(); + + QList layouts() const; + bool setLayouts(const QList &layouts); + + static KKeyboardType defaultLayout(); + + static QList modelNames(); + static QList layoutNames(); + static QList variantNames(const QByteArray &layout); + static QList optionNames(); + static QString modelDescription(const QByteArray &model); + static QString layoutDescription(const QByteArray &layout); + static QString variantDescription(const QByteArray &layout, const QByteArray &variant); + static QString optionDescription(const QByteArray &option); + +Q_SIGNALS: + void layoutChanged(); + +private: + friend KKeyboardLayoutPrivate; + Q_DISABLE_COPY(KKeyboardLayout); + KKeyboardLayoutPrivate * const d; + + Q_PRIVATE_SLOT(d, void _k_checkLayouts()) +}; + +#endif // KKEYBOARDLAYOUT_H diff --git a/kdeui/util/scoop-rules.py b/kdeui/util/scoop-rules.py new file mode 100755 index 00000000..07205d65 --- /dev/null +++ b/kdeui/util/scoop-rules.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +import os, sys, glob + +def cstringify(s): + r = s.replace('"', '\\"') + r = r.replace('\\', '\\\\') + return r + +if len(sys.argv) < 2: + print('usage: scoop-rules ') + exit(1) + +printmodel = False +printlayout = False +printvariant = False +printoption = False +if sys.argv[1] == 'model': + printmodel = True +elif sys.argv[1] == 'layout': + printlayout = True +elif sys.argv[1] == 'variant': + printvariant = True +elif sys.argv[1] == 'option': + printoption = True +else: + print('usage: scoop-rules ') + exit(1) + +lstfiles = glob.glob('/usr/share/X11/xkb/rules/*.lst') +if len(lstfiles) < 1: + print('Could not find lst files') + exit(2) + +for lstfile in lstfiles: + with open(lstfile, 'r') as lsthandle: + printline = False + for lstline in lsthandle.readlines(): + if printmodel: + strippedline = lstline.strip() + if strippedline.startswith('! model'): + printline = True + continue + elif len(strippedline) == 0: + printline = False + if not printline: + continue + splitline = strippedline.split(' ') + splitpart0 = splitline[0].strip() + splitpart1 = ' '.join(splitline[1:]).strip() + print(' { "%s", I18N_NOOP("%s") },' % (splitpart0, cstringify(splitpart1))) + elif printlayout: + strippedline = lstline.strip() + if strippedline.startswith('! layout'): + printline = True + continue + elif len(strippedline) == 0: + printline = False + if not printline: + continue + splitline = strippedline.split(' ') + splitpart0 = splitline[0].strip() + splitpart1 = ' '.join(splitline[1:]).strip() + print(' { "%s", I18N_NOOP("%s") },' % (splitpart0, cstringify(splitpart1))) + elif printvariant: + strippedline = lstline.strip() + if strippedline.startswith('! variant'): + printline = True + continue + elif len(strippedline) == 0: + printline = False + if not printline: + continue + splitline = strippedline.split(' ') + splitpart0 = splitline[0].strip() + splitpart1 = ' '.join(splitline[1:]).strip() + splitlayout = splitpart1.split(':')[0].strip() + splitdescription = ' '.join(splitpart1.split(':')[1:]).strip() + print(' { "%s", "%s", I18N_NOOP("%s") },' % (splitlayout, cstringify(splitpart0), cstringify(splitdescription))) + elif printoption: + strippedline = lstline.strip() + if strippedline.startswith('! option'): + printline = True + continue + elif len(strippedline) == 0: + printline = False + if not printline: + continue + splitline = strippedline.split(' ') + splitpart0 = splitline[0].strip() + splitpart1 = ' '.join(splitline[1:]).strip() + print(' { "%s", I18N_NOOP("%s") },' % (splitpart0, cstringify(splitpart1))) + \ No newline at end of file diff --git a/solid/solid/ifaces/input.cpp b/solid/solid/ifaces/input.cpp index 851429ad..75996e10 100644 --- a/solid/solid/ifaces/input.cpp +++ b/solid/solid/ifaces/input.cpp @@ -1,5 +1,5 @@ /* - Copyright 2021 Ivailo Monev + Copyright 2023 Ivailo Monev This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public